Bug Summary

File:root/firefox-clang/obj-x86_64-pc-linux-gnu/netwerk/protocol/websocket/./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp
Warning:line 2720, column 3
Value stored to 'rv' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -O2 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name Unified_cpp_protocol_websocket0.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -ffp-contract=off -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/netwerk/protocol/websocket -fcoverage-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/netwerk/protocol/websocket -resource-dir /usr/lib/llvm-23/lib/clang/23 -include /root/firefox-clang/config/gcc_hidden.h -include /root/firefox-clang/obj-x86_64-pc-linux-gnu/mozilla-config.h -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/stl_wrappers -D _GLIBCXX_ASSERTIONS=1 -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/system_wrappers -U _FORTIFY_SOURCE -D _FORTIFY_SOURCE=2 -D DEBUG=1 -D MOZ_HAS_MOZGLUE -D MOZILLA_INTERNAL_API -D IMPL_LIBXUL -D MOZ_SUPPORT_LEAKCHECKING -D STATIC_EXPORTABLE_JS_API -I /root/firefox-clang/netwerk/protocol/websocket -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/netwerk/protocol/websocket -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/ipc/ipdl/_ipdlheaders -I /root/firefox-clang/ipc/chromium/src -I /root/firefox-clang/third_party/abseil-cpp -I /root/firefox-clang/toolkit/components/telemetry -I /root/firefox-clang/xpcom/base -I /root/firefox-clang/dom/base -I /root/firefox-clang/netwerk/base -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nspr -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nss -D MOZILLA_CLIENT -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/c++/16 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/x86_64-linux-gnu/c++/16 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/c++/16/backward -internal-isystem /usr/lib/llvm-23/lib/clang/23/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-error=pessimizing-move -Wno-error=large-by-value-copy=128 -Wno-error=implicit-int-float-conversion -Wno-error=thread-safety-analysis -Wno-error=tautological-type-limit-compare -Wno-invalid-offsetof -Wno-range-loop-analysis -Wno-deprecated-anon-enum-enum-conversion -Wno-deprecated-enum-enum-conversion -Wno-inline-new-delete -Wno-error=deprecated-declarations -Wno-error=array-bounds -Wno-error=free-nonheap-object -Wno-error=atomic-alignment -Wno-error=deprecated-builtins -Wno-psabi -Wno-error=builtin-macro-redefined -Wno-vla-cxx-extension -Wno-unknown-warning-option -Wno-character-conversion -std=gnu++20 -fdeprecated-macro -ferror-limit 19 -fstrict-flex-arrays=1 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fno-rtti -fgnuc-version=4.2.1 -fno-implicit-modules -fskip-odr-check-in-gmf -fno-sized-deallocation -fno-aligned-allocation -fdiagnostics-absolute-paths -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -mllvm -dwarf-linkage-names=Abstract -faddrsig -fdwarf2-cfi-asm -o /tmp/scan-build-2026-09-01-224014-2642839-1 -x c++ Unified_cpp_protocol_websocket0.cpp
1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5#include "WebSocketChannel.h"
6
7#include <algorithm>
8
9#include "WebSocketConnectionBase.h"
10#include "WebSocketFrame.h"
11#include "WebSocketLog.h"
12#include "mozilla/Atomics.h"
13#include "mozilla/Attributes.h"
14#include "mozilla/Base64.h"
15#include "mozilla/Components.h"
16#include "mozilla/EndianUtils.h"
17#include "mozilla/MathAlgorithms.h"
18#include "mozilla/ScopeExit.h"
19#include "mozilla/StaticMutex.h"
20#include "mozilla/StaticPrefs_privacy.h"
21#include "mozilla/TimeStamp.h"
22#include "mozilla/Utf8.h"
23#include "mozilla/glean/NetwerkProtocolWebsocketMetrics.h"
24#include "mozilla/net/WebSocketEventService.h"
25#include "nsCRT.h"
26#include "nsCharSeparatedTokenizer.h"
27#include "nsComponentManagerUtils.h"
28#include "nsError.h"
29#include "nsIAsyncVerifyRedirectCallback.h"
30#include "nsICancelable.h"
31#include "nsIChannel.h"
32#include "nsIClassOfService.h"
33#include "nsICryptoHash.h"
34#include "nsIDNSRecord.h"
35#include "nsIDNSService.h"
36#include "nsIDashboardEventNotifier.h"
37#include "nsIEventTarget.h"
38#include "nsIHttpChannel.h"
39#include "nsIIOService.h"
40#include "nsINSSErrorsService.h"
41#include "nsINetworkLinkService.h"
42#include "nsINode.h"
43#include "nsIObserverService.h"
44#include "nsIPrefBranch.h"
45#include "nsIProtocolProxyService.h"
46#include "nsIProxiedChannel.h"
47#include "nsIProxyInfo.h"
48#include "nsIRandomGenerator.h"
49#include "nsIRunnable.h"
50#include "nsISocketTransport.h"
51#include "nsITLSSocketControl.h"
52#include "nsITransportProvider.h"
53#include "nsITransportSecurityInfo.h"
54#include "nsIURI.h"
55#include "nsIURIMutator.h"
56#include "nsNetCID.h"
57#include "nsNetUtil.h"
58#include "nsProxyRelease.h"
59#include "nsServiceManagerUtils.h"
60#include "nsSocketTransportService2.h"
61#include "nsStringStream.h"
62#include "nsThreadUtils.h"
63#include "plbase64.h"
64#include "prmem.h"
65#include "prnetdb.h"
66#include "zlib.h"
67
68// rather than slurp up all of nsIWebSocket.idl, which lives outside necko, just
69// dupe one constant we need from it
70#define CLOSE_GOING_AWAY 1001
71
72using namespace mozilla;
73using namespace mozilla::net;
74
75namespace mozilla::net {
76
77NS_IMPL_ISUPPORTS(WebSocketChannel, nsIWebSocketChannel, nsIHttpUpgradeListener,MozExternalRefCountType WebSocketChannel::AddRef(void) { static_assert
(!std::is_destructible_v<WebSocketChannel>, "Reference-counted class "
"WebSocketChannel" " should not have a public destructor. " "Make this class's destructor non-public"
); do { static_assert( mozilla::detail::AssertionConditionType
<decltype(int32_t(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 82); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { MOZ_CrashSequence(__null, 82
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("WebSocketChannel" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("WebSocketChannel" != nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"\"WebSocketChannel\" != nullptr" " (" "Must specify a name" ")"
, "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 82); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"WebSocketChannel\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 82); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); if (!mRefCnt.isThreadSafe) _mOwningThread.AssertOwnership
("WebSocketChannel" " not thread-safe"); nsrefcnt count = ++mRefCnt
; NS_LogAddRef((this), (count), ("WebSocketChannel"), (uint32_t
)(sizeof(*this))); return count; } MozExternalRefCountType WebSocketChannel
::Release(void) { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(int32_t(mRefCnt) > 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) > 0))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0"
" (" "dup release" ")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 82); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { MOZ_CrashSequence(__null, 82)
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("WebSocketChannel" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("WebSocketChannel" != nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"\"WebSocketChannel\" != nullptr" " (" "Must specify a name" ")"
, "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 82); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"WebSocketChannel\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 82); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); if (!mRefCnt.isThreadSafe) _mOwningThread.AssertOwnership
("WebSocketChannel" " not thread-safe"); const char* const nametmp
= "WebSocketChannel"; nsrefcnt count = --mRefCnt; NS_LogRelease
((this), (count), (nametmp)); if (count == 0) { mRefCnt = 1; delete
(this); return 0; } return count; } nsresult WebSocketChannel
::QueryInterface(const nsIID& aIID, void** aInstancePtr) {
do { if (!(aInstancePtr)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "QueryInterface requires a non-NULL destination!", "aInstancePtr"
, "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 82); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE
; static_assert(14 > 0, "Need more arguments to NS_INTERFACE_TABLE"
); static const QITableEntry table[] = { {&mozilla::detail
::kImplementedIID<WebSocketChannel, nsIWebSocketChannel>
, int32_t( reinterpret_cast<char*>(static_cast<nsIWebSocketChannel
*>((WebSocketChannel*)0x1000)) - reinterpret_cast<char*
>((WebSocketChannel*)0x1000))}, {&mozilla::detail::kImplementedIID
<WebSocketChannel, nsIHttpUpgradeListener>, int32_t( reinterpret_cast
<char*>(static_cast<nsIHttpUpgradeListener*>((WebSocketChannel
*)0x1000)) - reinterpret_cast<char*>((WebSocketChannel*
)0x1000))}, {&mozilla::detail::kImplementedIID<WebSocketChannel
, nsIRequestObserver>, int32_t( reinterpret_cast<char*>
(static_cast<nsIRequestObserver*>((WebSocketChannel*)0x1000
)) - reinterpret_cast<char*>((WebSocketChannel*)0x1000)
)}, {&mozilla::detail::kImplementedIID<WebSocketChannel
, nsIStreamListener>, int32_t( reinterpret_cast<char*>
(static_cast<nsIStreamListener*>((WebSocketChannel*)0x1000
)) - reinterpret_cast<char*>((WebSocketChannel*)0x1000)
)}, {&mozilla::detail::kImplementedIID<WebSocketChannel
, nsIInputStreamCallback>, int32_t( reinterpret_cast<char
*>(static_cast<nsIInputStreamCallback*>((WebSocketChannel
*)0x1000)) - reinterpret_cast<char*>((WebSocketChannel*
)0x1000))}, {&mozilla::detail::kImplementedIID<WebSocketChannel
, nsIOutputStreamCallback>, int32_t( reinterpret_cast<char
*>(static_cast<nsIOutputStreamCallback*>((WebSocketChannel
*)0x1000)) - reinterpret_cast<char*>((WebSocketChannel*
)0x1000))}, {&mozilla::detail::kImplementedIID<WebSocketChannel
, nsITimerCallback>, int32_t( reinterpret_cast<char*>
(static_cast<nsITimerCallback*>((WebSocketChannel*)0x1000
)) - reinterpret_cast<char*>((WebSocketChannel*)0x1000)
)}, {&mozilla::detail::kImplementedIID<WebSocketChannel
, nsIDNSListener>, int32_t( reinterpret_cast<char*>(
static_cast<nsIDNSListener*>((WebSocketChannel*)0x1000)
) - reinterpret_cast<char*>((WebSocketChannel*)0x1000))
}, {&mozilla::detail::kImplementedIID<WebSocketChannel
, nsIProtocolProxyCallback>, int32_t( reinterpret_cast<
char*>(static_cast<nsIProtocolProxyCallback*>((WebSocketChannel
*)0x1000)) - reinterpret_cast<char*>((WebSocketChannel*
)0x1000))}, {&mozilla::detail::kImplementedIID<WebSocketChannel
, nsIInterfaceRequestor>, int32_t( reinterpret_cast<char
*>(static_cast<nsIInterfaceRequestor*>((WebSocketChannel
*)0x1000)) - reinterpret_cast<char*>((WebSocketChannel*
)0x1000))}, {&mozilla::detail::kImplementedIID<WebSocketChannel
, nsIChannelEventSink>, int32_t( reinterpret_cast<char*
>(static_cast<nsIChannelEventSink*>((WebSocketChannel
*)0x1000)) - reinterpret_cast<char*>((WebSocketChannel*
)0x1000))}, {&mozilla::detail::kImplementedIID<WebSocketChannel
, nsIThreadRetargetableRequest>, int32_t( reinterpret_cast
<char*>(static_cast<nsIThreadRetargetableRequest*>
((WebSocketChannel*)0x1000)) - reinterpret_cast<char*>(
(WebSocketChannel*)0x1000))}, {&mozilla::detail::kImplementedIID
<WebSocketChannel, nsIObserver>, int32_t( reinterpret_cast
<char*>(static_cast<nsIObserver*>((WebSocketChannel
*)0x1000)) - reinterpret_cast<char*>((WebSocketChannel*
)0x1000))}, {&mozilla::detail::kImplementedIID<WebSocketChannel
, nsINamed>, int32_t( reinterpret_cast<char*>(static_cast
<nsINamed*>((WebSocketChannel*)0x1000)) - reinterpret_cast
<char*>((WebSocketChannel*)0x1000))}, {&mozilla::detail
::kImplementedIID<WebSocketChannel, nsISupports>, int32_t
(reinterpret_cast<char*>(static_cast<nsISupports*>
( static_cast<nsIWebSocketChannel*>((WebSocketChannel*)
0x1000))) - reinterpret_cast<char*>((WebSocketChannel*)
0x1000))}, { nullptr, 0 } } ; static_assert(std::size(table) >
1, "need at least 1 interface"); rv = NS_TableDrivenQI(static_cast
<void*>(this), aIID, aInstancePtr, table); return rv; }
78 nsIRequestObserver, nsIStreamListener, nsIInputStreamCallback,MozExternalRefCountType WebSocketChannel::AddRef(void) { static_assert
(!std::is_destructible_v<WebSocketChannel>, "Reference-counted class "
"WebSocketChannel" " should not have a public destructor. " "Make this class's destructor non-public"
); do { static_assert( mozilla::detail::AssertionConditionType
<decltype(int32_t(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 82); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { MOZ_CrashSequence(__null, 82
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("WebSocketChannel" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("WebSocketChannel" != nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"\"WebSocketChannel\" != nullptr" " (" "Must specify a name" ")"
, "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 82); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"WebSocketChannel\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 82); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); if (!mRefCnt.isThreadSafe) _mOwningThread.AssertOwnership
("WebSocketChannel" " not thread-safe"); nsrefcnt count = ++mRefCnt
; NS_LogAddRef((this), (count), ("WebSocketChannel"), (uint32_t
)(sizeof(*this))); return count; } MozExternalRefCountType WebSocketChannel
::Release(void) { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(int32_t(mRefCnt) > 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) > 0))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0"
" (" "dup release" ")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 82); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { MOZ_CrashSequence(__null, 82)
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("WebSocketChannel" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("WebSocketChannel" != nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"\"WebSocketChannel\" != nullptr" " (" "Must specify a name" ")"
, "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 82); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"WebSocketChannel\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 82); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); if (!mRefCnt.isThreadSafe) _mOwningThread.AssertOwnership
("WebSocketChannel" " not thread-safe"); const char* const nametmp
= "WebSocketChannel"; nsrefcnt count = --mRefCnt; NS_LogRelease
((this), (count), (nametmp)); if (count == 0) { mRefCnt = 1; delete
(this); return 0; } return count; } nsresult WebSocketChannel
::QueryInterface(const nsIID& aIID, void** aInstancePtr) {
do { if (!(aInstancePtr)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "QueryInterface requires a non-NULL destination!", "aInstancePtr"
, "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 82); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE
; static_assert(14 > 0, "Need more arguments to NS_INTERFACE_TABLE"
); static const QITableEntry table[] = { {&mozilla::detail
::kImplementedIID<WebSocketChannel, nsIWebSocketChannel>
, int32_t( reinterpret_cast<char*>(static_cast<nsIWebSocketChannel
*>((WebSocketChannel*)0x1000)) - reinterpret_cast<char*
>((WebSocketChannel*)0x1000))}, {&mozilla::detail::kImplementedIID
<WebSocketChannel, nsIHttpUpgradeListener>, int32_t( reinterpret_cast
<char*>(static_cast<nsIHttpUpgradeListener*>((WebSocketChannel
*)0x1000)) - reinterpret_cast<char*>((WebSocketChannel*
)0x1000))}, {&mozilla::detail::kImplementedIID<WebSocketChannel
, nsIRequestObserver>, int32_t( reinterpret_cast<char*>
(static_cast<nsIRequestObserver*>((WebSocketChannel*)0x1000
)) - reinterpret_cast<char*>((WebSocketChannel*)0x1000)
)}, {&mozilla::detail::kImplementedIID<WebSocketChannel
, nsIStreamListener>, int32_t( reinterpret_cast<char*>
(static_cast<nsIStreamListener*>((WebSocketChannel*)0x1000
)) - reinterpret_cast<char*>((WebSocketChannel*)0x1000)
)}, {&mozilla::detail::kImplementedIID<WebSocketChannel
, nsIInputStreamCallback>, int32_t( reinterpret_cast<char
*>(static_cast<nsIInputStreamCallback*>((WebSocketChannel
*)0x1000)) - reinterpret_cast<char*>((WebSocketChannel*
)0x1000))}, {&mozilla::detail::kImplementedIID<WebSocketChannel
, nsIOutputStreamCallback>, int32_t( reinterpret_cast<char
*>(static_cast<nsIOutputStreamCallback*>((WebSocketChannel
*)0x1000)) - reinterpret_cast<char*>((WebSocketChannel*
)0x1000))}, {&mozilla::detail::kImplementedIID<WebSocketChannel
, nsITimerCallback>, int32_t( reinterpret_cast<char*>
(static_cast<nsITimerCallback*>((WebSocketChannel*)0x1000
)) - reinterpret_cast<char*>((WebSocketChannel*)0x1000)
)}, {&mozilla::detail::kImplementedIID<WebSocketChannel
, nsIDNSListener>, int32_t( reinterpret_cast<char*>(
static_cast<nsIDNSListener*>((WebSocketChannel*)0x1000)
) - reinterpret_cast<char*>((WebSocketChannel*)0x1000))
}, {&mozilla::detail::kImplementedIID<WebSocketChannel
, nsIProtocolProxyCallback>, int32_t( reinterpret_cast<
char*>(static_cast<nsIProtocolProxyCallback*>((WebSocketChannel
*)0x1000)) - reinterpret_cast<char*>((WebSocketChannel*
)0x1000))}, {&mozilla::detail::kImplementedIID<WebSocketChannel
, nsIInterfaceRequestor>, int32_t( reinterpret_cast<char
*>(static_cast<nsIInterfaceRequestor*>((WebSocketChannel
*)0x1000)) - reinterpret_cast<char*>((WebSocketChannel*
)0x1000))}, {&mozilla::detail::kImplementedIID<WebSocketChannel
, nsIChannelEventSink>, int32_t( reinterpret_cast<char*
>(static_cast<nsIChannelEventSink*>((WebSocketChannel
*)0x1000)) - reinterpret_cast<char*>((WebSocketChannel*
)0x1000))}, {&mozilla::detail::kImplementedIID<WebSocketChannel
, nsIThreadRetargetableRequest>, int32_t( reinterpret_cast
<char*>(static_cast<nsIThreadRetargetableRequest*>
((WebSocketChannel*)0x1000)) - reinterpret_cast<char*>(
(WebSocketChannel*)0x1000))}, {&mozilla::detail::kImplementedIID
<WebSocketChannel, nsIObserver>, int32_t( reinterpret_cast
<char*>(static_cast<nsIObserver*>((WebSocketChannel
*)0x1000)) - reinterpret_cast<char*>((WebSocketChannel*
)0x1000))}, {&mozilla::detail::kImplementedIID<WebSocketChannel
, nsINamed>, int32_t( reinterpret_cast<char*>(static_cast
<nsINamed*>((WebSocketChannel*)0x1000)) - reinterpret_cast
<char*>((WebSocketChannel*)0x1000))}, {&mozilla::detail
::kImplementedIID<WebSocketChannel, nsISupports>, int32_t
(reinterpret_cast<char*>(static_cast<nsISupports*>
( static_cast<nsIWebSocketChannel*>((WebSocketChannel*)
0x1000))) - reinterpret_cast<char*>((WebSocketChannel*)
0x1000))}, { nullptr, 0 } } ; static_assert(std::size(table) >
1, "need at least 1 interface"); rv = NS_TableDrivenQI(static_cast
<void*>(this), aIID, aInstancePtr, table); return rv; }
79 nsIOutputStreamCallback, nsITimerCallback, nsIDNSListener,MozExternalRefCountType WebSocketChannel::AddRef(void) { static_assert
(!std::is_destructible_v<WebSocketChannel>, "Reference-counted class "
"WebSocketChannel" " should not have a public destructor. " "Make this class's destructor non-public"
); do { static_assert( mozilla::detail::AssertionConditionType
<decltype(int32_t(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 82); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { MOZ_CrashSequence(__null, 82
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("WebSocketChannel" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("WebSocketChannel" != nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"\"WebSocketChannel\" != nullptr" " (" "Must specify a name" ")"
, "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 82); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"WebSocketChannel\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 82); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); if (!mRefCnt.isThreadSafe) _mOwningThread.AssertOwnership
("WebSocketChannel" " not thread-safe"); nsrefcnt count = ++mRefCnt
; NS_LogAddRef((this), (count), ("WebSocketChannel"), (uint32_t
)(sizeof(*this))); return count; } MozExternalRefCountType WebSocketChannel
::Release(void) { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(int32_t(mRefCnt) > 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) > 0))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0"
" (" "dup release" ")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 82); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { MOZ_CrashSequence(__null, 82)
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("WebSocketChannel" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("WebSocketChannel" != nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"\"WebSocketChannel\" != nullptr" " (" "Must specify a name" ")"
, "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 82); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"WebSocketChannel\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 82); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); if (!mRefCnt.isThreadSafe) _mOwningThread.AssertOwnership
("WebSocketChannel" " not thread-safe"); const char* const nametmp
= "WebSocketChannel"; nsrefcnt count = --mRefCnt; NS_LogRelease
((this), (count), (nametmp)); if (count == 0) { mRefCnt = 1; delete
(this); return 0; } return count; } nsresult WebSocketChannel
::QueryInterface(const nsIID& aIID, void** aInstancePtr) {
do { if (!(aInstancePtr)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "QueryInterface requires a non-NULL destination!", "aInstancePtr"
, "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 82); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE
; static_assert(14 > 0, "Need more arguments to NS_INTERFACE_TABLE"
); static const QITableEntry table[] = { {&mozilla::detail
::kImplementedIID<WebSocketChannel, nsIWebSocketChannel>
, int32_t( reinterpret_cast<char*>(static_cast<nsIWebSocketChannel
*>((WebSocketChannel*)0x1000)) - reinterpret_cast<char*
>((WebSocketChannel*)0x1000))}, {&mozilla::detail::kImplementedIID
<WebSocketChannel, nsIHttpUpgradeListener>, int32_t( reinterpret_cast
<char*>(static_cast<nsIHttpUpgradeListener*>((WebSocketChannel
*)0x1000)) - reinterpret_cast<char*>((WebSocketChannel*
)0x1000))}, {&mozilla::detail::kImplementedIID<WebSocketChannel
, nsIRequestObserver>, int32_t( reinterpret_cast<char*>
(static_cast<nsIRequestObserver*>((WebSocketChannel*)0x1000
)) - reinterpret_cast<char*>((WebSocketChannel*)0x1000)
)}, {&mozilla::detail::kImplementedIID<WebSocketChannel
, nsIStreamListener>, int32_t( reinterpret_cast<char*>
(static_cast<nsIStreamListener*>((WebSocketChannel*)0x1000
)) - reinterpret_cast<char*>((WebSocketChannel*)0x1000)
)}, {&mozilla::detail::kImplementedIID<WebSocketChannel
, nsIInputStreamCallback>, int32_t( reinterpret_cast<char
*>(static_cast<nsIInputStreamCallback*>((WebSocketChannel
*)0x1000)) - reinterpret_cast<char*>((WebSocketChannel*
)0x1000))}, {&mozilla::detail::kImplementedIID<WebSocketChannel
, nsIOutputStreamCallback>, int32_t( reinterpret_cast<char
*>(static_cast<nsIOutputStreamCallback*>((WebSocketChannel
*)0x1000)) - reinterpret_cast<char*>((WebSocketChannel*
)0x1000))}, {&mozilla::detail::kImplementedIID<WebSocketChannel
, nsITimerCallback>, int32_t( reinterpret_cast<char*>
(static_cast<nsITimerCallback*>((WebSocketChannel*)0x1000
)) - reinterpret_cast<char*>((WebSocketChannel*)0x1000)
)}, {&mozilla::detail::kImplementedIID<WebSocketChannel
, nsIDNSListener>, int32_t( reinterpret_cast<char*>(
static_cast<nsIDNSListener*>((WebSocketChannel*)0x1000)
) - reinterpret_cast<char*>((WebSocketChannel*)0x1000))
}, {&mozilla::detail::kImplementedIID<WebSocketChannel
, nsIProtocolProxyCallback>, int32_t( reinterpret_cast<
char*>(static_cast<nsIProtocolProxyCallback*>((WebSocketChannel
*)0x1000)) - reinterpret_cast<char*>((WebSocketChannel*
)0x1000))}, {&mozilla::detail::kImplementedIID<WebSocketChannel
, nsIInterfaceRequestor>, int32_t( reinterpret_cast<char
*>(static_cast<nsIInterfaceRequestor*>((WebSocketChannel
*)0x1000)) - reinterpret_cast<char*>((WebSocketChannel*
)0x1000))}, {&mozilla::detail::kImplementedIID<WebSocketChannel
, nsIChannelEventSink>, int32_t( reinterpret_cast<char*
>(static_cast<nsIChannelEventSink*>((WebSocketChannel
*)0x1000)) - reinterpret_cast<char*>((WebSocketChannel*
)0x1000))}, {&mozilla::detail::kImplementedIID<WebSocketChannel
, nsIThreadRetargetableRequest>, int32_t( reinterpret_cast
<char*>(static_cast<nsIThreadRetargetableRequest*>
((WebSocketChannel*)0x1000)) - reinterpret_cast<char*>(
(WebSocketChannel*)0x1000))}, {&mozilla::detail::kImplementedIID
<WebSocketChannel, nsIObserver>, int32_t( reinterpret_cast
<char*>(static_cast<nsIObserver*>((WebSocketChannel
*)0x1000)) - reinterpret_cast<char*>((WebSocketChannel*
)0x1000))}, {&mozilla::detail::kImplementedIID<WebSocketChannel
, nsINamed>, int32_t( reinterpret_cast<char*>(static_cast
<nsINamed*>((WebSocketChannel*)0x1000)) - reinterpret_cast
<char*>((WebSocketChannel*)0x1000))}, {&mozilla::detail
::kImplementedIID<WebSocketChannel, nsISupports>, int32_t
(reinterpret_cast<char*>(static_cast<nsISupports*>
( static_cast<nsIWebSocketChannel*>((WebSocketChannel*)
0x1000))) - reinterpret_cast<char*>((WebSocketChannel*)
0x1000))}, { nullptr, 0 } } ; static_assert(std::size(table) >
1, "need at least 1 interface"); rv = NS_TableDrivenQI(static_cast
<void*>(this), aIID, aInstancePtr, table); return rv; }
80 nsIProtocolProxyCallback, nsIInterfaceRequestor,MozExternalRefCountType WebSocketChannel::AddRef(void) { static_assert
(!std::is_destructible_v<WebSocketChannel>, "Reference-counted class "
"WebSocketChannel" " should not have a public destructor. " "Make this class's destructor non-public"
); do { static_assert( mozilla::detail::AssertionConditionType
<decltype(int32_t(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 82); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { MOZ_CrashSequence(__null, 82
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("WebSocketChannel" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("WebSocketChannel" != nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"\"WebSocketChannel\" != nullptr" " (" "Must specify a name" ")"
, "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 82); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"WebSocketChannel\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 82); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); if (!mRefCnt.isThreadSafe) _mOwningThread.AssertOwnership
("WebSocketChannel" " not thread-safe"); nsrefcnt count = ++mRefCnt
; NS_LogAddRef((this), (count), ("WebSocketChannel"), (uint32_t
)(sizeof(*this))); return count; } MozExternalRefCountType WebSocketChannel
::Release(void) { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(int32_t(mRefCnt) > 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) > 0))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0"
" (" "dup release" ")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 82); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { MOZ_CrashSequence(__null, 82)
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("WebSocketChannel" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("WebSocketChannel" != nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"\"WebSocketChannel\" != nullptr" " (" "Must specify a name" ")"
, "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 82); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"WebSocketChannel\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 82); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); if (!mRefCnt.isThreadSafe) _mOwningThread.AssertOwnership
("WebSocketChannel" " not thread-safe"); const char* const nametmp
= "WebSocketChannel"; nsrefcnt count = --mRefCnt; NS_LogRelease
((this), (count), (nametmp)); if (count == 0) { mRefCnt = 1; delete
(this); return 0; } return count; } nsresult WebSocketChannel
::QueryInterface(const nsIID& aIID, void** aInstancePtr) {
do { if (!(aInstancePtr)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "QueryInterface requires a non-NULL destination!", "aInstancePtr"
, "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 82); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE
; static_assert(14 > 0, "Need more arguments to NS_INTERFACE_TABLE"
); static const QITableEntry table[] = { {&mozilla::detail
::kImplementedIID<WebSocketChannel, nsIWebSocketChannel>
, int32_t( reinterpret_cast<char*>(static_cast<nsIWebSocketChannel
*>((WebSocketChannel*)0x1000)) - reinterpret_cast<char*
>((WebSocketChannel*)0x1000))}, {&mozilla::detail::kImplementedIID
<WebSocketChannel, nsIHttpUpgradeListener>, int32_t( reinterpret_cast
<char*>(static_cast<nsIHttpUpgradeListener*>((WebSocketChannel
*)0x1000)) - reinterpret_cast<char*>((WebSocketChannel*
)0x1000))}, {&mozilla::detail::kImplementedIID<WebSocketChannel
, nsIRequestObserver>, int32_t( reinterpret_cast<char*>
(static_cast<nsIRequestObserver*>((WebSocketChannel*)0x1000
)) - reinterpret_cast<char*>((WebSocketChannel*)0x1000)
)}, {&mozilla::detail::kImplementedIID<WebSocketChannel
, nsIStreamListener>, int32_t( reinterpret_cast<char*>
(static_cast<nsIStreamListener*>((WebSocketChannel*)0x1000
)) - reinterpret_cast<char*>((WebSocketChannel*)0x1000)
)}, {&mozilla::detail::kImplementedIID<WebSocketChannel
, nsIInputStreamCallback>, int32_t( reinterpret_cast<char
*>(static_cast<nsIInputStreamCallback*>((WebSocketChannel
*)0x1000)) - reinterpret_cast<char*>((WebSocketChannel*
)0x1000))}, {&mozilla::detail::kImplementedIID<WebSocketChannel
, nsIOutputStreamCallback>, int32_t( reinterpret_cast<char
*>(static_cast<nsIOutputStreamCallback*>((WebSocketChannel
*)0x1000)) - reinterpret_cast<char*>((WebSocketChannel*
)0x1000))}, {&mozilla::detail::kImplementedIID<WebSocketChannel
, nsITimerCallback>, int32_t( reinterpret_cast<char*>
(static_cast<nsITimerCallback*>((WebSocketChannel*)0x1000
)) - reinterpret_cast<char*>((WebSocketChannel*)0x1000)
)}, {&mozilla::detail::kImplementedIID<WebSocketChannel
, nsIDNSListener>, int32_t( reinterpret_cast<char*>(
static_cast<nsIDNSListener*>((WebSocketChannel*)0x1000)
) - reinterpret_cast<char*>((WebSocketChannel*)0x1000))
}, {&mozilla::detail::kImplementedIID<WebSocketChannel
, nsIProtocolProxyCallback>, int32_t( reinterpret_cast<
char*>(static_cast<nsIProtocolProxyCallback*>((WebSocketChannel
*)0x1000)) - reinterpret_cast<char*>((WebSocketChannel*
)0x1000))}, {&mozilla::detail::kImplementedIID<WebSocketChannel
, nsIInterfaceRequestor>, int32_t( reinterpret_cast<char
*>(static_cast<nsIInterfaceRequestor*>((WebSocketChannel
*)0x1000)) - reinterpret_cast<char*>((WebSocketChannel*
)0x1000))}, {&mozilla::detail::kImplementedIID<WebSocketChannel
, nsIChannelEventSink>, int32_t( reinterpret_cast<char*
>(static_cast<nsIChannelEventSink*>((WebSocketChannel
*)0x1000)) - reinterpret_cast<char*>((WebSocketChannel*
)0x1000))}, {&mozilla::detail::kImplementedIID<WebSocketChannel
, nsIThreadRetargetableRequest>, int32_t( reinterpret_cast
<char*>(static_cast<nsIThreadRetargetableRequest*>
((WebSocketChannel*)0x1000)) - reinterpret_cast<char*>(
(WebSocketChannel*)0x1000))}, {&mozilla::detail::kImplementedIID
<WebSocketChannel, nsIObserver>, int32_t( reinterpret_cast
<char*>(static_cast<nsIObserver*>((WebSocketChannel
*)0x1000)) - reinterpret_cast<char*>((WebSocketChannel*
)0x1000))}, {&mozilla::detail::kImplementedIID<WebSocketChannel
, nsINamed>, int32_t( reinterpret_cast<char*>(static_cast
<nsINamed*>((WebSocketChannel*)0x1000)) - reinterpret_cast
<char*>((WebSocketChannel*)0x1000))}, {&mozilla::detail
::kImplementedIID<WebSocketChannel, nsISupports>, int32_t
(reinterpret_cast<char*>(static_cast<nsISupports*>
( static_cast<nsIWebSocketChannel*>((WebSocketChannel*)
0x1000))) - reinterpret_cast<char*>((WebSocketChannel*)
0x1000))}, { nullptr, 0 } } ; static_assert(std::size(table) >
1, "need at least 1 interface"); rv = NS_TableDrivenQI(static_cast
<void*>(this), aIID, aInstancePtr, table); return rv; }
81 nsIChannelEventSink, nsIThreadRetargetableRequest,MozExternalRefCountType WebSocketChannel::AddRef(void) { static_assert
(!std::is_destructible_v<WebSocketChannel>, "Reference-counted class "
"WebSocketChannel" " should not have a public destructor. " "Make this class's destructor non-public"
); do { static_assert( mozilla::detail::AssertionConditionType
<decltype(int32_t(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 82); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { MOZ_CrashSequence(__null, 82
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("WebSocketChannel" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("WebSocketChannel" != nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"\"WebSocketChannel\" != nullptr" " (" "Must specify a name" ")"
, "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 82); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"WebSocketChannel\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 82); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); if (!mRefCnt.isThreadSafe) _mOwningThread.AssertOwnership
("WebSocketChannel" " not thread-safe"); nsrefcnt count = ++mRefCnt
; NS_LogAddRef((this), (count), ("WebSocketChannel"), (uint32_t
)(sizeof(*this))); return count; } MozExternalRefCountType WebSocketChannel
::Release(void) { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(int32_t(mRefCnt) > 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) > 0))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0"
" (" "dup release" ")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 82); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { MOZ_CrashSequence(__null, 82)
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("WebSocketChannel" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("WebSocketChannel" != nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"\"WebSocketChannel\" != nullptr" " (" "Must specify a name" ")"
, "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 82); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"WebSocketChannel\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 82); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); if (!mRefCnt.isThreadSafe) _mOwningThread.AssertOwnership
("WebSocketChannel" " not thread-safe"); const char* const nametmp
= "WebSocketChannel"; nsrefcnt count = --mRefCnt; NS_LogRelease
((this), (count), (nametmp)); if (count == 0) { mRefCnt = 1; delete
(this); return 0; } return count; } nsresult WebSocketChannel
::QueryInterface(const nsIID& aIID, void** aInstancePtr) {
do { if (!(aInstancePtr)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "QueryInterface requires a non-NULL destination!", "aInstancePtr"
, "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 82); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE
; static_assert(14 > 0, "Need more arguments to NS_INTERFACE_TABLE"
); static const QITableEntry table[] = { {&mozilla::detail
::kImplementedIID<WebSocketChannel, nsIWebSocketChannel>
, int32_t( reinterpret_cast<char*>(static_cast<nsIWebSocketChannel
*>((WebSocketChannel*)0x1000)) - reinterpret_cast<char*
>((WebSocketChannel*)0x1000))}, {&mozilla::detail::kImplementedIID
<WebSocketChannel, nsIHttpUpgradeListener>, int32_t( reinterpret_cast
<char*>(static_cast<nsIHttpUpgradeListener*>((WebSocketChannel
*)0x1000)) - reinterpret_cast<char*>((WebSocketChannel*
)0x1000))}, {&mozilla::detail::kImplementedIID<WebSocketChannel
, nsIRequestObserver>, int32_t( reinterpret_cast<char*>
(static_cast<nsIRequestObserver*>((WebSocketChannel*)0x1000
)) - reinterpret_cast<char*>((WebSocketChannel*)0x1000)
)}, {&mozilla::detail::kImplementedIID<WebSocketChannel
, nsIStreamListener>, int32_t( reinterpret_cast<char*>
(static_cast<nsIStreamListener*>((WebSocketChannel*)0x1000
)) - reinterpret_cast<char*>((WebSocketChannel*)0x1000)
)}, {&mozilla::detail::kImplementedIID<WebSocketChannel
, nsIInputStreamCallback>, int32_t( reinterpret_cast<char
*>(static_cast<nsIInputStreamCallback*>((WebSocketChannel
*)0x1000)) - reinterpret_cast<char*>((WebSocketChannel*
)0x1000))}, {&mozilla::detail::kImplementedIID<WebSocketChannel
, nsIOutputStreamCallback>, int32_t( reinterpret_cast<char
*>(static_cast<nsIOutputStreamCallback*>((WebSocketChannel
*)0x1000)) - reinterpret_cast<char*>((WebSocketChannel*
)0x1000))}, {&mozilla::detail::kImplementedIID<WebSocketChannel
, nsITimerCallback>, int32_t( reinterpret_cast<char*>
(static_cast<nsITimerCallback*>((WebSocketChannel*)0x1000
)) - reinterpret_cast<char*>((WebSocketChannel*)0x1000)
)}, {&mozilla::detail::kImplementedIID<WebSocketChannel
, nsIDNSListener>, int32_t( reinterpret_cast<char*>(
static_cast<nsIDNSListener*>((WebSocketChannel*)0x1000)
) - reinterpret_cast<char*>((WebSocketChannel*)0x1000))
}, {&mozilla::detail::kImplementedIID<WebSocketChannel
, nsIProtocolProxyCallback>, int32_t( reinterpret_cast<
char*>(static_cast<nsIProtocolProxyCallback*>((WebSocketChannel
*)0x1000)) - reinterpret_cast<char*>((WebSocketChannel*
)0x1000))}, {&mozilla::detail::kImplementedIID<WebSocketChannel
, nsIInterfaceRequestor>, int32_t( reinterpret_cast<char
*>(static_cast<nsIInterfaceRequestor*>((WebSocketChannel
*)0x1000)) - reinterpret_cast<char*>((WebSocketChannel*
)0x1000))}, {&mozilla::detail::kImplementedIID<WebSocketChannel
, nsIChannelEventSink>, int32_t( reinterpret_cast<char*
>(static_cast<nsIChannelEventSink*>((WebSocketChannel
*)0x1000)) - reinterpret_cast<char*>((WebSocketChannel*
)0x1000))}, {&mozilla::detail::kImplementedIID<WebSocketChannel
, nsIThreadRetargetableRequest>, int32_t( reinterpret_cast
<char*>(static_cast<nsIThreadRetargetableRequest*>
((WebSocketChannel*)0x1000)) - reinterpret_cast<char*>(
(WebSocketChannel*)0x1000))}, {&mozilla::detail::kImplementedIID
<WebSocketChannel, nsIObserver>, int32_t( reinterpret_cast
<char*>(static_cast<nsIObserver*>((WebSocketChannel
*)0x1000)) - reinterpret_cast<char*>((WebSocketChannel*
)0x1000))}, {&mozilla::detail::kImplementedIID<WebSocketChannel
, nsINamed>, int32_t( reinterpret_cast<char*>(static_cast
<nsINamed*>((WebSocketChannel*)0x1000)) - reinterpret_cast
<char*>((WebSocketChannel*)0x1000))}, {&mozilla::detail
::kImplementedIID<WebSocketChannel, nsISupports>, int32_t
(reinterpret_cast<char*>(static_cast<nsISupports*>
( static_cast<nsIWebSocketChannel*>((WebSocketChannel*)
0x1000))) - reinterpret_cast<char*>((WebSocketChannel*)
0x1000))}, { nullptr, 0 } } ; static_assert(std::size(table) >
1, "need at least 1 interface"); rv = NS_TableDrivenQI(static_cast
<void*>(this), aIID, aInstancePtr, table); return rv; }
82 nsIObserver, nsINamed)MozExternalRefCountType WebSocketChannel::AddRef(void) { static_assert
(!std::is_destructible_v<WebSocketChannel>, "Reference-counted class "
"WebSocketChannel" " should not have a public destructor. " "Make this class's destructor non-public"
); do { static_assert( mozilla::detail::AssertionConditionType
<decltype(int32_t(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 82); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { MOZ_CrashSequence(__null, 82
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("WebSocketChannel" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("WebSocketChannel" != nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"\"WebSocketChannel\" != nullptr" " (" "Must specify a name" ")"
, "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 82); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"WebSocketChannel\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 82); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); if (!mRefCnt.isThreadSafe) _mOwningThread.AssertOwnership
("WebSocketChannel" " not thread-safe"); nsrefcnt count = ++mRefCnt
; NS_LogAddRef((this), (count), ("WebSocketChannel"), (uint32_t
)(sizeof(*this))); return count; } MozExternalRefCountType WebSocketChannel
::Release(void) { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(int32_t(mRefCnt) > 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) > 0))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0"
" (" "dup release" ")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 82); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { MOZ_CrashSequence(__null, 82)
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("WebSocketChannel" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("WebSocketChannel" != nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"\"WebSocketChannel\" != nullptr" " (" "Must specify a name" ")"
, "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 82); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"WebSocketChannel\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 82); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); if (!mRefCnt.isThreadSafe) _mOwningThread.AssertOwnership
("WebSocketChannel" " not thread-safe"); const char* const nametmp
= "WebSocketChannel"; nsrefcnt count = --mRefCnt; NS_LogRelease
((this), (count), (nametmp)); if (count == 0) { mRefCnt = 1; delete
(this); return 0; } return count; } nsresult WebSocketChannel
::QueryInterface(const nsIID& aIID, void** aInstancePtr) {
do { if (!(aInstancePtr)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "QueryInterface requires a non-NULL destination!", "aInstancePtr"
, "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 82); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE
; static_assert(14 > 0, "Need more arguments to NS_INTERFACE_TABLE"
); static const QITableEntry table[] = { {&mozilla::detail
::kImplementedIID<WebSocketChannel, nsIWebSocketChannel>
, int32_t( reinterpret_cast<char*>(static_cast<nsIWebSocketChannel
*>((WebSocketChannel*)0x1000)) - reinterpret_cast<char*
>((WebSocketChannel*)0x1000))}, {&mozilla::detail::kImplementedIID
<WebSocketChannel, nsIHttpUpgradeListener>, int32_t( reinterpret_cast
<char*>(static_cast<nsIHttpUpgradeListener*>((WebSocketChannel
*)0x1000)) - reinterpret_cast<char*>((WebSocketChannel*
)0x1000))}, {&mozilla::detail::kImplementedIID<WebSocketChannel
, nsIRequestObserver>, int32_t( reinterpret_cast<char*>
(static_cast<nsIRequestObserver*>((WebSocketChannel*)0x1000
)) - reinterpret_cast<char*>((WebSocketChannel*)0x1000)
)}, {&mozilla::detail::kImplementedIID<WebSocketChannel
, nsIStreamListener>, int32_t( reinterpret_cast<char*>
(static_cast<nsIStreamListener*>((WebSocketChannel*)0x1000
)) - reinterpret_cast<char*>((WebSocketChannel*)0x1000)
)}, {&mozilla::detail::kImplementedIID<WebSocketChannel
, nsIInputStreamCallback>, int32_t( reinterpret_cast<char
*>(static_cast<nsIInputStreamCallback*>((WebSocketChannel
*)0x1000)) - reinterpret_cast<char*>((WebSocketChannel*
)0x1000))}, {&mozilla::detail::kImplementedIID<WebSocketChannel
, nsIOutputStreamCallback>, int32_t( reinterpret_cast<char
*>(static_cast<nsIOutputStreamCallback*>((WebSocketChannel
*)0x1000)) - reinterpret_cast<char*>((WebSocketChannel*
)0x1000))}, {&mozilla::detail::kImplementedIID<WebSocketChannel
, nsITimerCallback>, int32_t( reinterpret_cast<char*>
(static_cast<nsITimerCallback*>((WebSocketChannel*)0x1000
)) - reinterpret_cast<char*>((WebSocketChannel*)0x1000)
)}, {&mozilla::detail::kImplementedIID<WebSocketChannel
, nsIDNSListener>, int32_t( reinterpret_cast<char*>(
static_cast<nsIDNSListener*>((WebSocketChannel*)0x1000)
) - reinterpret_cast<char*>((WebSocketChannel*)0x1000))
}, {&mozilla::detail::kImplementedIID<WebSocketChannel
, nsIProtocolProxyCallback>, int32_t( reinterpret_cast<
char*>(static_cast<nsIProtocolProxyCallback*>((WebSocketChannel
*)0x1000)) - reinterpret_cast<char*>((WebSocketChannel*
)0x1000))}, {&mozilla::detail::kImplementedIID<WebSocketChannel
, nsIInterfaceRequestor>, int32_t( reinterpret_cast<char
*>(static_cast<nsIInterfaceRequestor*>((WebSocketChannel
*)0x1000)) - reinterpret_cast<char*>((WebSocketChannel*
)0x1000))}, {&mozilla::detail::kImplementedIID<WebSocketChannel
, nsIChannelEventSink>, int32_t( reinterpret_cast<char*
>(static_cast<nsIChannelEventSink*>((WebSocketChannel
*)0x1000)) - reinterpret_cast<char*>((WebSocketChannel*
)0x1000))}, {&mozilla::detail::kImplementedIID<WebSocketChannel
, nsIThreadRetargetableRequest>, int32_t( reinterpret_cast
<char*>(static_cast<nsIThreadRetargetableRequest*>
((WebSocketChannel*)0x1000)) - reinterpret_cast<char*>(
(WebSocketChannel*)0x1000))}, {&mozilla::detail::kImplementedIID
<WebSocketChannel, nsIObserver>, int32_t( reinterpret_cast
<char*>(static_cast<nsIObserver*>((WebSocketChannel
*)0x1000)) - reinterpret_cast<char*>((WebSocketChannel*
)0x1000))}, {&mozilla::detail::kImplementedIID<WebSocketChannel
, nsINamed>, int32_t( reinterpret_cast<char*>(static_cast
<nsINamed*>((WebSocketChannel*)0x1000)) - reinterpret_cast
<char*>((WebSocketChannel*)0x1000))}, {&mozilla::detail
::kImplementedIID<WebSocketChannel, nsISupports>, int32_t
(reinterpret_cast<char*>(static_cast<nsISupports*>
( static_cast<nsIWebSocketChannel*>((WebSocketChannel*)
0x1000))) - reinterpret_cast<char*>((WebSocketChannel*)
0x1000))}, { nullptr, 0 } } ; static_assert(std::size(table) >
1, "need at least 1 interface"); rv = NS_TableDrivenQI(static_cast
<void*>(this), aIID, aInstancePtr, table); return rv; }
83
84// We implement RFC 6455, which uses Sec-WebSocket-Version: 13 on the wire.
85#define SEC_WEBSOCKET_VERSION"13" "13"
86
87/*
88 * About SSL unsigned certificates
89 *
90 * wss will not work to a host using an unsigned certificate unless there
91 * is already an exception (i.e. it cannot popup a dialog asking for
92 * a security exception). This is similar to how an inlined img will
93 * fail without a dialog if fails for the same reason. This should not
94 * be a problem in practice as it is expected the websocket javascript
95 * is served from the same host as the websocket server (or of course,
96 * a valid cert could just be provided).
97 *
98 */
99
100// some helper classes
101
102//-----------------------------------------------------------------------------
103// FailDelayManager
104//
105// Stores entries (searchable by {host, port}) of connections that have recently
106// failed, so we can do delay of reconnects per RFC 6455 Section 7.2.3
107//-----------------------------------------------------------------------------
108
109// Initial reconnect delay is randomly chosen between 200-400 ms.
110// This is a gentler backoff than the 0-5 seconds the spec offhandedly suggests.
111const uint32_t kWSReconnectInitialBaseDelay = 200;
112const uint32_t kWSReconnectInitialRandomDelay = 200;
113
114// Base lifetime (in ms) of a FailDelay: kept longer if more failures occur
115const uint32_t kWSReconnectBaseLifeTime = 60 * 1000;
116// Maximum reconnect delay (in ms)
117const uint32_t kWSReconnectMaxDelay = 60 * 1000;
118
119// hold record of failed connections, and calculates needed delay for reconnects
120// to same host/path/port.
121class FailDelay {
122 public:
123 FailDelay(nsCString address, nsCString path, int32_t port,
124 nsCString originSuffix)
125 : mAddress(std::move(address)),
126 mPath(std::move(path)),
127 mPort(port),
128 mOriginSuffix(std::move(originSuffix)) {
129 mLastFailure = TimeStamp::Now();
130 mNextDelay = kWSReconnectInitialBaseDelay +
131 (rand() % kWSReconnectInitialRandomDelay);
132 }
133
134 // Called to update settings when connection fails again.
135 void FailedAgain() {
136 mLastFailure = TimeStamp::Now();
137 // We use a truncated exponential backoff as suggested by RFC 6455,
138 // but multiply by 1.5 instead of 2 to be more gradual.
139 mNextDelay = static_cast<uint32_t>(
140 std::min<double>(kWSReconnectMaxDelay, mNextDelay * 1.5));
141 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocket: FailedAgain: host=%s, path=%s, port=%d: incremented delay "
"to " "%" "u", mAddress.get(), mPath.get(), mPort, mNextDelay
); } } while (0)
142 ("WebSocket: FailedAgain: host=%s, path=%s, port=%d: incremented delay "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocket: FailedAgain: host=%s, path=%s, port=%d: incremented delay "
"to " "%" "u", mAddress.get(), mPath.get(), mPort, mNextDelay
); } } while (0)
143 "to "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocket: FailedAgain: host=%s, path=%s, port=%d: incremented delay "
"to " "%" "u", mAddress.get(), mPath.get(), mPort, mNextDelay
); } } while (0)
144 "%" PRIu32,do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocket: FailedAgain: host=%s, path=%s, port=%d: incremented delay "
"to " "%" "u", mAddress.get(), mPath.get(), mPort, mNextDelay
); } } while (0)
145 mAddress.get(), mPath.get(), mPort, mNextDelay))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocket: FailedAgain: host=%s, path=%s, port=%d: incremented delay "
"to " "%" "u", mAddress.get(), mPath.get(), mPort, mNextDelay
); } } while (0)
;
146 }
147
148 // returns 0 if there is no need to delay (i.e. delay interval is over)
149 uint32_t RemainingDelay(TimeStamp rightNow) {
150 TimeDuration dur = rightNow - mLastFailure;
151 uint32_t sinceFail = (uint32_t)dur.ToMilliseconds();
152 if (sinceFail > mNextDelay) return 0;
153
154 return mNextDelay - sinceFail;
155 }
156
157 bool IsExpired(TimeStamp rightNow) {
158 return (mLastFailure + TimeDuration::FromMilliseconds(
159 kWSReconnectBaseLifeTime + mNextDelay)) <=
160 rightNow;
161 }
162
163 nsCString mAddress; // IP address (or hostname if using proxy)
164 nsCString mPath;
165 int32_t mPort;
166 nsCString mOriginSuffix;
167
168 private:
169 TimeStamp mLastFailure; // Time of last failed attempt
170 // mLastFailure + mNextDelay is the soonest we'll allow a reconnect
171 uint32_t mNextDelay; // milliseconds
172};
173
174class FailDelayManager {
175 public:
176 FailDelayManager() {
177 MOZ_COUNT_CTOR(FailDelayManager)do { static_assert(std::is_class_v<FailDelayManager>, "Token '"
"FailDelayManager" "' is not a class type."); static_assert(
!std::is_base_of_v<nsISupports, FailDelayManager>, "nsISupports classes don't need to call MOZ_COUNT_CTOR or "
"MOZ_COUNT_DTOR");; NS_LogCtor((void*)this, "FailDelayManager"
, sizeof(*this)); } while (0)
;
178
179 mDelaysDisabled = false;
180
181 nsCOMPtr<nsIPrefBranch> prefService;
182 prefService = mozilla::components::Preferences::Service();
183 if (!prefService) {
184 return;
185 }
186 bool boolpref = true;
187 nsresult rv;
188 rv = prefService->GetBoolPref("network.websocket.delay-failed-reconnects",
189 &boolpref);
190 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) && !boolpref) {
191 mDelaysDisabled = true;
192 }
193 }
194
195 ~FailDelayManager() { MOZ_COUNT_DTOR(FailDelayManager)do { static_assert(std::is_class_v<FailDelayManager>, "Token '"
"FailDelayManager" "' is not a class type."); static_assert(
!std::is_base_of_v<nsISupports, FailDelayManager>, "nsISupports classes don't need to call MOZ_COUNT_CTOR or "
"MOZ_COUNT_DTOR");; NS_LogDtor((void*)this, "FailDelayManager"
, sizeof(*this)); } while (0)
; }
196
197 void Add(nsCString& address, nsCString& path, int32_t port,
198 nsCString& originSuffix) {
199 if (mDelaysDisabled) {
200 return;
201 }
202
203 mEntries.AppendElement(
204 MakeUnique<FailDelay>(address, path, port, originSuffix));
205 }
206
207 // Element returned may not be valid after next main thread event: don't keep
208 // pointer to it around
209 FailDelay* Lookup(nsCString& address, nsCString& path, int32_t port,
210 nsCString& originSuffix, uint32_t* outIndex = nullptr) {
211 if (mDelaysDisabled) {
212 return nullptr;
213 }
214
215 FailDelay* result = nullptr;
216 TimeStamp rightNow = TimeStamp::Now();
217
218 // We also remove expired entries during search: iterate from end to make
219 // indexing simpler
220 for (int32_t i = mEntries.Length() - 1; i >= 0; --i) {
221 FailDelay* fail = mEntries[i].get();
222 if (fail->mAddress.Equals(address) && fail->mPath.Equals(path) &&
223 fail->mPort == port && fail->mOriginSuffix.Equals(originSuffix)) {
224 if (outIndex) *outIndex = i;
225 result = fail;
226 // break here: removing more entries would mess up *outIndex.
227 // Any remaining expired entries will be deleted next time Lookup
228 // finds nothing, which is the most common case anyway.
229 break;
230 }
231 if (fail->IsExpired(rightNow)) {
232 mEntries.RemoveElementAt(i);
233 }
234 }
235 return result;
236 }
237
238 // returns true if channel connects immediately, or false if it's delayed
239 void DelayOrBegin(WebSocketChannel* ws) {
240 if (!mDelaysDisabled) {
241 uint32_t failIndex = 0;
242 FailDelay* fail = Lookup(ws->mAddress, ws->mPath, ws->mPort,
243 ws->mOriginSuffix, &failIndex);
244
245 if (fail) {
246 TimeStamp rightNow = TimeStamp::Now();
247
248 uint32_t remainingDelay = fail->RemainingDelay(rightNow);
249 if (remainingDelay) {
250 // reconnecting within delay interval: delay by remaining time
251 nsresult rv;
252 MutexAutoLock lock(ws->mMutex);
253 rv = NS_NewTimerWithCallback(getter_AddRefs(ws->mReconnectDelayTimer),
254 ws, remainingDelay,
255 nsITimer::TYPE_ONE_SHOT);
256 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
257 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocket: delaying websocket [this=%p] by %lu ms, changing"
" state to CONNECTING_DELAYED", ws, (unsigned long)remainingDelay
); } } while (0)
258 ("WebSocket: delaying websocket [this=%p] by %lu ms, changing"do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocket: delaying websocket [this=%p] by %lu ms, changing"
" state to CONNECTING_DELAYED", ws, (unsigned long)remainingDelay
); } } while (0)
259 " state to CONNECTING_DELAYED",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocket: delaying websocket [this=%p] by %lu ms, changing"
" state to CONNECTING_DELAYED", ws, (unsigned long)remainingDelay
); } } while (0)
260 ws, (unsigned long)remainingDelay))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocket: delaying websocket [this=%p] by %lu ms, changing"
" state to CONNECTING_DELAYED", ws, (unsigned long)remainingDelay
); } } while (0)
;
261 ws->mConnecting = CONNECTING_DELAYED;
262 return;
263 }
264 // if timer fails (which is very unlikely), drop down to BeginOpen
265 // call
266 } else if (fail->IsExpired(rightNow)) {
267 mEntries.RemoveElementAt(failIndex);
268 }
269 }
270 }
271
272 // Delays disabled, or no previous failure, or we're reconnecting after
273 // scheduled delay interval has passed: connect.
274 ws->BeginOpen(true);
275 }
276
277 // Remove() also deletes all expired entries as it iterates: better for
278 // battery life than using a periodic timer.
279 void Remove(nsCString& address, nsCString& path, int32_t port,
280 nsCString& originSuffix) {
281 TimeStamp rightNow = TimeStamp::Now();
282
283 // iterate from end, to make deletion indexing easier
284 for (int32_t i = mEntries.Length() - 1; i >= 0; --i) {
285 FailDelay* entry = mEntries[i].get();
286 if ((entry->mAddress.Equals(address) && entry->mPath.Equals(path) &&
287 entry->mPort == port && entry->mOriginSuffix.Equals(originSuffix)) ||
288 entry->IsExpired(rightNow)) {
289 mEntries.RemoveElementAt(i);
290 }
291 }
292 }
293
294 private:
295 nsTArray<UniquePtr<FailDelay>> mEntries;
296 bool mDelaysDisabled;
297};
298
299//-----------------------------------------------------------------------------
300// nsWSAdmissionManager
301//
302// 1) Ensures that only one websocket at a time is CONNECTING to a given IP
303// address (or hostname, if using proxy), per RFC 6455 Section 4.1.
304// 2) Delays reconnects to IP/host after connection failure, per Section 7.2.3
305//-----------------------------------------------------------------------------
306
307class nsWSAdmissionManager {
308 public:
309 static void Init() {
310 StaticMutexAutoLock lock(sLock);
311 if (!sManager) {
312 sManager = new nsWSAdmissionManager();
313 }
314 }
315
316 static void Shutdown() {
317 StaticMutexAutoLock lock(sLock);
318 delete sManager;
319 sManager = nullptr;
320 }
321
322 // Determine if we will open connection immediately (returns true), or
323 // delay/queue the connection (returns false)
324 static void ConditionallyConnect(WebSocketChannel* ws) {
325 LOG(("Websocket: ConditionallyConnect: [this=%p]", ws))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "Websocket: ConditionallyConnect: [this=%p]"
, ws); } } while (0)
;
326 MOZ_ASSERT(NS_IsMainThread(), "not main thread")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
" (" "not main thread" ")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 326); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
") (" "not main thread" ")"); do { MOZ_CrashSequence(__null,
326); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false)
;
327 MOZ_ASSERT(ws->mConnecting == NOT_CONNECTING, "opening state")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(ws->mConnecting == NOT_CONNECTING)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(ws->mConnecting == NOT_CONNECTING
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"ws->mConnecting == NOT_CONNECTING" " (" "opening state" ")"
, "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 327); AnnotateMozCrashReason("MOZ_ASSERT" "(" "ws->mConnecting == NOT_CONNECTING"
") (" "opening state" ")"); do { MOZ_CrashSequence(__null, 327
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
;
328
329 StaticMutexAutoLock lock(sLock);
330 if (!sManager) {
331 return;
332 }
333
334 // If there is already another WS channel connecting to this IP address,
335 // defer BeginOpen and mark as waiting in queue.
336 bool hostFound = (sManager->IndexOf(ws->mAddress, ws->mOriginSuffix) >= 0);
337
338 uint32_t failIndex = 0;
339 FailDelay* fail = sManager->mFailures.Lookup(
340 ws->mAddress, ws->mPath, ws->mPort, ws->mOriginSuffix, &failIndex);
341 bool existingFail = fail != nullptr;
342
343 // Always add ourselves to queue, even if we'll connect immediately
344 auto newdata = MakeUnique<nsOpenConn>(ws->mAddress, ws->mOriginSuffix,
345 existingFail, ws);
346
347 // If a connection has not previously failed then prioritize it over
348 // connections that have
349 if (existingFail) {
350 sManager->mQueue.AppendElement(std::move(newdata));
351 } else {
352 uint32_t insertionIndex = sManager->IndexOfFirstFailure();
353 MOZ_ASSERT(insertionIndex <= sManager->mQueue.Length(),do { static_assert( mozilla::detail::AssertionConditionType<
decltype(insertionIndex <= sManager->mQueue.Length())>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(insertionIndex <= sManager->mQueue.Length())))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("insertionIndex <= sManager->mQueue.Length()"
" (" "Insertion index outside bounds" ")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 354); AnnotateMozCrashReason("MOZ_ASSERT" "(" "insertionIndex <= sManager->mQueue.Length()"
") (" "Insertion index outside bounds" ")"); do { MOZ_CrashSequence
(__null, 354); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
354 "Insertion index outside bounds")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(insertionIndex <= sManager->mQueue.Length())>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(insertionIndex <= sManager->mQueue.Length())))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("insertionIndex <= sManager->mQueue.Length()"
" (" "Insertion index outside bounds" ")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 354); AnnotateMozCrashReason("MOZ_ASSERT" "(" "insertionIndex <= sManager->mQueue.Length()"
") (" "Insertion index outside bounds" ")"); do { MOZ_CrashSequence
(__null, 354); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
355 sManager->mQueue.InsertElementAt(insertionIndex, std::move(newdata));
356 }
357
358 if (hostFound) {
359 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "Websocket: some other channel is connecting, changing state to "
"CONNECTING_QUEUED"); } } while (0)
360 ("Websocket: some other channel is connecting, changing state to "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "Websocket: some other channel is connecting, changing state to "
"CONNECTING_QUEUED"); } } while (0)
361 "CONNECTING_QUEUED"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "Websocket: some other channel is connecting, changing state to "
"CONNECTING_QUEUED"); } } while (0)
;
362 ws->mConnecting = CONNECTING_QUEUED;
363 } else {
364 sManager->mFailures.DelayOrBegin(ws);
365 }
366 }
367
368 static void OnConnected(WebSocketChannel* aChannel) {
369 LOG(("Websocket: OnConnected: [this=%p]", aChannel))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "Websocket: OnConnected: [this=%p]"
, aChannel); } } while (0)
;
370
371 MOZ_ASSERT(NS_IsMainThread(), "not main thread")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
" (" "not main thread" ")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 371); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
") (" "not main thread" ")"); do { MOZ_CrashSequence(__null,
371); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false)
;
372 MOZ_ASSERT(aChannel->mConnecting == CONNECTING_IN_PROGRESS,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aChannel->mConnecting == CONNECTING_IN_PROGRESS)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aChannel->mConnecting == CONNECTING_IN_PROGRESS))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aChannel->mConnecting == CONNECTING_IN_PROGRESS"
" (" "Channel completed connect, but not connecting?" ")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 373); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChannel->mConnecting == CONNECTING_IN_PROGRESS"
") (" "Channel completed connect, but not connecting?" ")");
do { MOZ_CrashSequence(__null, 373); __attribute__((nomerge)
) ::abort(); } while (false); } } while (false)
373 "Channel completed connect, but not connecting?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aChannel->mConnecting == CONNECTING_IN_PROGRESS)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(aChannel->mConnecting == CONNECTING_IN_PROGRESS))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("aChannel->mConnecting == CONNECTING_IN_PROGRESS"
" (" "Channel completed connect, but not connecting?" ")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 373); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChannel->mConnecting == CONNECTING_IN_PROGRESS"
") (" "Channel completed connect, but not connecting?" ")");
do { MOZ_CrashSequence(__null, 373); __attribute__((nomerge)
) ::abort(); } while (false); } } while (false)
;
374
375 StaticMutexAutoLock lock(sLock);
376 if (!sManager) {
377 return;
378 }
379
380 LOG(("Websocket: changing state to NOT_CONNECTING"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "Websocket: changing state to NOT_CONNECTING"
); } } while (0)
;
381 aChannel->mConnecting = NOT_CONNECTING;
382
383 // Remove from queue
384 sManager->RemoveFromQueue(aChannel);
385
386 // Connection succeeded, so stop keeping track of any previous failures
387 sManager->mFailures.Remove(aChannel->mAddress, aChannel->mPath,
388 aChannel->mPort, aChannel->mOriginSuffix);
389
390 // Check for queued connections to same host.
391 // Note: still need to check for failures, since next websocket with same
392 // host may have different port
393 sManager->ConnectNext(aChannel->mAddress, aChannel->mOriginSuffix);
394 }
395
396 // Called every time a websocket channel ends its session (including going
397 // away w/o ever successfully creating a connection)
398 static void OnStopSession(WebSocketChannel* aChannel, nsresult aReason) {
399 LOG(("Websocket: OnStopSession: [this=%p, reason=0x%08" PRIx32 "]",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "Websocket: OnStopSession: [this=%p, reason=0x%08"
"x" "]", aChannel, static_cast<uint32_t>(aReason)); } }
while (0)
400 aChannel, static_cast<uint32_t>(aReason)))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "Websocket: OnStopSession: [this=%p, reason=0x%08"
"x" "]", aChannel, static_cast<uint32_t>(aReason)); } }
while (0)
;
401
402 StaticMutexAutoLock lock(sLock);
403 if (!sManager) {
404 return;
405 }
406
407 if (NS_FAILED(aReason)((bool)(__builtin_expect(!!(NS_FAILED_impl(aReason)), 0)))) {
408 // Have we seen this failure before?
409 FailDelay* knownFailure =
410 sManager->mFailures.Lookup(aChannel->mAddress, aChannel->mPath,
411 aChannel->mPort, aChannel->mOriginSuffix);
412 if (knownFailure) {
413 if (aReason == NS_ERROR_NOT_CONNECTED) {
414 // Don't count close() before connection as a network error
415 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "Websocket close() before connection to %s, %s, %d completed"
" [this=%p]", aChannel->mAddress.get(), aChannel->mPath
.get(), (int)aChannel->mPort, aChannel); } } while (0)
416 ("Websocket close() before connection to %s, %s, %d completed"do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "Websocket close() before connection to %s, %s, %d completed"
" [this=%p]", aChannel->mAddress.get(), aChannel->mPath
.get(), (int)aChannel->mPort, aChannel); } } while (0)
417 " [this=%p]",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "Websocket close() before connection to %s, %s, %d completed"
" [this=%p]", aChannel->mAddress.get(), aChannel->mPath
.get(), (int)aChannel->mPort, aChannel); } } while (0)
418 aChannel->mAddress.get(), aChannel->mPath.get(),do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "Websocket close() before connection to %s, %s, %d completed"
" [this=%p]", aChannel->mAddress.get(), aChannel->mPath
.get(), (int)aChannel->mPort, aChannel); } } while (0)
419 (int)aChannel->mPort, aChannel))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "Websocket close() before connection to %s, %s, %d completed"
" [this=%p]", aChannel->mAddress.get(), aChannel->mPath
.get(), (int)aChannel->mPort, aChannel); } } while (0)
;
420 } else {
421 // repeated failure to connect: increase delay for next connection
422 knownFailure->FailedAgain();
423 }
424 } else {
425 // new connection failure: record it.
426 LOG(("WebSocket: connection to %s, %s, %d failed: [this=%p]",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocket: connection to %s, %s, %d failed: [this=%p]"
, aChannel->mAddress.get(), aChannel->mPath.get(), (int
)aChannel->mPort, aChannel); } } while (0)
427 aChannel->mAddress.get(), aChannel->mPath.get(),do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocket: connection to %s, %s, %d failed: [this=%p]"
, aChannel->mAddress.get(), aChannel->mPath.get(), (int
)aChannel->mPort, aChannel); } } while (0)
428 (int)aChannel->mPort, aChannel))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocket: connection to %s, %s, %d failed: [this=%p]"
, aChannel->mAddress.get(), aChannel->mPath.get(), (int
)aChannel->mPort, aChannel); } } while (0)
;
429 sManager->mFailures.Add(aChannel->mAddress, aChannel->mPath,
430 aChannel->mPort, aChannel->mOriginSuffix);
431 }
432 }
433
434 if (NS_IsMainThread()) {
435 ContinueOnStopSession(aChannel, aReason);
436 } else {
437 NS_DispatchToMainThread(NS_NewRunnableFunction(
438 "nsWSAdmissionManager::ContinueOnStopSession",
439 [channel = RefPtr{aChannel}, reason = aReason]() {
440 StaticMutexAutoLock lock(sLock);
441 if (!sManager) {
442 return;
443 }
444
445 nsWSAdmissionManager::ContinueOnStopSession(channel, reason);
446 }));
447 }
448 }
449
450 static void ContinueOnStopSession(WebSocketChannel* aChannel,
451 nsresult aReason) {
452 sLock.AssertCurrentThreadOwns();
453 MOZ_ASSERT(NS_IsMainThread(), "not main thread")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
" (" "not main thread" ")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 453); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
") (" "not main thread" ")"); do { MOZ_CrashSequence(__null,
453); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false)
;
454
455 if (!aChannel->mConnecting) {
456 return;
457 }
458
459 // Only way a connecting channel may get here w/o failing is if it
460 // was closed with GOING_AWAY (1001) because of navigation, tab
461 // close, etc.
462#ifdef DEBUG1
463 {
464 MutexAutoLock lock(aChannel->mMutex);
465 MOZ_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType<
decltype(((bool)(__builtin_expect(!!(NS_FAILED_impl(aReason))
, 0))) || aChannel->mScriptCloseCode == CLOSE_GOING_AWAY)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(((bool)(__builtin_expect(!!(NS_FAILED_impl(aReason))
, 0))) || aChannel->mScriptCloseCode == CLOSE_GOING_AWAY))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("((bool)(__builtin_expect(!!(NS_FAILED_impl(aReason)), 0))) || aChannel->mScriptCloseCode == CLOSE_GOING_AWAY"
" (" "websocket closed while connecting w/o failing?" ")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 467); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(NS_FAILED_impl(aReason)), 0))) || aChannel->mScriptCloseCode == CLOSE_GOING_AWAY"
") (" "websocket closed while connecting w/o failing?" ")");
do { MOZ_CrashSequence(__null, 467); __attribute__((nomerge)
) ::abort(); } while (false); } } while (false)
466 NS_FAILED(aReason) || aChannel->mScriptCloseCode == CLOSE_GOING_AWAY,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(((bool)(__builtin_expect(!!(NS_FAILED_impl(aReason))
, 0))) || aChannel->mScriptCloseCode == CLOSE_GOING_AWAY)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(((bool)(__builtin_expect(!!(NS_FAILED_impl(aReason))
, 0))) || aChannel->mScriptCloseCode == CLOSE_GOING_AWAY))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("((bool)(__builtin_expect(!!(NS_FAILED_impl(aReason)), 0))) || aChannel->mScriptCloseCode == CLOSE_GOING_AWAY"
" (" "websocket closed while connecting w/o failing?" ")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 467); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(NS_FAILED_impl(aReason)), 0))) || aChannel->mScriptCloseCode == CLOSE_GOING_AWAY"
") (" "websocket closed while connecting w/o failing?" ")");
do { MOZ_CrashSequence(__null, 467); __attribute__((nomerge)
) ::abort(); } while (false); } } while (false)
467 "websocket closed while connecting w/o failing?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(((bool)(__builtin_expect(!!(NS_FAILED_impl(aReason))
, 0))) || aChannel->mScriptCloseCode == CLOSE_GOING_AWAY)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(((bool)(__builtin_expect(!!(NS_FAILED_impl(aReason))
, 0))) || aChannel->mScriptCloseCode == CLOSE_GOING_AWAY))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("((bool)(__builtin_expect(!!(NS_FAILED_impl(aReason)), 0))) || aChannel->mScriptCloseCode == CLOSE_GOING_AWAY"
" (" "websocket closed while connecting w/o failing?" ")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 467); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(NS_FAILED_impl(aReason)), 0))) || aChannel->mScriptCloseCode == CLOSE_GOING_AWAY"
") (" "websocket closed while connecting w/o failing?" ")");
do { MOZ_CrashSequence(__null, 467); __attribute__((nomerge)
) ::abort(); } while (false); } } while (false)
;
468 }
469#endif
470 (void)aReason;
471
472 sManager->RemoveFromQueue(aChannel);
473
474 bool wasNotQueued = (aChannel->mConnecting != CONNECTING_QUEUED);
475 LOG(("Websocket: changing state to NOT_CONNECTING"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "Websocket: changing state to NOT_CONNECTING"
); } } while (0)
;
476 aChannel->mConnecting = NOT_CONNECTING;
477 if (wasNotQueued) {
478 sManager->ConnectNext(aChannel->mAddress, aChannel->mOriginSuffix);
479 }
480 }
481
482 static void IncrementSessionCount() {
483 StaticMutexAutoLock lock(sLock);
484 if (!sManager) {
485 return;
486 }
487 sManager->mSessionCount++;
488 }
489
490 static void DecrementSessionCount() {
491 StaticMutexAutoLock lock(sLock);
492 if (!sManager) {
493 return;
494 }
495 sManager->mSessionCount--;
496 }
497
498 static void GetSessionCount(int32_t& aSessionCount) {
499 StaticMutexAutoLock lock(sLock);
500 if (!sManager) {
501 return;
502 }
503 aSessionCount = sManager->mSessionCount;
504 }
505
506 private:
507 nsWSAdmissionManager() : mSessionCount(0) {
508 MOZ_COUNT_CTOR(nsWSAdmissionManager)do { static_assert(std::is_class_v<nsWSAdmissionManager>
, "Token '" "nsWSAdmissionManager" "' is not a class type.");
static_assert(!std::is_base_of_v<nsISupports, nsWSAdmissionManager
>, "nsISupports classes don't need to call MOZ_COUNT_CTOR or "
"MOZ_COUNT_DTOR");; NS_LogCtor((void*)this, "nsWSAdmissionManager"
, sizeof(*this)); } while (0)
;
509 }
510
511 ~nsWSAdmissionManager() { MOZ_COUNT_DTOR(nsWSAdmissionManager)do { static_assert(std::is_class_v<nsWSAdmissionManager>
, "Token '" "nsWSAdmissionManager" "' is not a class type.");
static_assert(!std::is_base_of_v<nsISupports, nsWSAdmissionManager
>, "nsISupports classes don't need to call MOZ_COUNT_CTOR or "
"MOZ_COUNT_DTOR");; NS_LogDtor((void*)this, "nsWSAdmissionManager"
, sizeof(*this)); } while (0)
; }
512
513 class nsOpenConn {
514 public:
515 nsOpenConn(nsCString& addr, nsCString& originSuffix, bool failed,
516 WebSocketChannel* channel)
517 : mAddress(addr),
518 mOriginSuffix(originSuffix),
519 mFailed(failed),
520 mChannel(channel) {
521 MOZ_COUNT_CTOR(nsOpenConn)do { static_assert(std::is_class_v<nsOpenConn>, "Token '"
"nsOpenConn" "' is not a class type."); static_assert(!std::
is_base_of_v<nsISupports, nsOpenConn>, "nsISupports classes don't need to call MOZ_COUNT_CTOR or "
"MOZ_COUNT_DTOR");; NS_LogCtor((void*)this, "nsOpenConn", sizeof
(*this)); } while (0)
;
522 }
523 MOZ_COUNTED_DTOR(nsOpenConn)~nsOpenConn() { do { static_assert(std::is_class_v<nsOpenConn
>, "Token '" "nsOpenConn" "' is not a class type."); static_assert
(!std::is_base_of_v<nsISupports, nsOpenConn>, "nsISupports classes don't need to call MOZ_COUNT_CTOR or "
"MOZ_COUNT_DTOR");; NS_LogDtor((void*)this, "nsOpenConn", sizeof
(*this)); } while (0); }
524
525 nsCString mAddress;
526 nsCString mOriginSuffix;
527 bool mFailed = false;
528 RefPtr<WebSocketChannel> mChannel;
529 };
530
531 void ConnectNext(nsCString& hostName, nsCString& originSuffix) {
532 MOZ_ASSERT(NS_IsMainThread(), "not main thread")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
" (" "not main thread" ")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 532); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
") (" "not main thread" ")"); do { MOZ_CrashSequence(__null,
532); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false)
;
533
534 int32_t index = IndexOf(hostName, originSuffix);
535 if (index >= 0) {
536 WebSocketChannel* chan = mQueue[index]->mChannel;
537
538 MOZ_ASSERT(chan->mConnecting == CONNECTING_QUEUED,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(chan->mConnecting == CONNECTING_QUEUED)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(chan->mConnecting == CONNECTING_QUEUED))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("chan->mConnecting == CONNECTING_QUEUED"
" (" "transaction not queued but in queue" ")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 539); AnnotateMozCrashReason("MOZ_ASSERT" "(" "chan->mConnecting == CONNECTING_QUEUED"
") (" "transaction not queued but in queue" ")"); do { MOZ_CrashSequence
(__null, 539); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
539 "transaction not queued but in queue")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(chan->mConnecting == CONNECTING_QUEUED)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(chan->mConnecting == CONNECTING_QUEUED))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("chan->mConnecting == CONNECTING_QUEUED"
" (" "transaction not queued but in queue" ")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 539); AnnotateMozCrashReason("MOZ_ASSERT" "(" "chan->mConnecting == CONNECTING_QUEUED"
") (" "transaction not queued but in queue" ")"); do { MOZ_CrashSequence
(__null, 539); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
540 LOG(("WebSocket: ConnectNext: found channel [this=%p] in queue", chan))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocket: ConnectNext: found channel [this=%p] in queue"
, chan); } } while (0)
;
541
542 mFailures.DelayOrBegin(chan);
543 }
544 }
545
546 void RemoveFromQueue(WebSocketChannel* aChannel) {
547 LOG(("Websocket: RemoveFromQueue: [this=%p]", aChannel))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "Websocket: RemoveFromQueue: [this=%p]"
, aChannel); } } while (0)
;
548 int32_t index = IndexOf(aChannel);
549 MOZ_ASSERT(index >= 0, "connection to remove not in queue")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(index >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(index >= 0))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("index >= 0" " ("
"connection to remove not in queue" ")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 549); AnnotateMozCrashReason("MOZ_ASSERT" "(" "index >= 0"
") (" "connection to remove not in queue" ")"); do { MOZ_CrashSequence
(__null, 549); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
550 if (index >= 0) {
551 mQueue.RemoveElementAt(index);
552 }
553 }
554
555 int32_t IndexOf(nsCString& aAddress, nsCString& aOriginSuffix) {
556 for (uint32_t i = 0; i < mQueue.Length(); i++) {
557 if (aAddress == mQueue[i]->mAddress &&
558 aOriginSuffix == mQueue[i]->mOriginSuffix) {
559 return i;
560 }
561 }
562 return -1;
563 }
564
565 int32_t IndexOf(WebSocketChannel* aChannel) {
566 for (uint32_t i = 0; i < mQueue.Length(); i++) {
567 if (aChannel == mQueue[i]->mChannel) {
568 return i;
569 }
570 }
571 return -1;
572 }
573
574 // Returns the index of the first entry that failed, or else the last entry if
575 // none found
576 uint32_t IndexOfFirstFailure() {
577 for (uint32_t i = 0; i < mQueue.Length(); i++) {
578 if (mQueue[i]->mFailed) return i;
579 }
580 return mQueue.Length();
581 }
582
583 // SessionCount might be decremented from the main or the socket
584 // thread, so manage it with atomic counters
585 Atomic<int32_t> mSessionCount;
586
587 // Queue for websockets that have not completed connecting yet.
588 // The first nsOpenConn with a given address will be either be
589 // CONNECTING_IN_PROGRESS or CONNECTING_DELAYED. Later ones with the same
590 // hostname must be CONNECTING_QUEUED.
591 //
592 // We could hash hostnames instead of using a single big vector here, but the
593 // dataset is expected to be small.
594 nsTArray<UniquePtr<nsOpenConn>> mQueue;
595
596 FailDelayManager mFailures;
597
598 static nsWSAdmissionManager* sManager MOZ_GUARDED_BY(sLock)__attribute__((guarded_by(sLock)));
599 static StaticMutex sLock;
600};
601
602nsWSAdmissionManager* nsWSAdmissionManager::sManager;
603StaticMutex nsWSAdmissionManager::sLock;
604
605//-----------------------------------------------------------------------------
606// CallOnMessageAvailable
607//-----------------------------------------------------------------------------
608
609class CallOnMessageAvailable final : public Runnable {
610 public:
611 CallOnMessageAvailable(
612 WebSocketChannel* aChannel,
613 RefPtr<BaseWebSocketChannel::ListenerAndContextContainer>&& aListenerMT,
614 nsACString& aData, int32_t aLen)
615 : Runnable("net::CallOnMessageAvailable"),
616 mChannel(aChannel),
617 mListenerMT(std::move(aListenerMT)),
618 mData(aData),
619 mLen(aLen) {}
620
621 NS_IMETHODvirtual nsresult Run() override {
622 MOZ_ASSERT(mChannel->IsOnTargetThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mChannel->IsOnTargetThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mChannel->IsOnTargetThread
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mChannel->IsOnTargetThread()", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 622); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mChannel->IsOnTargetThread()"
")"); do { MOZ_CrashSequence(__null, 622); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
623
624 if (mListenerMT) {
625 nsresult rv;
626 if (mLen < 0) {
627 rv = mListenerMT->mListener->OnMessageAvailable(mListenerMT->mContext,
628 mData);
629 } else {
630 rv = mListenerMT->mListener->OnBinaryMessageAvailable(
631 mListenerMT->mContext, mData);
632 }
633 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
634 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "OnMessageAvailable or OnBinaryMessageAvailable "
"failed with 0x%08" "x", static_cast<uint32_t>(rv)); }
} while (0)
635 ("OnMessageAvailable or OnBinaryMessageAvailable "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "OnMessageAvailable or OnBinaryMessageAvailable "
"failed with 0x%08" "x", static_cast<uint32_t>(rv)); }
} while (0)
636 "failed with 0x%08" PRIx32,do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "OnMessageAvailable or OnBinaryMessageAvailable "
"failed with 0x%08" "x", static_cast<uint32_t>(rv)); }
} while (0)
637 static_cast<uint32_t>(rv)))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "OnMessageAvailable or OnBinaryMessageAvailable "
"failed with 0x%08" "x", static_cast<uint32_t>(rv)); }
} while (0)
;
638 }
639 }
640
641 return NS_OK;
642 }
643
644 private:
645 ~CallOnMessageAvailable() = default;
646
647 RefPtr<WebSocketChannel> mChannel;
648 RefPtr<BaseWebSocketChannel::ListenerAndContextContainer> mListenerMT;
649 nsCString mData;
650 int32_t mLen;
651};
652
653//-----------------------------------------------------------------------------
654// CallOnStop
655//-----------------------------------------------------------------------------
656
657class CallOnStop final : public Runnable {
658 public:
659 CallOnStop(
660 WebSocketChannel* aChannel,
661 RefPtr<BaseWebSocketChannel::ListenerAndContextContainer>&& aListenerMT,
662 nsresult aReason)
663 : Runnable("net::CallOnStop"),
664 mChannel(aChannel),
665 mListenerMT(std::move(aListenerMT)),
666 mReason(aReason) {}
667
668 NS_IMETHODvirtual nsresult Run() override {
669 MOZ_ASSERT(mChannel->IsOnTargetThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mChannel->IsOnTargetThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mChannel->IsOnTargetThread
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mChannel->IsOnTargetThread()", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 669); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mChannel->IsOnTargetThread()"
")"); do { MOZ_CrashSequence(__null, 669); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
670
671 if (mListenerMT) {
672 nsresult rv =
673 mListenerMT->mListener->OnStop(mListenerMT->mContext, mReason);
674 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
675 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::CallOnStop "
"OnStop failed (%08" "x" ")\n", static_cast<uint32_t>(
rv)); } } while (0)
676 ("WebSocketChannel::CallOnStop "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::CallOnStop "
"OnStop failed (%08" "x" ")\n", static_cast<uint32_t>(
rv)); } } while (0)
677 "OnStop failed (%08" PRIx32 ")\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::CallOnStop "
"OnStop failed (%08" "x" ")\n", static_cast<uint32_t>(
rv)); } } while (0)
678 static_cast<uint32_t>(rv)))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::CallOnStop "
"OnStop failed (%08" "x" ")\n", static_cast<uint32_t>(
rv)); } } while (0)
;
679 }
680 }
681
682 return NS_OK;
683 }
684
685 private:
686 ~CallOnStop() = default;
687
688 RefPtr<WebSocketChannel> mChannel;
689 RefPtr<BaseWebSocketChannel::ListenerAndContextContainer> mListenerMT;
690 nsresult mReason;
691};
692
693//-----------------------------------------------------------------------------
694// CallOnServerClose
695//-----------------------------------------------------------------------------
696
697class CallOnServerClose final : public Runnable {
698 public:
699 CallOnServerClose(
700 WebSocketChannel* aChannel,
701 RefPtr<BaseWebSocketChannel::ListenerAndContextContainer>&& aListenerMT,
702 uint16_t aCode, nsACString& aReason)
703 : Runnable("net::CallOnServerClose"),
704 mChannel(aChannel),
705 mListenerMT(std::move(aListenerMT)),
706 mCode(aCode),
707 mReason(aReason) {}
708
709 NS_IMETHODvirtual nsresult Run() override {
710 MOZ_ASSERT(mChannel->IsOnTargetThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mChannel->IsOnTargetThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mChannel->IsOnTargetThread
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mChannel->IsOnTargetThread()", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 710); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mChannel->IsOnTargetThread()"
")"); do { MOZ_CrashSequence(__null, 710); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
711
712 if (mListenerMT) {
713 nsresult rv = mListenerMT->mListener->OnServerClose(mListenerMT->mContext,
714 mCode, mReason);
715 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
716 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::CallOnServerClose "
"OnServerClose failed (%08" "x" ")\n", static_cast<uint32_t
>(rv)); } } while (0)
717 ("WebSocketChannel::CallOnServerClose "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::CallOnServerClose "
"OnServerClose failed (%08" "x" ")\n", static_cast<uint32_t
>(rv)); } } while (0)
718 "OnServerClose failed (%08" PRIx32 ")\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::CallOnServerClose "
"OnServerClose failed (%08" "x" ")\n", static_cast<uint32_t
>(rv)); } } while (0)
719 static_cast<uint32_t>(rv)))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::CallOnServerClose "
"OnServerClose failed (%08" "x" ")\n", static_cast<uint32_t
>(rv)); } } while (0)
;
720 }
721 }
722 return NS_OK;
723 }
724
725 private:
726 ~CallOnServerClose() = default;
727
728 RefPtr<WebSocketChannel> mChannel;
729 RefPtr<BaseWebSocketChannel::ListenerAndContextContainer> mListenerMT;
730 uint16_t mCode;
731 nsCString mReason;
732};
733
734//-----------------------------------------------------------------------------
735// CallAcknowledge
736//-----------------------------------------------------------------------------
737
738class CallAcknowledge final : public Runnable {
739 public:
740 CallAcknowledge(
741 WebSocketChannel* aChannel,
742 RefPtr<BaseWebSocketChannel::ListenerAndContextContainer>&& aListenerMT,
743 uint32_t aSize)
744 : Runnable("net::CallAcknowledge"),
745 mChannel(aChannel),
746 mListenerMT(std::move(aListenerMT)),
747 mSize(aSize) {}
748
749 NS_IMETHODvirtual nsresult Run() override {
750 MOZ_ASSERT(mChannel->IsOnTargetThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mChannel->IsOnTargetThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mChannel->IsOnTargetThread
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mChannel->IsOnTargetThread()", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 750); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mChannel->IsOnTargetThread()"
")"); do { MOZ_CrashSequence(__null, 750); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
751
752 LOG(("WebSocketChannel::CallAcknowledge: Size %u\n", mSize))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::CallAcknowledge: Size %u\n"
, mSize); } } while (0)
;
753 if (mListenerMT) {
754 nsresult rv =
755 mListenerMT->mListener->OnAcknowledge(mListenerMT->mContext, mSize);
756 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
757 LOG(("WebSocketChannel::CallAcknowledge: Acknowledge failed (%08" PRIx32do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::CallAcknowledge: Acknowledge failed (%08"
"x" ")\n", static_cast<uint32_t>(rv)); } } while (0)
758 ")\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::CallAcknowledge: Acknowledge failed (%08"
"x" ")\n", static_cast<uint32_t>(rv)); } } while (0)
759 static_cast<uint32_t>(rv)))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::CallAcknowledge: Acknowledge failed (%08"
"x" ")\n", static_cast<uint32_t>(rv)); } } while (0)
;
760 }
761 }
762 return NS_OK;
763 }
764
765 private:
766 ~CallAcknowledge() = default;
767
768 RefPtr<WebSocketChannel> mChannel;
769 RefPtr<BaseWebSocketChannel::ListenerAndContextContainer> mListenerMT;
770 uint32_t mSize;
771};
772
773//-----------------------------------------------------------------------------
774// CallOnTransportAvailable
775//-----------------------------------------------------------------------------
776
777class CallOnTransportAvailable final : public Runnable {
778 public:
779 CallOnTransportAvailable(WebSocketChannel* aChannel,
780 nsISocketTransport* aTransport,
781 nsIAsyncInputStream* aSocketIn,
782 nsIAsyncOutputStream* aSocketOut)
783 : Runnable("net::CallOnTransportAvailble"),
784 mChannel(aChannel),
785 mTransport(aTransport),
786 mSocketIn(aSocketIn),
787 mSocketOut(aSocketOut) {}
788
789 NS_IMETHODvirtual nsresult Run() override {
790 LOG(("WebSocketChannel::CallOnTransportAvailable %p\n", this))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::CallOnTransportAvailable %p\n"
, this); } } while (0)
;
791 return mChannel->OnTransportAvailable(mTransport, mSocketIn, mSocketOut);
792 }
793
794 private:
795 ~CallOnTransportAvailable() = default;
796
797 RefPtr<WebSocketChannel> mChannel;
798 nsCOMPtr<nsISocketTransport> mTransport;
799 nsCOMPtr<nsIAsyncInputStream> mSocketIn;
800 nsCOMPtr<nsIAsyncOutputStream> mSocketOut;
801};
802
803//-----------------------------------------------------------------------------
804// PMCECompression
805//-----------------------------------------------------------------------------
806
807class PMCECompression {
808 public:
809 PMCECompression(bool aNoContextTakeover, int32_t aLocalMaxWindowBits,
810 int32_t aRemoteMaxWindowBits)
811 : mActive(false),
812 mNoContextTakeover(aNoContextTakeover),
813 mResetDeflater(false),
814 mMessageDeflated(false) {
815 this->mDeflater.next_in = nullptr;
816 this->mDeflater.avail_in = 0;
817 this->mDeflater.total_in = 0;
818 this->mDeflater.next_out = nullptr;
819 this->mDeflater.avail_out = 0;
820 this->mDeflater.total_out = 0;
821 this->mDeflater.msg = nullptr;
822 this->mDeflater.state = nullptr;
823 this->mDeflater.data_type = 0;
824 this->mDeflater.adler = 0;
825 this->mDeflater.reserved = 0;
826 this->mInflater.next_in = nullptr;
827 this->mInflater.avail_in = 0;
828 this->mInflater.total_in = 0;
829 this->mInflater.next_out = nullptr;
830 this->mInflater.avail_out = 0;
831 this->mInflater.total_out = 0;
832 this->mInflater.msg = nullptr;
833 this->mInflater.state = nullptr;
834 this->mInflater.data_type = 0;
835 this->mInflater.adler = 0;
836 this->mInflater.reserved = 0;
837 MOZ_COUNT_CTOR(PMCECompression)do { static_assert(std::is_class_v<PMCECompression>, "Token '"
"PMCECompression" "' is not a class type."); static_assert(!
std::is_base_of_v<nsISupports, PMCECompression>, "nsISupports classes don't need to call MOZ_COUNT_CTOR or "
"MOZ_COUNT_DTOR");; NS_LogCtor((void*)this, "PMCECompression"
, sizeof(*this)); } while (0)
;
838
839 mDeflater.zalloc = mInflater.zalloc = Z_NULL0;
840 mDeflater.zfree = mInflater.zfree = Z_NULL0;
841 mDeflater.opaque = mInflater.opaque = Z_NULL0;
842
843 if (deflateInit2(&mDeflater, Z_DEFAULT_COMPRESSION, Z_DEFLATED,MOZ_Z_deflateInit2_((&mDeflater),((-1)),(8),(-aLocalMaxWindowBits
),(8), (0), "1.3.2", (int)sizeof(z_stream))
844 -aLocalMaxWindowBits, 8, Z_DEFAULT_STRATEGY)MOZ_Z_deflateInit2_((&mDeflater),((-1)),(8),(-aLocalMaxWindowBits
),(8), (0), "1.3.2", (int)sizeof(z_stream))
== Z_OK0) {
845 if (inflateInit2(&mInflater, -aRemoteMaxWindowBits)MOZ_Z_inflateInit2_((&mInflater), (-aRemoteMaxWindowBits)
, "1.3.2", (int)sizeof(z_stream))
== Z_OK0) {
846 mActive = true;
847 } else {
848 deflateEndMOZ_Z_deflateEnd(&mDeflater);
849 }
850 }
851 }
852
853 ~PMCECompression() {
854 MOZ_COUNT_DTOR(PMCECompression)do { static_assert(std::is_class_v<PMCECompression>, "Token '"
"PMCECompression" "' is not a class type."); static_assert(!
std::is_base_of_v<nsISupports, PMCECompression>, "nsISupports classes don't need to call MOZ_COUNT_CTOR or "
"MOZ_COUNT_DTOR");; NS_LogDtor((void*)this, "PMCECompression"
, sizeof(*this)); } while (0)
;
855
856 if (mActive) {
857 inflateEndMOZ_Z_inflateEnd(&mInflater);
858 deflateEndMOZ_Z_deflateEnd(&mDeflater);
859 }
860 }
861
862 bool Active() { return mActive; }
863
864 void SetMessageDeflated() {
865 MOZ_ASSERT(!mMessageDeflated)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mMessageDeflated)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mMessageDeflated))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("!mMessageDeflated"
, "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 865); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mMessageDeflated"
")"); do { MOZ_CrashSequence(__null, 865); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
866 mMessageDeflated = true;
867 }
868 bool IsMessageDeflated() { return mMessageDeflated; }
869
870 bool UsingContextTakeover() { return !mNoContextTakeover; }
871
872 nsresult Deflate(uint8_t* data, uint32_t dataLen, nsACString& _retval) {
873 if (mResetDeflater || mNoContextTakeover) {
874 if (deflateResetMOZ_Z_deflateReset(&mDeflater) != Z_OK0) {
875 return NS_ERROR_UNEXPECTED;
876 }
877 mResetDeflater = false;
878 }
879
880 mDeflater.avail_out = kBufferLen;
881 mDeflater.next_out = mBuffer;
882 mDeflater.avail_in = dataLen;
883 mDeflater.next_in = data;
884
885 while (true) {
886 int zerr = deflateMOZ_Z_deflate(&mDeflater, Z_SYNC_FLUSH2);
887
888 if (zerr != Z_OK0) {
889 mResetDeflater = true;
890 return NS_ERROR_UNEXPECTED;
891 }
892
893 uint32_t deflated = kBufferLen - mDeflater.avail_out;
894 if (deflated > 0) {
895 _retval.Append(reinterpret_cast<char*>(mBuffer), deflated);
896 }
897
898 mDeflater.avail_out = kBufferLen;
899 mDeflater.next_out = mBuffer;
900
901 if (mDeflater.avail_in > 0) {
902 continue; // There is still some data to deflate
903 }
904
905 if (deflated == kBufferLen) {
906 continue; // There was not enough space in the buffer
907 }
908
909 break;
910 }
911
912 if (_retval.Length() < 4) {
913 MOZ_ASSERT(false, "Expected trailing not found in deflated data!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "Expected trailing not found in deflated data!"
")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 913); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"Expected trailing not found in deflated data!" ")"); do { MOZ_CrashSequence
(__null, 913); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
914 mResetDeflater = true;
915 return NS_ERROR_UNEXPECTED;
916 }
917
918 _retval.Truncate(_retval.Length() - 4);
919
920 return NS_OK;
921 }
922
923 nsresult Inflate(uint8_t* data, uint32_t dataLen, nsACString& _retval) {
924 mMessageDeflated = false;
925
926 Bytef trailingData[] = {0x00, 0x00, 0xFF, 0xFF};
927 bool trailingDataUsed = false;
928
929 mInflater.avail_out = kBufferLen;
930 mInflater.next_out = mBuffer;
931 mInflater.avail_in = dataLen;
932 mInflater.next_in = data;
933
934 while (true) {
935 int zerr = inflateMOZ_Z_inflate(&mInflater, Z_NO_FLUSH0);
936
937 if (zerr == Z_STREAM_END1) {
938 Bytef* saveNextIn = mInflater.next_in;
939 uint32_t saveAvailIn = mInflater.avail_in;
940 Bytef* saveNextOut = mInflater.next_out;
941 uint32_t saveAvailOut = mInflater.avail_out;
942
943 inflateResetMOZ_Z_inflateReset(&mInflater);
944
945 mInflater.next_in = saveNextIn;
946 mInflater.avail_in = saveAvailIn;
947 mInflater.next_out = saveNextOut;
948 mInflater.avail_out = saveAvailOut;
949 } else if (zerr != Z_OK0 && zerr != Z_BUF_ERROR(-5)) {
950 return NS_ERROR_INVALID_CONTENT_ENCODING;
951 }
952
953 uint32_t inflated = kBufferLen - mInflater.avail_out;
954 if (inflated > 0) {
955 if (!_retval.Append(reinterpret_cast<char*>(mBuffer), inflated,
956 fallible)) {
957 return NS_ERROR_OUT_OF_MEMORY;
958 }
959 }
960
961 mInflater.avail_out = kBufferLen;
962 mInflater.next_out = mBuffer;
963
964 if (mInflater.avail_in > 0) {
965 continue; // There is still some data to inflate
966 }
967
968 if (inflated == kBufferLen) {
969 continue; // There was not enough space in the buffer
970 }
971
972 if (!trailingDataUsed) {
973 trailingDataUsed = true;
974 mInflater.avail_in = sizeof(trailingData);
975 mInflater.next_in = trailingData;
976 continue;
977 }
978
979 return NS_OK;
980 }
981 }
982
983 private:
984 bool mActive;
985 bool mNoContextTakeover;
986 bool mResetDeflater;
987 bool mMessageDeflated;
988 z_stream mDeflater{};
989 z_stream mInflater{};
990 const static uint32_t kBufferLen = 4096;
991 uint8_t mBuffer[kBufferLen]{0};
992};
993
994//-----------------------------------------------------------------------------
995// OutboundMessage
996//-----------------------------------------------------------------------------
997
998enum WsMsgType {
999 kMsgTypeString = 0,
1000 kMsgTypeBinaryString,
1001 kMsgTypeStream,
1002 kMsgTypePing,
1003 kMsgTypePong,
1004 kMsgTypeFin
1005};
1006
1007static const char* msgNames[] = {"text", "binaryString", "binaryStream",
1008 "ping", "pong", "close"};
1009
1010class OutboundMessage {
1011 public:
1012 OutboundMessage(WsMsgType type, const nsACString& str)
1013 : mMsg(mozilla::AsVariant(pString(str))),
1014 mMsgType(type),
1015 mDeflated(false) {
1016 MOZ_COUNT_CTOR(OutboundMessage)do { static_assert(std::is_class_v<OutboundMessage>, "Token '"
"OutboundMessage" "' is not a class type."); static_assert(!
std::is_base_of_v<nsISupports, OutboundMessage>, "nsISupports classes don't need to call MOZ_COUNT_CTOR or "
"MOZ_COUNT_DTOR");; NS_LogCtor((void*)this, "OutboundMessage"
, sizeof(*this)); } while (0)
;
1017 }
1018
1019 OutboundMessage(nsIInputStream* stream, uint32_t length)
1020 : mMsg(mozilla::AsVariant(StreamWithLength(stream, length))),
1021 mMsgType(kMsgTypeStream),
1022 mDeflated(false) {
1023 MOZ_COUNT_CTOR(OutboundMessage)do { static_assert(std::is_class_v<OutboundMessage>, "Token '"
"OutboundMessage" "' is not a class type."); static_assert(!
std::is_base_of_v<nsISupports, OutboundMessage>, "nsISupports classes don't need to call MOZ_COUNT_CTOR or "
"MOZ_COUNT_DTOR");; NS_LogCtor((void*)this, "OutboundMessage"
, sizeof(*this)); } while (0)
;
1024 }
1025
1026 ~OutboundMessage() {
1027 MOZ_COUNT_DTOR(OutboundMessage)do { static_assert(std::is_class_v<OutboundMessage>, "Token '"
"OutboundMessage" "' is not a class type."); static_assert(!
std::is_base_of_v<nsISupports, OutboundMessage>, "nsISupports classes don't need to call MOZ_COUNT_CTOR or "
"MOZ_COUNT_DTOR");; NS_LogDtor((void*)this, "OutboundMessage"
, sizeof(*this)); } while (0)
;
1028 switch (mMsgType) {
1029 case kMsgTypeString:
1030 case kMsgTypeBinaryString:
1031 case kMsgTypePing:
1032 case kMsgTypePong:
1033 break;
1034 case kMsgTypeStream:
1035 // for now this only gets hit if msg deleted w/o being sent
1036 if (mMsg.as<StreamWithLength>().mStream) {
1037 mMsg.as<StreamWithLength>().mStream->Close();
1038 }
1039 break;
1040 case kMsgTypeFin:
1041 break; // do-nothing: avoid compiler warning
1042 }
1043 }
1044
1045 WsMsgType GetMsgType() const { return mMsgType; }
1046 int32_t Length() {
1047 if (mMsg.is<pString>()) {
1048 return mMsg.as<pString>().mValue.Length();
1049 }
1050
1051 return mMsg.as<StreamWithLength>().mLength;
1052 }
1053 int32_t OrigLength() {
1054 if (mMsg.is<pString>()) {
1055 pString& ref = mMsg.as<pString>();
1056 return mDeflated ? ref.mOrigValue.Length() : ref.mValue.Length();
1057 }
1058
1059 return mMsg.as<StreamWithLength>().mLength;
1060 }
1061
1062 uint8_t* BeginWriting() {
1063 MOZ_ASSERT(mMsgType != kMsgTypeStream,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mMsgType != kMsgTypeStream)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mMsgType != kMsgTypeStream))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("mMsgType != kMsgTypeStream"
" (" "Stream should have been converted to string by now" ")"
, "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 1064); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mMsgType != kMsgTypeStream"
") (" "Stream should have been converted to string by now" ")"
); do { MOZ_CrashSequence(__null, 1064); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1064 "Stream should have been converted to string by now")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mMsgType != kMsgTypeStream)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mMsgType != kMsgTypeStream))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("mMsgType != kMsgTypeStream"
" (" "Stream should have been converted to string by now" ")"
, "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 1064); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mMsgType != kMsgTypeStream"
") (" "Stream should have been converted to string by now" ")"
); do { MOZ_CrashSequence(__null, 1064); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1065 if (!mMsg.as<pString>().mValue.IsVoid()) {
1066 return (uint8_t*)mMsg.as<pString>().mValue.BeginWriting();
1067 }
1068 return nullptr;
1069 }
1070
1071 uint8_t* BeginReading() {
1072 MOZ_ASSERT(mMsgType != kMsgTypeStream,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mMsgType != kMsgTypeStream)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mMsgType != kMsgTypeStream))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("mMsgType != kMsgTypeStream"
" (" "Stream should have been converted to string by now" ")"
, "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 1073); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mMsgType != kMsgTypeStream"
") (" "Stream should have been converted to string by now" ")"
); do { MOZ_CrashSequence(__null, 1073); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1073 "Stream should have been converted to string by now")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mMsgType != kMsgTypeStream)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mMsgType != kMsgTypeStream))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("mMsgType != kMsgTypeStream"
" (" "Stream should have been converted to string by now" ")"
, "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 1073); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mMsgType != kMsgTypeStream"
") (" "Stream should have been converted to string by now" ")"
); do { MOZ_CrashSequence(__null, 1073); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1074 if (!mMsg.as<pString>().mValue.IsVoid()) {
1075 return (uint8_t*)mMsg.as<pString>().mValue.BeginReading();
1076 }
1077 return nullptr;
1078 }
1079
1080 uint8_t* BeginOrigReading() {
1081 MOZ_ASSERT(mMsgType != kMsgTypeStream,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mMsgType != kMsgTypeStream)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mMsgType != kMsgTypeStream))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("mMsgType != kMsgTypeStream"
" (" "Stream should have been converted to string by now" ")"
, "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 1082); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mMsgType != kMsgTypeStream"
") (" "Stream should have been converted to string by now" ")"
); do { MOZ_CrashSequence(__null, 1082); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1082 "Stream should have been converted to string by now")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mMsgType != kMsgTypeStream)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mMsgType != kMsgTypeStream))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("mMsgType != kMsgTypeStream"
" (" "Stream should have been converted to string by now" ")"
, "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 1082); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mMsgType != kMsgTypeStream"
") (" "Stream should have been converted to string by now" ")"
); do { MOZ_CrashSequence(__null, 1082); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1083 if (!mDeflated) return BeginReading();
1084 if (!mMsg.as<pString>().mOrigValue.IsVoid()) {
1085 return (uint8_t*)mMsg.as<pString>().mOrigValue.BeginReading();
1086 }
1087 return nullptr;
1088 }
1089
1090 nsresult ConvertStreamToString() {
1091 MOZ_ASSERT(mMsgType == kMsgTypeStream, "Not a stream!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mMsgType == kMsgTypeStream)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mMsgType == kMsgTypeStream))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("mMsgType == kMsgTypeStream"
" (" "Not a stream!" ")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 1091); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mMsgType == kMsgTypeStream"
") (" "Not a stream!" ")"); do { MOZ_CrashSequence(__null, 1091
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
;
1092 nsAutoCString temp;
1093 {
1094 StreamWithLength& ref = mMsg.as<StreamWithLength>();
1095 nsresult rv = NS_ReadInputStreamToString(ref.mStream, temp, ref.mLength);
1096
1097 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 1097); return rv; } } while (false)
;
1098 if (temp.Length() != ref.mLength) {
1099 return NS_ERROR_UNEXPECTED;
1100 }
1101 ref.mStream->Close();
1102 }
1103
1104 mMsg = mozilla::AsVariant(pString(temp));
1105 mMsgType = kMsgTypeBinaryString;
1106
1107 return NS_OK;
1108 }
1109
1110 bool DeflatePayload(PMCECompression* aCompressor) {
1111 MOZ_ASSERT(mMsgType != kMsgTypeStream,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mMsgType != kMsgTypeStream)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mMsgType != kMsgTypeStream))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("mMsgType != kMsgTypeStream"
" (" "Stream should have been converted to string by now" ")"
, "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 1112); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mMsgType != kMsgTypeStream"
") (" "Stream should have been converted to string by now" ")"
); do { MOZ_CrashSequence(__null, 1112); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1112 "Stream should have been converted to string by now")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mMsgType != kMsgTypeStream)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mMsgType != kMsgTypeStream))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("mMsgType != kMsgTypeStream"
" (" "Stream should have been converted to string by now" ")"
, "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 1112); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mMsgType != kMsgTypeStream"
") (" "Stream should have been converted to string by now" ")"
); do { MOZ_CrashSequence(__null, 1112); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1113 MOZ_ASSERT(!mDeflated)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mDeflated)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mDeflated))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("!mDeflated", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 1113); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mDeflated"
")"); do { MOZ_CrashSequence(__null, 1113); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1114
1115 nsresult rv;
1116 pString& ref = mMsg.as<pString>();
1117 if (ref.mValue.Length() == 0) {
1118 // Empty message
1119 return false;
1120 }
1121
1122 nsAutoCString temp;
1123 rv = aCompressor->Deflate(BeginReading(), ref.mValue.Length(), temp);
1124 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
1125 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OutboundMessage: Deflating payload failed "
"[rv=0x%08" "x" "]\n", static_cast<uint32_t>(rv)); } }
while (0)
1126 ("WebSocketChannel::OutboundMessage: Deflating payload failed "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OutboundMessage: Deflating payload failed "
"[rv=0x%08" "x" "]\n", static_cast<uint32_t>(rv)); } }
while (0)
1127 "[rv=0x%08" PRIx32 "]\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OutboundMessage: Deflating payload failed "
"[rv=0x%08" "x" "]\n", static_cast<uint32_t>(rv)); } }
while (0)
1128 static_cast<uint32_t>(rv)))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OutboundMessage: Deflating payload failed "
"[rv=0x%08" "x" "]\n", static_cast<uint32_t>(rv)); } }
while (0)
;
1129 return false;
1130 }
1131
1132 if (!aCompressor->UsingContextTakeover() &&
1133 temp.Length() > ref.mValue.Length()) {
1134 // When "<local>_no_context_takeover" was negotiated, do not send deflated
1135 // payload if it's larger that the original one. OTOH, it makes sense
1136 // to send the larger deflated payload when the sliding window is not
1137 // reset between messages because if we would skip some deflated block
1138 // we would need to empty the sliding window which could affect the
1139 // compression of the subsequent messages.
1140 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OutboundMessage: Not deflating message since the "
"deflated payload is larger than the original one [deflated=%zd, "
"original=%zd]", temp.Length(), ref.mValue.Length()); } } while
(0)
1141 ("WebSocketChannel::OutboundMessage: Not deflating message since the "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OutboundMessage: Not deflating message since the "
"deflated payload is larger than the original one [deflated=%zd, "
"original=%zd]", temp.Length(), ref.mValue.Length()); } } while
(0)
1142 "deflated payload is larger than the original one [deflated=%zd, "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OutboundMessage: Not deflating message since the "
"deflated payload is larger than the original one [deflated=%zd, "
"original=%zd]", temp.Length(), ref.mValue.Length()); } } while
(0)
1143 "original=%zd]",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OutboundMessage: Not deflating message since the "
"deflated payload is larger than the original one [deflated=%zd, "
"original=%zd]", temp.Length(), ref.mValue.Length()); } } while
(0)
1144 temp.Length(), ref.mValue.Length()))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OutboundMessage: Not deflating message since the "
"deflated payload is larger than the original one [deflated=%zd, "
"original=%zd]", temp.Length(), ref.mValue.Length()); } } while
(0)
;
1145 return false;
1146 }
1147
1148 mDeflated = true;
1149 mMsg.as<pString>().mOrigValue = std::move(mMsg.as<pString>().mValue);
1150 mMsg.as<pString>().mValue = std::move(temp);
1151 return true;
1152 }
1153
1154 private:
1155 struct pString {
1156 nsCString mValue;
1157 nsCString mOrigValue;
1158 explicit pString(const nsACString& value)
1159 : mValue(value), mOrigValue(VoidCString()) {}
1160 };
1161 struct StreamWithLength {
1162 nsCOMPtr<nsIInputStream> mStream;
1163 uint32_t mLength;
1164 explicit StreamWithLength(nsIInputStream* stream, uint32_t Length)
1165 : mStream(stream), mLength(Length) {}
1166 };
1167 mozilla::Variant<pString, StreamWithLength> mMsg;
1168 WsMsgType mMsgType;
1169 bool mDeflated;
1170};
1171
1172//-----------------------------------------------------------------------------
1173// OutboundEnqueuer
1174//-----------------------------------------------------------------------------
1175
1176class OutboundEnqueuer final : public Runnable {
1177 public:
1178 OutboundEnqueuer(WebSocketChannel* aChannel, OutboundMessage* aMsg)
1179 : Runnable("OutboundEnquerer"), mChannel(aChannel), mMessage(aMsg) {}
1180
1181 NS_IMETHODvirtual nsresult Run() override {
1182 mChannel->EnqueueOutgoingMessage(mChannel->mOutgoingMessages, mMessage);
1183 return NS_OK;
1184 }
1185
1186 private:
1187 ~OutboundEnqueuer() = default;
1188
1189 RefPtr<WebSocketChannel> mChannel;
1190 OutboundMessage* mMessage;
1191};
1192
1193//-----------------------------------------------------------------------------
1194// WebSocketChannel
1195//-----------------------------------------------------------------------------
1196
1197WebSocketChannel::WebSocketChannel()
1198 : mPort(0),
1199 mCloseTimeout(20000),
1200 mOpenTimeout(20000),
1201 mConnecting(NOT_CONNECTING),
1202 mMaxConcurrentConnections(200),
1203 mInnerWindowID(0),
1204 mGotUpgradeOK(0),
1205 mRecvdHttpUpgradeTransport(0),
1206 mPingOutstanding(0),
1207 mReleaseOnTransmit(0),
1208 mDataStarted(false),
1209 mRequestedClose(false),
1210 mClientClosed(false),
1211 mServerClosed(false),
1212 mStopped(false),
1213 mCalledOnStop(false),
1214 mTCPClosed(false),
1215 mOpenedHttpChannel(false),
1216 mIncrementedSessionCount(false),
1217 mDecrementedSessionCount(false),
1218 mMaxMessageSize(INT32_MAX(2147483647)),
1219 mStopOnClose(NS_OK),
1220 mServerCloseCode(CLOSE_ABNORMAL),
1221 mScriptCloseCode(0),
1222 mFragmentOpcode(nsIWebSocketFrame::OPCODE_CONTINUATION),
1223 mFragmentAccumulator(0),
1224 mBuffered(0),
1225 mBufferSize(kIncomingBufferInitialSize),
1226 mCurrentOut(nullptr),
1227 mCurrentOutSent(0),
1228 mHdrOutToSend(0),
1229 mHdrOut(nullptr),
1230 mCompressorMutex("WebSocketChannel::mCompressorMutex"),
1231 mDynamicOutputSize(0),
1232 mDynamicOutput(nullptr),
1233 mPrivateBrowsing(false),
1234 mConnectionLogService(nullptr),
1235 mMutex("WebSocketChannel::mMutex") {
1236 MOZ_ASSERT(NS_IsMainThread(), "not main thread")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
" (" "not main thread" ")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 1236); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
") (" "not main thread" ")"); do { MOZ_CrashSequence(__null,
1236); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false)
;
1237
1238 LOG(("WebSocketChannel::WebSocketChannel() %p\n", this))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::WebSocketChannel() %p\n"
, this); } } while (0)
;
1239
1240 nsWSAdmissionManager::Init();
1241
1242 mFramePtr = mBuffer = static_cast<uint8_t*>(moz_xmalloc(mBufferSize));
1243
1244 nsresult rv;
1245 mConnectionLogService = mozilla::components::Dashboard::Service(&rv);
1246 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) LOG(("Failed to initiate dashboard service."))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "Failed to initiate dashboard service."
); } } while (0)
;
1247
1248 mService = WebSocketEventService::GetOrCreate();
1249}
1250
1251WebSocketChannel::~WebSocketChannel() {
1252 LOG(("WebSocketChannel::~WebSocketChannel() %p\n", this))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::~WebSocketChannel() %p\n"
, this); } } while (0)
;
1253
1254 if (mWasOpened) {
1255 MOZ_ASSERT(mCalledOnStop, "WebSocket was opened but OnStop was not called")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mCalledOnStop)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mCalledOnStop))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("mCalledOnStop" " ("
"WebSocket was opened but OnStop was not called" ")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 1255); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mCalledOnStop"
") (" "WebSocket was opened but OnStop was not called" ")");
do { MOZ_CrashSequence(__null, 1255); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1256 MOZ_ASSERT(mStopped, "WebSocket was opened but never stopped")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mStopped)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mStopped))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("mStopped" " (" "WebSocket was opened but never stopped"
")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 1256); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mStopped" ") ("
"WebSocket was opened but never stopped" ")"); do { MOZ_CrashSequence
(__null, 1256); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
1257 }
1258 MOZ_ASSERT(!mCancelable, "DNS/Proxy Request still alive at destruction")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mCancelable)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mCancelable))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("!mCancelable" " ("
"DNS/Proxy Request still alive at destruction" ")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 1258); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mCancelable"
") (" "DNS/Proxy Request still alive at destruction" ")"); do
{ MOZ_CrashSequence(__null, 1258); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
1259 MOZ_ASSERT(!mConnecting, "Should not be connecting in destructor")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mConnecting)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mConnecting))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("!mConnecting" " ("
"Should not be connecting in destructor" ")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 1259); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mConnecting"
") (" "Should not be connecting in destructor" ")"); do { MOZ_CrashSequence
(__null, 1259); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
1260
1261 free(mBuffer);
1262 free(mDynamicOutput);
1263 delete mCurrentOut;
1264
1265 while ((mCurrentOut = mOutgoingPingMessages.PopFront())) {
1266 delete mCurrentOut;
1267 }
1268 while ((mCurrentOut = mOutgoingPongMessages.PopFront())) {
1269 delete mCurrentOut;
1270 }
1271 while ((mCurrentOut = mOutgoingMessages.PopFront())) {
1272 delete mCurrentOut;
1273 }
1274
1275 mListenerMT = nullptr;
1276
1277 NS_ReleaseOnMainThread("WebSocketChannel::mService", mService.forget());
1278}
1279
1280NS_IMETHODIMPnsresult
1281WebSocketChannel::Observe(nsISupports* subject, const char* topic,
1282 const char16_t* data) {
1283 LOG(("WebSocketChannel::Observe [topic=\"%s\"]\n", topic))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::Observe [topic=\"%s\"]\n"
, topic); } } while (0)
;
1284
1285 if (strcmp(topic, NS_NETWORK_LINK_TOPIC"network:link-status-changed") == 0) {
1286 nsCString converted = NS_ConvertUTF16toUTF8(data);
1287 const char* state = converted.get();
1288
1289 if (strcmp(state, NS_NETWORK_LINK_DATA_CHANGED"changed") == 0) {
1290 LOG(("WebSocket: received network CHANGED event"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocket: received network CHANGED event"
); } } while (0)
;
1291
1292 if (!mIOThread) {
1293 // there has not been an asyncopen yet on the object and then we need
1294 // no ping.
1295 LOG(("WebSocket: early object, no ping needed"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocket: early object, no ping needed"
); } } while (0)
;
1296 } else {
1297 mIOThread->Dispatch(
1298 NewRunnableMethod("net::WebSocketChannel::OnNetworkChanged", this,
1299 &WebSocketChannel::OnNetworkChanged),
1300 NS_DISPATCH_NORMALnsIEventTarget::DISPATCH_NORMAL);
1301 }
1302 }
1303 }
1304
1305 return NS_OK;
1306}
1307
1308nsresult WebSocketChannel::OnNetworkChanged() {
1309 if (!mDataStarted) {
1310 LOG(("WebSocket: data not started yet, no ping needed"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocket: data not started yet, no ping needed"
); } } while (0)
;
1311 return NS_OK;
1312 }
1313
1314 MOZ_ASSERT(mIOThread->IsOnCurrentThread(), "not on right thread")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mIOThread->IsOnCurrentThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mIOThread->IsOnCurrentThread
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mIOThread->IsOnCurrentThread()" " (" "not on right thread"
")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 1314); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mIOThread->IsOnCurrentThread()"
") (" "not on right thread" ")"); do { MOZ_CrashSequence(__null
, 1314); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
1315
1316 LOG(("WebSocketChannel::OnNetworkChanged() - on socket thread %p", this))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OnNetworkChanged() - on socket thread %p"
, this); } } while (0)
;
1317
1318 if (mPingOutstanding) {
1319 // If there's an outstanding ping that's expected to get a pong back
1320 // we let that do its thing.
1321 LOG(("WebSocket: pong already pending"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocket: pong already pending"
); } } while (0)
;
1322 return NS_OK;
1323 }
1324
1325 if (mPingForced) {
1326 // avoid more than one
1327 LOG(("WebSocket: forced ping timer already fired"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocket: forced ping timer already fired"
); } } while (0)
;
1328 return NS_OK;
1329 }
1330
1331 LOG(("nsWebSocketChannel:: Generating Ping as network changed\n"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "nsWebSocketChannel:: Generating Ping as network changed\n"
); } } while (0)
;
1332
1333 if (!mPingTimer) {
1334 // The ping timer is only conditionally running already. If it wasn't
1335 // already created do it here.
1336 mPingTimer = NS_NewTimer();
1337 if (!mPingTimer) {
1338 LOG(("WebSocket: unable to create ping timer!"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocket: unable to create ping timer!"
); } } while (0)
;
1339 NS_WARNING("unable to create ping timer!")NS_DebugBreak(NS_DEBUG_WARNING, "unable to create ping timer!"
, nullptr, "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 1339)
;
1340 return NS_ERROR_OUT_OF_MEMORY;
1341 }
1342 }
1343 // Trigger the ping timeout asap to fire off a new ping. Wait just
1344 // a little bit to better avoid multi-triggers.
1345 mPingForced = true;
1346 mPingTimer->InitWithCallback(this, 200, nsITimer::TYPE_ONE_SHOT);
1347
1348 return NS_OK;
1349}
1350
1351void WebSocketChannel::Shutdown() { nsWSAdmissionManager::Shutdown(); }
1352
1353void WebSocketChannel::GetEffectiveURL(nsAString& aEffectiveURL) const {
1354 aEffectiveURL = mEffectiveURL;
1355}
1356
1357bool WebSocketChannel::IsEncrypted() const { return mEncrypted; }
1358
1359void WebSocketChannel::BeginOpen(bool aCalledFromAdmissionManager) {
1360 MOZ_ASSERT(NS_IsMainThread(), "not main thread")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
" (" "not main thread" ")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 1360); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
") (" "not main thread" ")"); do { MOZ_CrashSequence(__null,
1360); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false)
;
1361
1362 LOG(("WebSocketChannel::BeginOpen() %p\n", this))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::BeginOpen() %p\n"
, this); } } while (0)
;
1363
1364 // Important that we set CONNECTING_IN_PROGRESS before any call to
1365 // AbortSession here: ensures that any remaining queued connection(s) are
1366 // scheduled in OnStopSession
1367 LOG(("Websocket: changing state to CONNECTING_IN_PROGRESS"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "Websocket: changing state to CONNECTING_IN_PROGRESS"
); } } while (0)
;
1368 mConnecting = CONNECTING_IN_PROGRESS;
1369
1370 if (aCalledFromAdmissionManager) {
1371 // When called from nsWSAdmissionManager post an event to avoid potential
1372 // re-entering of nsWSAdmissionManager and its lock.
1373 NS_DispatchToMainThread(
1374 NewRunnableMethod("net::WebSocketChannel::BeginOpenInternal", this,
1375 &WebSocketChannel::BeginOpenInternal),
1376 NS_DISPATCH_NORMALnsIEventTarget::DISPATCH_NORMAL);
1377 } else {
1378 BeginOpenInternal();
1379 }
1380}
1381
1382// MainThread
1383void WebSocketChannel::BeginOpenInternal() {
1384 LOG(("WebSocketChannel::BeginOpenInternal() %p\n", this))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::BeginOpenInternal() %p\n"
, this); } } while (0)
;
1385 MOZ_ASSERT(NS_IsMainThread(), "not main thread")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
" (" "not main thread" ")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 1385); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
") (" "not main thread" ")"); do { MOZ_CrashSequence(__null,
1385); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false)
;
1386
1387 nsresult rv;
1388
1389 if (mRedirectCallback) {
1390 LOG(("WebSocketChannel::BeginOpenInternal: Resuming Redirect\n"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::BeginOpenInternal: Resuming Redirect\n"
); } } while (0)
;
1391 rv = mRedirectCallback->OnRedirectVerifyCallback(NS_OK);
1392 mRedirectCallback = nullptr;
1393 return;
1394 }
1395
1396 nsCOMPtr<nsIChannel> localChannel = do_QueryInterface(mChannel, &rv);
1397 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
1398 LOG(("WebSocketChannel::BeginOpenInternal: cannot async open\n"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::BeginOpenInternal: cannot async open\n"
); } } while (0)
;
1399 AbortSession(NS_ERROR_UNEXPECTED);
1400 return;
1401 }
1402
1403 rv = localChannel->AsyncOpen(this);
1404
1405 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
1406 LOG(("WebSocketChannel::BeginOpenInternal: cannot async open\n"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::BeginOpenInternal: cannot async open\n"
); } } while (0)
;
1407 AbortSession(NS_ERROR_WEBSOCKET_CONNECTION_REFUSED);
1408 return;
1409 }
1410 mOpenedHttpChannel = true;
1411
1412 rv = NS_NewTimerWithCallback(getter_AddRefs(mOpenTimer), this, mOpenTimeout,
1413 nsITimer::TYPE_ONE_SHOT);
1414 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
1415 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::BeginOpenInternal: cannot initialize open "
"timer\n"); } } while (0)
1416 ("WebSocketChannel::BeginOpenInternal: cannot initialize open "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::BeginOpenInternal: cannot initialize open "
"timer\n"); } } while (0)
1417 "timer\n"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::BeginOpenInternal: cannot initialize open "
"timer\n"); } } while (0)
;
1418 AbortSession(NS_ERROR_UNEXPECTED);
1419 return;
1420 }
1421}
1422
1423bool WebSocketChannel::IsPersistentFramePtr() {
1424 return (mFramePtr >= mBuffer && mFramePtr <= mBuffer + mBufferSize);
1425}
1426
1427// Extends the internal buffer by count and returns the total
1428// amount of data available for read
1429//
1430// Accumulated fragment size is passed in instead of using the member
1431// variable beacuse when transitioning from the stack to the persistent
1432// read buffer we want to explicitly include them in the buffer instead
1433// of as already existing data.
1434bool WebSocketChannel::UpdateReadBuffer(uint8_t* buffer, uint32_t count,
1435 uint32_t accumulatedFragments,
1436 uint32_t* available) {
1437 LOG(("WebSocketChannel::UpdateReadBuffer() %p [%p %u]\n", this, buffer,do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::UpdateReadBuffer() %p [%p %u]\n"
, this, buffer, count); } } while (0)
1438 count))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::UpdateReadBuffer() %p [%p %u]\n"
, this, buffer, count); } } while (0)
;
1439
1440 if (!mBuffered) mFramePtr = mBuffer;
1441
1442 MOZ_ASSERT(IsPersistentFramePtr(), "update read buffer bad mFramePtr")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsPersistentFramePtr())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(IsPersistentFramePtr()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("IsPersistentFramePtr()"
" (" "update read buffer bad mFramePtr" ")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 1442); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsPersistentFramePtr()"
") (" "update read buffer bad mFramePtr" ")"); do { MOZ_CrashSequence
(__null, 1442); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
1443 MOZ_ASSERT(mFramePtr - accumulatedFragments >= mBuffer,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mFramePtr - accumulatedFragments >= mBuffer)>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(mFramePtr - accumulatedFragments >= mBuffer))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("mFramePtr - accumulatedFragments >= mBuffer"
" (" "reserved FramePtr bad" ")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 1444); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mFramePtr - accumulatedFragments >= mBuffer"
") (" "reserved FramePtr bad" ")"); do { MOZ_CrashSequence(__null
, 1444); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
1444 "reserved FramePtr bad")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mFramePtr - accumulatedFragments >= mBuffer)>::
isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(mFramePtr - accumulatedFragments >= mBuffer))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("mFramePtr - accumulatedFragments >= mBuffer"
" (" "reserved FramePtr bad" ")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 1444); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mFramePtr - accumulatedFragments >= mBuffer"
") (" "reserved FramePtr bad" ")"); do { MOZ_CrashSequence(__null
, 1444); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
1445
1446 if (mBuffered + count <= mBufferSize) {
1447 // append to existing buffer
1448 LOG(("WebSocketChannel: update read buffer absorbed %u\n", count))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel: update read buffer absorbed %u\n"
, count); } } while (0)
;
1449 } else if (mBuffered + count - (mFramePtr - accumulatedFragments - mBuffer) <=
1450 mBufferSize) {
1451 // make room in existing buffer by shifting unused data to start
1452 mBuffered -= (mFramePtr - mBuffer - accumulatedFragments);
1453 LOG(("WebSocketChannel: update read buffer shifted %u\n", mBuffered))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel: update read buffer shifted %u\n"
, mBuffered); } } while (0)
;
1454 ::memmove(mBuffer, mFramePtr - accumulatedFragments, mBuffered);
1455 mFramePtr = mBuffer + accumulatedFragments;
1456 } else {
1457 // existing buffer is not sufficient, extend it
1458 uint32_t newBufferSize = mBufferSize;
1459 newBufferSize += count + 8192 + mBufferSize / 3;
1460 ptrdiff_t frameIndex = mFramePtr - mBuffer;
1461 LOG(("WebSocketChannel: update read buffer extended to %u\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel: update read buffer extended to %u\n"
, newBufferSize); } } while (0)
1462 newBufferSize))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel: update read buffer extended to %u\n"
, newBufferSize); } } while (0)
;
1463 uint8_t* newBuffer = (uint8_t*)realloc(mBuffer, newBufferSize);
1464 if (!newBuffer) {
1465 // Reallocation failed.
1466 return false;
1467 }
1468 mBuffer = newBuffer;
1469 mBufferSize = newBufferSize;
1470
1471 // mBuffer was reallocated, so we need to update mFramePtr
1472 mFramePtr = mBuffer + frameIndex;
1473 }
1474
1475 ::memmove(mBuffer + mBuffered, buffer, count);
1476 mBuffered += count;
1477
1478 if (available) *available = mBuffered - (mFramePtr - mBuffer);
1479
1480 return true;
1481}
1482
1483already_AddRefed<BaseWebSocketChannel::ListenerAndContextContainer>
1484WebSocketChannel::GetListenerMT() {
1485 MutexAutoLock lock(mMutex);
1486 return do_AddRef(mStopped ? nullptr : mListenerMT.get());
1487}
1488
1489already_AddRefed<BaseWebSocketChannel::ListenerAndContextContainer>
1490WebSocketChannel::TakeListenerMT() {
1491 MutexAutoLock lock(mMutex);
1492 return mListenerMT.forget();
1493}
1494
1495nsresult WebSocketChannel::ProcessInput(uint8_t* buffer, uint32_t count) {
1496 LOG(("WebSocketChannel::ProcessInput %p [%d %d]\n", this, count, mBuffered))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::ProcessInput %p [%d %d]\n"
, this, count, mBuffered); } } while (0)
;
1497 MOZ_ASSERT(mIOThread->IsOnCurrentThread(), "not on right thread")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mIOThread->IsOnCurrentThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mIOThread->IsOnCurrentThread
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mIOThread->IsOnCurrentThread()" " (" "not on right thread"
")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 1497); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mIOThread->IsOnCurrentThread()"
") (" "not on right thread" ")"); do { MOZ_CrashSequence(__null
, 1497); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
1498
1499 nsresult rv;
1500
1501 // The purpose of ping/pong is to actively probe the peer so that an
1502 // unreachable peer is not mistaken for a period of idleness. This
1503 // implementation accepts any application level read activity as a sign of
1504 // life, it does not necessarily have to be a pong.
1505 ResetPingTimer();
1506
1507 uint32_t avail;
1508
1509 if (!mBuffered) {
1510 // Most of the time we can process right off the stack buffer without
1511 // having to accumulate anything
1512 mFramePtr = buffer;
1513 avail = count;
1514 } else {
1515 if (!UpdateReadBuffer(buffer, count, mFragmentAccumulator, &avail)) {
1516 return NS_ERROR_FILE_TOO_BIG;
1517 }
1518 }
1519
1520 uint8_t* payload;
1521 uint32_t totalAvail = avail;
1522
1523 while (avail >= 2) {
1524 int64_t payloadLength64 = mFramePtr[1] & kPayloadLengthBitsMask;
1525 uint8_t finBit = mFramePtr[0] & kFinalFragBit;
1526 uint8_t rsvBits = mFramePtr[0] & kRsvBitsMask;
1527 uint8_t rsvBit1 = mFramePtr[0] & kRsv1Bit;
1528 uint8_t rsvBit2 = mFramePtr[0] & kRsv2Bit;
1529 uint8_t rsvBit3 = mFramePtr[0] & kRsv3Bit;
1530 uint8_t opcode = mFramePtr[0] & kOpcodeBitsMask;
1531 uint8_t maskBit = mFramePtr[1] & kMaskBit;
1532 uint32_t mask = 0;
1533
1534 uint32_t framingLength = 2;
1535 if (maskBit) framingLength += 4;
1536
1537 if (payloadLength64 < 126) {
1538 if (avail < framingLength) break;
1539 } else if (payloadLength64 == 126) {
1540 // 16 bit length field
1541 framingLength += 2;
1542 if (avail < framingLength) break;
1543
1544 payloadLength64 = mFramePtr[2] << 8 | mFramePtr[3];
1545
1546 if (payloadLength64 < 126) {
1547 // Section 5.2 says that the minimal number of bytes MUST
1548 // be used to encode the length in all cases
1549 LOG(("WebSocketChannel:: non-minimal-encoded payload length"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel:: non-minimal-encoded payload length"
); } } while (0)
;
1550 return NS_ERROR_ILLEGAL_VALUE;
1551 }
1552
1553 } else {
1554 // 64 bit length
1555 framingLength += 8;
1556 if (avail < framingLength) break;
1557
1558 if (mFramePtr[2] & 0x80) {
1559 // Section 4.2 says that the most significant bit MUST be
1560 // 0. (i.e. this is really a 63 bit value)
1561 LOG(("WebSocketChannel:: high bit of 64 bit length set"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel:: high bit of 64 bit length set"
); } } while (0)
;
1562 return NS_ERROR_ILLEGAL_VALUE;
1563 }
1564
1565 // copy this in case it is unaligned
1566 payloadLength64 = NetworkEndian::readInt64(mFramePtr + 2);
1567
1568 if (payloadLength64 <= 0xffff) {
1569 // Section 5.2 says that the minimal number of bytes MUST
1570 // be used to encode the length in all cases
1571 LOG(("WebSocketChannel:: non-minimal-encoded payload length"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel:: non-minimal-encoded payload length"
); } } while (0)
;
1572 return NS_ERROR_ILLEGAL_VALUE;
1573 }
1574 }
1575
1576 payload = mFramePtr + framingLength;
1577 avail -= framingLength;
1578
1579 LOG(("WebSocketChannel::ProcessInput: payload %" PRId64 " avail %" PRIu32do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::ProcessInput: payload %"
"l" "d" " avail %" "u" "\n", payloadLength64, avail); } } while
(0)
1580 "\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::ProcessInput: payload %"
"l" "d" " avail %" "u" "\n", payloadLength64, avail); } } while
(0)
1581 payloadLength64, avail))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::ProcessInput: payload %"
"l" "d" " avail %" "u" "\n", payloadLength64, avail); } } while
(0)
;
1582
1583 CheckedInt<int64_t> payloadLengthChecked(payloadLength64);
1584 payloadLengthChecked += mFragmentAccumulator;
1585 if (!payloadLengthChecked.isValid() ||
1586 payloadLengthChecked.value() > mMaxMessageSize) {
1587 return NS_ERROR_FILE_TOO_BIG;
1588 }
1589
1590 uint32_t payloadLength = static_cast<uint32_t>(payloadLength64);
1591
1592 if (avail < payloadLength) break;
1593
1594 LOG(("WebSocketChannel::ProcessInput: Frame accumulated - opcode %d\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::ProcessInput: Frame accumulated - opcode %d\n"
, opcode); } } while (0)
1595 opcode))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::ProcessInput: Frame accumulated - opcode %d\n"
, opcode); } } while (0)
;
1596
1597 if (!maskBit && mIsServerSide) {
1598 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::ProcessInput: unmasked frame received "
"from client\n"); } } while (0)
1599 ("WebSocketChannel::ProcessInput: unmasked frame received "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::ProcessInput: unmasked frame received "
"from client\n"); } } while (0)
1600 "from client\n"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::ProcessInput: unmasked frame received "
"from client\n"); } } while (0)
;
1601 return NS_ERROR_ILLEGAL_VALUE;
1602 }
1603
1604 if (maskBit) {
1605 if (!mIsServerSide) {
1606 // The server should not be allowed to send masked frames to clients.
1607 // But we've been allowing it for some time, so this should be
1608 // deprecated with care.
1609 LOG(("WebSocketChannel:: Client RECEIVING masked frame."))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel:: Client RECEIVING masked frame."
); } } while (0)
;
1610 }
1611
1612 mask = NetworkEndian::readUint32(payload - 4);
1613 }
1614
1615 if (mask) {
1616 ApplyMask(mask, payload, payloadLength);
1617 } else if (mIsServerSide) {
1618 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::ProcessInput: masked frame with mask 0 received"
"from client\n"); } } while (0)
1619 ("WebSocketChannel::ProcessInput: masked frame with mask 0 received"do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::ProcessInput: masked frame with mask 0 received"
"from client\n"); } } while (0)
1620 "from client\n"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::ProcessInput: masked frame with mask 0 received"
"from client\n"); } } while (0)
;
1621 return NS_ERROR_ILLEGAL_VALUE;
1622 }
1623
1624 // Control codes are required to have the fin bit set
1625 if (!finBit && (opcode & kControlFrameMask)) {
1626 LOG(("WebSocketChannel:: fragmented control frame code %d\n", opcode))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel:: fragmented control frame code %d\n"
, opcode); } } while (0)
;
1627 return NS_ERROR_ILLEGAL_VALUE;
1628 }
1629
1630 if (rsvBits) {
1631 // PMCE sets RSV1 bit in the first fragment when the non-control frame
1632 // is deflated
1633 MutexAutoLock lock(mCompressorMutex);
1634 if (mPMCECompressor && rsvBits == kRsv1Bit && mFragmentAccumulator == 0 &&
1635 !(opcode & kControlFrameMask)) {
1636 mPMCECompressor->SetMessageDeflated();
1637 LOG(("WebSocketChannel::ProcessInput: received deflated frame\n"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::ProcessInput: received deflated frame\n"
); } } while (0)
;
1638 } else {
1639 LOG(("WebSocketChannel::ProcessInput: unexpected reserved bits %x\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::ProcessInput: unexpected reserved bits %x\n"
, rsvBits); } } while (0)
1640 rsvBits))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::ProcessInput: unexpected reserved bits %x\n"
, rsvBits); } } while (0)
;
1641 return NS_ERROR_ILLEGAL_VALUE;
1642 }
1643 }
1644
1645 if (!finBit || opcode == nsIWebSocketFrame::OPCODE_CONTINUATION) {
1646 // This is part of a fragment response
1647
1648 // Only the first frame has a non zero op code: Make sure we don't see a
1649 // first frame while some old fragments are open
1650 if ((mFragmentAccumulator != 0) &&
1651 (opcode != nsIWebSocketFrame::OPCODE_CONTINUATION)) {
1652 LOG(("WebSocketChannel:: nested fragments\n"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel:: nested fragments\n"
); } } while (0)
;
1653 return NS_ERROR_ILLEGAL_VALUE;
1654 }
1655
1656 LOG(("WebSocketChannel:: Accumulating Fragment %" PRIu32 "\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel:: Accumulating Fragment %"
"u" "\n", payloadLength); } } while (0)
1657 payloadLength))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel:: Accumulating Fragment %"
"u" "\n", payloadLength); } } while (0)
;
1658
1659 if (opcode == nsIWebSocketFrame::OPCODE_CONTINUATION) {
1660 // Make sure this continuation fragment isn't the first fragment
1661 if (mFragmentOpcode == nsIWebSocketFrame::OPCODE_CONTINUATION) {
1662 LOG(("WebSocketHeandler:: continuation code in first fragment\n"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketHeandler:: continuation code in first fragment\n"
); } } while (0)
;
1663 return NS_ERROR_ILLEGAL_VALUE;
1664 }
1665
1666 // For frag > 1 move the data body back on top of the headers
1667 // so we have contiguous stream of data
1668 MOZ_ASSERT(mFramePtr + framingLength == payload,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mFramePtr + framingLength == payload)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mFramePtr + framingLength ==
payload))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mFramePtr + framingLength == payload" " (" "payload offset from frameptr wrong"
")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 1669); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mFramePtr + framingLength == payload"
") (" "payload offset from frameptr wrong" ")"); do { MOZ_CrashSequence
(__null, 1669); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
1669 "payload offset from frameptr wrong")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mFramePtr + framingLength == payload)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mFramePtr + framingLength ==
payload))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mFramePtr + framingLength == payload" " (" "payload offset from frameptr wrong"
")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 1669); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mFramePtr + framingLength == payload"
") (" "payload offset from frameptr wrong" ")"); do { MOZ_CrashSequence
(__null, 1669); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
1670 ::memmove(mFramePtr, payload, avail);
1671 payload = mFramePtr;
1672 if (mBuffered) mBuffered -= framingLength;
1673 } else {
1674 mFragmentOpcode = opcode;
1675 }
1676
1677 if (finBit) {
1678 LOG(("WebSocketChannel:: Finalizing Fragment\n"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel:: Finalizing Fragment\n"
); } } while (0)
;
1679 payload -= mFragmentAccumulator;
1680 payloadLength += mFragmentAccumulator;
1681 avail += mFragmentAccumulator;
1682 mFragmentAccumulator = 0;
1683 opcode = mFragmentOpcode;
1684 // reset to detect if next message illegally starts with continuation
1685 mFragmentOpcode = nsIWebSocketFrame::OPCODE_CONTINUATION;
1686 } else {
1687 opcode = nsIWebSocketFrame::OPCODE_CONTINUATION;
1688 mFragmentAccumulator += payloadLength;
1689 }
1690 } else if (mFragmentAccumulator != 0 && !(opcode & kControlFrameMask)) {
1691 // This frame is not part of a fragment sequence but we
1692 // have an open fragment.. it must be a control code or else
1693 // we have a problem
1694 LOG(("WebSocketChannel:: illegal fragment sequence\n"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel:: illegal fragment sequence\n"
); } } while (0)
;
1695 return NS_ERROR_ILLEGAL_VALUE;
1696 }
1697
1698 if (mServerClosed) {
1699 LOG(("WebSocketChannel:: ignoring read frame code %d after close\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel:: ignoring read frame code %d after close\n"
, opcode); } } while (0)
1700 opcode))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel:: ignoring read frame code %d after close\n"
, opcode); } } while (0)
;
1701 // nop
1702 } else if (mStopped) {
1703 LOG(("WebSocketChannel:: ignoring read frame code %d after completion\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel:: ignoring read frame code %d after completion\n"
, opcode); } } while (0)
1704 opcode))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel:: ignoring read frame code %d after completion\n"
, opcode); } } while (0)
;
1705 } else if (opcode == nsIWebSocketFrame::OPCODE_TEXT) {
1706 if (RefPtr<BaseWebSocketChannel::ListenerAndContextContainer> listener =
1707 GetListenerMT()) {
1708 nsCString utf8Data;
1709 {
1710 MutexAutoLock lock(mCompressorMutex);
1711 bool isDeflated =
1712 mPMCECompressor && mPMCECompressor->IsMessageDeflated();
1713 LOG(("WebSocketChannel:: %stext frame received\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel:: %stext frame received\n"
, isDeflated ? "deflated " : ""); } } while (0)
1714 isDeflated ? "deflated " : ""))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel:: %stext frame received\n"
, isDeflated ? "deflated " : ""); } } while (0)
;
1715
1716 if (isDeflated) {
1717 rv = mPMCECompressor->Inflate(payload, payloadLength, utf8Data);
1718 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
1719 return rv;
1720 }
1721 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel:: message successfully inflated "
"[origLength=%d, newLength=%zd]\n", payloadLength, utf8Data.
Length()); } } while (0)
1722 ("WebSocketChannel:: message successfully inflated "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel:: message successfully inflated "
"[origLength=%d, newLength=%zd]\n", payloadLength, utf8Data.
Length()); } } while (0)
1723 "[origLength=%d, newLength=%zd]\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel:: message successfully inflated "
"[origLength=%d, newLength=%zd]\n", payloadLength, utf8Data.
Length()); } } while (0)
1724 payloadLength, utf8Data.Length()))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel:: message successfully inflated "
"[origLength=%d, newLength=%zd]\n", payloadLength, utf8Data.
Length()); } } while (0)
;
1725 } else {
1726 if (!utf8Data.Assign((const char*)payload, payloadLength,
1727 mozilla::fallible)) {
1728 return NS_ERROR_OUT_OF_MEMORY;
1729 }
1730 }
1731 }
1732
1733 // Section 8.1 says to fail connection if invalid utf-8 in text message
1734 if (!IsUtf8(utf8Data)) {
1735 LOG(("WebSocketChannel:: text frame invalid utf-8\n"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel:: text frame invalid utf-8\n"
); } } while (0)
;
1736 return NS_ERROR_CANNOT_CONVERT_DATA;
1737 }
1738
1739 RefPtr<WebSocketFrame> frame = mService->CreateFrameIfNeeded(
1740 finBit, rsvBit1, rsvBit2, rsvBit3, opcode, maskBit, mask, utf8Data);
1741
1742 if (frame) {
1743 mService->FrameReceived(mSerial, mInnerWindowID, frame.forget());
1744 }
1745
1746 if (nsCOMPtr<nsIEventTarget> target = GetTargetThread()) {
1747 target->Dispatch(new CallOnMessageAvailable(this, std::move(listener),
1748 utf8Data, -1),
1749 NS_DISPATCH_NORMALnsIEventTarget::DISPATCH_NORMAL);
1750 } else {
1751 return NS_ERROR_UNEXPECTED;
1752 }
1753 if (mConnectionLogService && !mPrivateBrowsing) {
1754 mConnectionLogService->NewMsgReceived(mHost, mSerial, count);
1755 LOG(("Added new msg received for %s", mHost.get()))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "Added new msg received for %s"
, mHost.get()); } } while (0)
;
1756 }
1757 }
1758 } else if (opcode & kControlFrameMask) {
1759 // control frames
1760 if (payloadLength > 125) {
1761 LOG(("WebSocketChannel:: bad control frame code %d length %d\n", opcode,do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel:: bad control frame code %d length %d\n"
, opcode, payloadLength); } } while (0)
1762 payloadLength))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel:: bad control frame code %d length %d\n"
, opcode, payloadLength); } } while (0)
;
1763 return NS_ERROR_ILLEGAL_VALUE;
1764 }
1765
1766 RefPtr<WebSocketFrame> frame = mService->CreateFrameIfNeeded(
1767 finBit, rsvBit1, rsvBit2, rsvBit3, opcode, maskBit, mask, payload,
1768 payloadLength);
1769
1770 if (opcode == nsIWebSocketFrame::OPCODE_CLOSE) {
1771 LOG(("WebSocketChannel:: close received\n"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel:: close received\n"
); } } while (0)
;
1772 mServerClosed = true;
1773
1774 mServerCloseCode = CLOSE_NO_STATUS;
1775 if (payloadLength >= 2) {
1776 mServerCloseCode = NetworkEndian::readUint16(payload);
1777 LOG(("WebSocketChannel:: close recvd code %u\n", mServerCloseCode))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel:: close recvd code %u\n"
, mServerCloseCode); } } while (0)
;
1778 uint16_t msglen = static_cast<uint16_t>(payloadLength - 2);
1779 if (msglen > 0) {
1780 mServerCloseReason.SetLength(msglen);
1781 memcpy(mServerCloseReason.BeginWriting(), (const char*)payload + 2,
1782 msglen);
1783
1784 // section 8.1 says to replace received non utf-8 sequences
1785 // (which are non-conformant to send) with u+fffd,
1786 // but secteam feels that silently rewriting messages is
1787 // inappropriate - so we will fail the connection instead.
1788 if (!IsUtf8(mServerCloseReason)) {
1789 LOG(("WebSocketChannel:: close frame invalid utf-8\n"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel:: close frame invalid utf-8\n"
); } } while (0)
;
1790 return NS_ERROR_CANNOT_CONVERT_DATA;
1791 }
1792
1793 LOG(("WebSocketChannel:: close msg %s\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel:: close msg %s\n"
, mServerCloseReason.get()); } } while (0)
1794 mServerCloseReason.get()))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel:: close msg %s\n"
, mServerCloseReason.get()); } } while (0)
;
1795 }
1796 }
1797
1798 if (mCloseTimer) {
1799 mCloseTimer->Cancel();
1800 mCloseTimer = nullptr;
1801 }
1802
1803 if (frame) {
1804 // We send the frame immediately becuase we want to have it dispatched
1805 // before the CallOnServerClose.
1806 mService->FrameReceived(mSerial, mInnerWindowID, frame.forget());
1807 frame = nullptr;
1808 }
1809
1810 if (RefPtr<BaseWebSocketChannel::ListenerAndContextContainer> listener =
1811 GetListenerMT()) {
1812 if (nsCOMPtr<nsIEventTarget> target = GetTargetThread()) {
1813 target->Dispatch(
1814 new CallOnServerClose(this, std::move(listener),
1815 mServerCloseCode, mServerCloseReason),
1816 NS_DISPATCH_NORMALnsIEventTarget::DISPATCH_NORMAL);
1817 } else {
1818 return NS_ERROR_UNEXPECTED;
1819 }
1820 }
1821
1822 if (mClientClosed) ReleaseSession();
1823 } else if (opcode == nsIWebSocketFrame::OPCODE_PING) {
1824 LOG(("WebSocketChannel:: ping received\n"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel:: ping received\n"
); } } while (0)
;
1825 GeneratePong(payload, payloadLength);
1826 } else if (opcode == nsIWebSocketFrame::OPCODE_PONG) {
1827 // opcode OPCODE_PONG: the mere act of receiving the packet is all we
1828 // need to do for the pong to trigger the activity timers
1829 LOG(("WebSocketChannel:: pong received\n"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel:: pong received\n"
); } } while (0)
;
1830 } else {
1831 /* unknown control frame opcode */
1832 LOG(("WebSocketChannel:: unknown control op code %d\n", opcode))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel:: unknown control op code %d\n"
, opcode); } } while (0)
;
1833 return NS_ERROR_ILLEGAL_VALUE;
1834 }
1835
1836 if (mFragmentAccumulator) {
1837 // Remove the control frame from the stream so we have a contiguous
1838 // data buffer of reassembled fragments
1839 LOG(("WebSocketChannel:: Removing Control From Read buffer\n"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel:: Removing Control From Read buffer\n"
); } } while (0)
;
1840 MOZ_ASSERT(mFramePtr + framingLength == payload,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mFramePtr + framingLength == payload)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mFramePtr + framingLength ==
payload))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mFramePtr + framingLength == payload" " (" "payload offset from frameptr wrong"
")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 1841); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mFramePtr + framingLength == payload"
") (" "payload offset from frameptr wrong" ")"); do { MOZ_CrashSequence
(__null, 1841); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
1841 "payload offset from frameptr wrong")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mFramePtr + framingLength == payload)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mFramePtr + framingLength ==
payload))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mFramePtr + framingLength == payload" " (" "payload offset from frameptr wrong"
")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 1841); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mFramePtr + framingLength == payload"
") (" "payload offset from frameptr wrong" ")"); do { MOZ_CrashSequence
(__null, 1841); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
1842 ::memmove(mFramePtr, payload + payloadLength, avail - payloadLength);
1843 payload = mFramePtr;
1844 avail -= payloadLength;
1845 if (mBuffered) mBuffered -= framingLength + payloadLength;
1846 payloadLength = 0;
1847 }
1848
1849 if (frame) {
1850 mService->FrameReceived(mSerial, mInnerWindowID, frame.forget());
1851 }
1852 } else if (opcode == nsIWebSocketFrame::OPCODE_BINARY) {
1853 if (RefPtr<BaseWebSocketChannel::ListenerAndContextContainer> listener =
1854 GetListenerMT()) {
1855 nsCString binaryData;
1856 {
1857 MutexAutoLock lock(mCompressorMutex);
1858 bool isDeflated =
1859 mPMCECompressor && mPMCECompressor->IsMessageDeflated();
1860 LOG(("WebSocketChannel:: %sbinary frame received\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel:: %sbinary frame received\n"
, isDeflated ? "deflated " : ""); } } while (0)
1861 isDeflated ? "deflated " : ""))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel:: %sbinary frame received\n"
, isDeflated ? "deflated " : ""); } } while (0)
;
1862
1863 if (isDeflated) {
1864 rv = mPMCECompressor->Inflate(payload, payloadLength, binaryData);
1865 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
1866 return rv;
1867 }
1868 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel:: message successfully inflated "
"[origLength=%d, newLength=%zd]\n", payloadLength, binaryData
.Length()); } } while (0)
1869 ("WebSocketChannel:: message successfully inflated "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel:: message successfully inflated "
"[origLength=%d, newLength=%zd]\n", payloadLength, binaryData
.Length()); } } while (0)
1870 "[origLength=%d, newLength=%zd]\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel:: message successfully inflated "
"[origLength=%d, newLength=%zd]\n", payloadLength, binaryData
.Length()); } } while (0)
1871 payloadLength, binaryData.Length()))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel:: message successfully inflated "
"[origLength=%d, newLength=%zd]\n", payloadLength, binaryData
.Length()); } } while (0)
;
1872 } else {
1873 if (!binaryData.Assign((const char*)payload, payloadLength,
1874 mozilla::fallible)) {
1875 return NS_ERROR_OUT_OF_MEMORY;
1876 }
1877 }
1878 }
1879
1880 RefPtr<WebSocketFrame> frame =
1881 mService->CreateFrameIfNeeded(finBit, rsvBit1, rsvBit2, rsvBit3,
1882 opcode, maskBit, mask, binaryData);
1883 if (frame) {
1884 mService->FrameReceived(mSerial, mInnerWindowID, frame.forget());
1885 }
1886
1887 if (nsCOMPtr<nsIEventTarget> target = GetTargetThread()) {
1888 target->Dispatch(
1889 new CallOnMessageAvailable(this, std::move(listener), binaryData,
1890 binaryData.Length()),
1891 NS_DISPATCH_NORMALnsIEventTarget::DISPATCH_NORMAL);
1892 } else {
1893 return NS_ERROR_UNEXPECTED;
1894 }
1895 // To add the header to 'Networking Dashboard' log
1896 if (mConnectionLogService && !mPrivateBrowsing) {
1897 mConnectionLogService->NewMsgReceived(mHost, mSerial, count);
1898 LOG(("Added new received msg for %s", mHost.get()))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "Added new received msg for %s"
, mHost.get()); } } while (0)
;
1899 }
1900 }
1901 } else if (opcode != nsIWebSocketFrame::OPCODE_CONTINUATION) {
1902 /* unknown opcode */
1903 LOG(("WebSocketChannel:: unknown op code %d\n", opcode))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel:: unknown op code %d\n"
, opcode); } } while (0)
;
1904 return NS_ERROR_ILLEGAL_VALUE;
1905 }
1906
1907 mFramePtr = payload + payloadLength;
1908 avail -= payloadLength;
1909 totalAvail = avail;
1910 }
1911
1912 // Adjust the stateful buffer. If we were operating off the stack and
1913 // now have a partial message then transition to the buffer, or if
1914 // we were working off the buffer but no longer have any active state
1915 // then transition to the stack
1916 if (!IsPersistentFramePtr()) {
1917 mBuffered = 0;
1918
1919 if (mFragmentAccumulator) {
1920 LOG(("WebSocketChannel:: Setup Buffer due to fragment"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel:: Setup Buffer due to fragment"
); } } while (0)
;
1921
1922 if (!UpdateReadBuffer(mFramePtr - mFragmentAccumulator,
1923 totalAvail + mFragmentAccumulator, 0, nullptr)) {
1924 return NS_ERROR_FILE_TOO_BIG;
1925 }
1926
1927 // UpdateReadBuffer will reset the frameptr to the beginning
1928 // of new saved state, so we need to skip past processed framgents
1929 mFramePtr += mFragmentAccumulator;
1930 } else if (totalAvail) {
1931 LOG(("WebSocketChannel:: Setup Buffer due to partial frame"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel:: Setup Buffer due to partial frame"
); } } while (0)
;
1932 if (!UpdateReadBuffer(mFramePtr, totalAvail, 0, nullptr)) {
1933 return NS_ERROR_FILE_TOO_BIG;
1934 }
1935 }
1936 } else if (!mFragmentAccumulator && !totalAvail) {
1937 // If we were working off a saved buffer state and there is no partial
1938 // frame or fragment in process, then revert to stack behavior
1939 LOG(("WebSocketChannel:: Internal buffering not needed anymore"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel:: Internal buffering not needed anymore"
); } } while (0)
;
1940 mBuffered = 0;
1941
1942 // release memory if we've been processing a large message
1943 if (mBufferSize > kIncomingBufferStableSize) {
1944 mBufferSize = kIncomingBufferStableSize;
1945 free(mBuffer);
1946 mBuffer = (uint8_t*)moz_xmalloc(mBufferSize);
1947 }
1948 }
1949 return NS_OK;
1950}
1951
1952/* static */
1953void WebSocketChannel::ApplyMask(uint32_t mask, uint8_t* data, uint64_t len) {
1954 if (!data || len == 0) return;
1955
1956 // Optimally we want to apply the mask 32 bits at a time,
1957 // but the buffer might not be alligned. So we first deal with
1958 // 0 to 3 bytes of preamble individually
1959
1960 while (len && (reinterpret_cast<uintptr_t>(data) & 3)) {
1961 *data ^= mask >> 24;
1962 mask = RotateLeft(mask, 8);
1963 data++;
1964 len--;
1965 }
1966
1967 // perform mask on full words of data
1968
1969 uint32_t* iData = (uint32_t*)data;
1970 uint32_t* end = iData + (len / 4);
1971 NetworkEndian::writeUint32(&mask, mask);
1972 for (; iData < end; iData++) *iData ^= mask;
1973 mask = NetworkEndian::readUint32(&mask);
1974 data = (uint8_t*)iData;
1975 len = len % 4;
1976
1977 // There maybe up to 3 trailing bytes that need to be dealt with
1978 // individually
1979
1980 while (len) {
1981 *data ^= mask >> 24;
1982 mask = RotateLeft(mask, 8);
1983 data++;
1984 len--;
1985 }
1986}
1987
1988void WebSocketChannel::GeneratePing() {
1989 nsAutoCString buf;
1990 buf.AssignLiteral("PING");
1991 EnqueueOutgoingMessage(mOutgoingPingMessages,
1992 new OutboundMessage(kMsgTypePing, buf));
1993}
1994
1995void WebSocketChannel::GeneratePong(uint8_t* payload, uint32_t len) {
1996 nsAutoCString buf;
1997 buf.SetLength(len);
1998 if (buf.Length() < len) {
1999 LOG(("WebSocketChannel::GeneratePong Allocation Failure\n"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::GeneratePong Allocation Failure\n"
); } } while (0)
;
2000 return;
2001 }
2002
2003 memcpy(buf.BeginWriting(), payload, len);
2004 EnqueueOutgoingMessage(mOutgoingPongMessages,
2005 new OutboundMessage(kMsgTypePong, buf));
2006}
2007
2008void WebSocketChannel::EnqueueOutgoingMessage(nsDeque<OutboundMessage>& aQueue,
2009 OutboundMessage* aMsg) {
2010 MOZ_ASSERT(mIOThread->IsOnCurrentThread(), "not on right thread")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mIOThread->IsOnCurrentThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mIOThread->IsOnCurrentThread
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mIOThread->IsOnCurrentThread()" " (" "not on right thread"
")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 2010); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mIOThread->IsOnCurrentThread()"
") (" "not on right thread" ")"); do { MOZ_CrashSequence(__null
, 2010); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
2011
2012 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::EnqueueOutgoingMessage %p "
"queueing msg %p [type=%s len=%d]\n", this, aMsg, msgNames[aMsg
->GetMsgType()], aMsg->Length()); } } while (0)
2013 ("WebSocketChannel::EnqueueOutgoingMessage %p "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::EnqueueOutgoingMessage %p "
"queueing msg %p [type=%s len=%d]\n", this, aMsg, msgNames[aMsg
->GetMsgType()], aMsg->Length()); } } while (0)
2014 "queueing msg %p [type=%s len=%d]\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::EnqueueOutgoingMessage %p "
"queueing msg %p [type=%s len=%d]\n", this, aMsg, msgNames[aMsg
->GetMsgType()], aMsg->Length()); } } while (0)
2015 this, aMsg, msgNames[aMsg->GetMsgType()], aMsg->Length()))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::EnqueueOutgoingMessage %p "
"queueing msg %p [type=%s len=%d]\n", this, aMsg, msgNames[aMsg
->GetMsgType()], aMsg->Length()); } } while (0)
;
2016
2017 aQueue.Push(aMsg);
2018 if (mSocketOut) {
2019 OnOutputStreamReady(mSocketOut);
2020 } else {
2021 DoEnqueueOutgoingMessage();
2022 }
2023}
2024
2025uint16_t WebSocketChannel::ResultToCloseCode(nsresult resultCode) {
2026 if (NS_SUCCEEDED(resultCode)((bool)(__builtin_expect(!!(!NS_FAILED_impl(resultCode)), 1))
)
) return CLOSE_NORMAL;
2027
2028 switch (resultCode) {
2029 case NS_ERROR_FILE_TOO_BIG:
2030 case NS_ERROR_OUT_OF_MEMORY:
2031 return CLOSE_TOO_LARGE;
2032 case NS_ERROR_CANNOT_CONVERT_DATA:
2033 return CLOSE_INVALID_PAYLOAD;
2034 case NS_ERROR_UNEXPECTED:
2035 return CLOSE_INTERNAL_ERROR;
2036 default:
2037 return CLOSE_PROTOCOL_ERROR;
2038 }
2039}
2040
2041void WebSocketChannel::PrimeNewOutgoingMessage() {
2042 LOG(("WebSocketChannel::PrimeNewOutgoingMessage() %p\n", this))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::PrimeNewOutgoingMessage() %p\n"
, this); } } while (0)
;
2043 MOZ_ASSERT(mIOThread->IsOnCurrentThread(), "not on right thread")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mIOThread->IsOnCurrentThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mIOThread->IsOnCurrentThread
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mIOThread->IsOnCurrentThread()" " (" "not on right thread"
")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 2043); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mIOThread->IsOnCurrentThread()"
") (" "not on right thread" ")"); do { MOZ_CrashSequence(__null
, 2043); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
2044 MOZ_ASSERT(!mCurrentOut, "Current message in progress")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mCurrentOut)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mCurrentOut))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("!mCurrentOut" " ("
"Current message in progress" ")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 2044); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mCurrentOut"
") (" "Current message in progress" ")"); do { MOZ_CrashSequence
(__null, 2044); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2045
2046 nsresult rv = NS_OK;
2047
2048 mCurrentOut = mOutgoingPongMessages.PopFront();
2049 if (mCurrentOut) {
2050 MOZ_ASSERT(mCurrentOut->GetMsgType() == kMsgTypePong, "Not pong message!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mCurrentOut->GetMsgType() == kMsgTypePong)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(mCurrentOut->GetMsgType() == kMsgTypePong))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("mCurrentOut->GetMsgType() == kMsgTypePong"
" (" "Not pong message!" ")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 2050); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mCurrentOut->GetMsgType() == kMsgTypePong"
") (" "Not pong message!" ")"); do { MOZ_CrashSequence(__null
, 2050); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
2051 } else {
2052 mCurrentOut = mOutgoingPingMessages.PopFront();
2053 if (mCurrentOut) {
2054 MOZ_ASSERT(mCurrentOut->GetMsgType() == kMsgTypePing,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mCurrentOut->GetMsgType() == kMsgTypePing)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(mCurrentOut->GetMsgType() == kMsgTypePing))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("mCurrentOut->GetMsgType() == kMsgTypePing"
" (" "Not ping message!" ")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 2055); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mCurrentOut->GetMsgType() == kMsgTypePing"
") (" "Not ping message!" ")"); do { MOZ_CrashSequence(__null
, 2055); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
2055 "Not ping message!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mCurrentOut->GetMsgType() == kMsgTypePing)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(mCurrentOut->GetMsgType() == kMsgTypePing))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("mCurrentOut->GetMsgType() == kMsgTypePing"
" (" "Not ping message!" ")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 2055); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mCurrentOut->GetMsgType() == kMsgTypePing"
") (" "Not ping message!" ")"); do { MOZ_CrashSequence(__null
, 2055); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
2056 } else {
2057 mCurrentOut = mOutgoingMessages.PopFront();
2058 }
2059 }
2060
2061 if (!mCurrentOut) return;
2062
2063 auto cleanupAfterFailure =
2064 MakeScopeExit([&] { DeleteCurrentOutGoingMessage(); });
2065
2066 WsMsgType msgType = mCurrentOut->GetMsgType();
2067
2068 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::PrimeNewOutgoingMessage "
"%p found queued msg %p [type=%s len=%d]\n", this, mCurrentOut
, msgNames[msgType], mCurrentOut->Length()); } } while (0)
2069 ("WebSocketChannel::PrimeNewOutgoingMessage "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::PrimeNewOutgoingMessage "
"%p found queued msg %p [type=%s len=%d]\n", this, mCurrentOut
, msgNames[msgType], mCurrentOut->Length()); } } while (0)
2070 "%p found queued msg %p [type=%s len=%d]\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::PrimeNewOutgoingMessage "
"%p found queued msg %p [type=%s len=%d]\n", this, mCurrentOut
, msgNames[msgType], mCurrentOut->Length()); } } while (0)
2071 this, mCurrentOut, msgNames[msgType], mCurrentOut->Length()))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::PrimeNewOutgoingMessage "
"%p found queued msg %p [type=%s len=%d]\n", this, mCurrentOut
, msgNames[msgType], mCurrentOut->Length()); } } while (0)
;
2072
2073 mCurrentOutSent = 0;
2074 mHdrOut = mOutHeader;
2075
2076 uint8_t maskBit = mIsServerSide ? 0 : kMaskBit;
2077 uint8_t maskSize = mIsServerSide ? 0 : 4;
2078
2079 uint8_t* payload = nullptr;
2080
2081 if (msgType == kMsgTypeFin) {
2082 // This is a demand to create a close message
2083 if (mClientClosed) {
2084 DeleteCurrentOutGoingMessage();
2085 PrimeNewOutgoingMessage();
2086 cleanupAfterFailure.release();
2087 return;
2088 }
2089
2090 mClientClosed = true;
2091 mOutHeader[0] = kFinalFragBit | nsIWebSocketFrame::OPCODE_CLOSE;
2092 mOutHeader[1] = maskBit;
2093
2094 // payload is offset 2 plus size of the mask
2095 payload = mOutHeader + 2 + maskSize;
2096
2097 // The close reason code sits in the first 2 bytes of payload
2098 // If the channel user provided a code and reason during Close()
2099 // and there isn't an internal error, use that.
2100 if (NS_SUCCEEDED(mStopOnClose)((bool)(__builtin_expect(!!(!NS_FAILED_impl(mStopOnClose)), 1
)))
) {
2101 MutexAutoLock lock(mMutex);
2102 if (mScriptCloseCode) {
2103 NetworkEndian::writeUint16(payload, mScriptCloseCode);
2104 mOutHeader[1] += 2;
2105 mHdrOutToSend = 4 + maskSize;
2106 if (!mScriptCloseReason.IsEmpty()) {
2107 MOZ_ASSERT(mScriptCloseReason.Length() <= 123,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mScriptCloseReason.Length() <= 123)>::isValid,
"invalid assertion condition"); if ((__builtin_expect(!!(!(!
!(mScriptCloseReason.Length() <= 123))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("mScriptCloseReason.Length() <= 123"
" (" "Close Reason Too Long" ")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 2108); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mScriptCloseReason.Length() <= 123"
") (" "Close Reason Too Long" ")"); do { MOZ_CrashSequence(__null
, 2108); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
2108 "Close Reason Too Long")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mScriptCloseReason.Length() <= 123)>::isValid,
"invalid assertion condition"); if ((__builtin_expect(!!(!(!
!(mScriptCloseReason.Length() <= 123))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("mScriptCloseReason.Length() <= 123"
" (" "Close Reason Too Long" ")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 2108); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mScriptCloseReason.Length() <= 123"
") (" "Close Reason Too Long" ")"); do { MOZ_CrashSequence(__null
, 2108); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
2109 mOutHeader[1] += mScriptCloseReason.Length();
2110 mHdrOutToSend += mScriptCloseReason.Length();
2111 memcpy(payload + 2, mScriptCloseReason.BeginReading(),
2112 mScriptCloseReason.Length());
2113 }
2114 } else {
2115 // No close code/reason, so payload length = 0. We must still send mask
2116 // even though it's not used. Keep payload offset so we write mask
2117 // below.
2118 mHdrOutToSend = 2 + maskSize;
2119 }
2120 } else {
2121 NetworkEndian::writeUint16(payload, ResultToCloseCode(mStopOnClose));
2122 mOutHeader[1] += 2;
2123 mHdrOutToSend = 4 + maskSize;
2124 }
2125
2126 if (mServerClosed) {
2127 /* bidi close complete */
2128 mReleaseOnTransmit = 1;
2129 } else if (NS_FAILED(mStopOnClose)((bool)(__builtin_expect(!!(NS_FAILED_impl(mStopOnClose)), 0)
))
) {
2130 /* result of abort session - give up */
2131 StopSession(mStopOnClose);
2132 } else {
2133 /* wait for reciprocal close from server */
2134 rv = NS_NewTimerWithCallback(getter_AddRefs(mCloseTimer), this,
2135 mCloseTimeout, nsITimer::TYPE_ONE_SHOT);
2136 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
2137 StopSession(rv);
2138 }
2139 }
2140 } else {
2141 switch (msgType) {
2142 case kMsgTypePong:
2143 mOutHeader[0] = kFinalFragBit | nsIWebSocketFrame::OPCODE_PONG;
2144 break;
2145 case kMsgTypePing:
2146 mOutHeader[0] = kFinalFragBit | nsIWebSocketFrame::OPCODE_PING;
2147 break;
2148 case kMsgTypeString:
2149 mOutHeader[0] = kFinalFragBit | nsIWebSocketFrame::OPCODE_TEXT;
2150 break;
2151 case kMsgTypeStream:
2152 // HACK ALERT: read in entire stream into string.
2153 // Will block socket transport thread if file is blocking.
2154 // TODO: bug 704447: don't block socket thread!
2155 rv = mCurrentOut->ConvertStreamToString();
2156 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
2157 AbortSession(NS_ERROR_FILE_TOO_BIG);
2158 return;
2159 }
2160 // Now we're a binary string
2161 msgType = kMsgTypeBinaryString;
2162
2163 // no break: fall down into binary string case
2164 [[fallthrough]];
2165
2166 case kMsgTypeBinaryString:
2167 mOutHeader[0] = kFinalFragBit | nsIWebSocketFrame::OPCODE_BINARY;
2168 break;
2169 case kMsgTypeFin:
2170 MOZ_ASSERT(false, "unreachable")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "unreachable"
")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 2170); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"unreachable" ")"); do { MOZ_CrashSequence(__null, 2170); __attribute__
((nomerge)) ::abort(); } while (false); } } while (false)
; // avoid compiler warning
2171 break;
2172 }
2173
2174 // deflate the payload if PMCE is negotiated
2175 MutexAutoLock lock(mCompressorMutex);
2176 if (mPMCECompressor &&
2177 (msgType == kMsgTypeString || msgType == kMsgTypeBinaryString)) {
2178 if (mCurrentOut->DeflatePayload(mPMCECompressor.get())) {
2179 // The payload was deflated successfully, set RSV1 bit
2180 mOutHeader[0] |= kRsv1Bit;
2181
2182 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::PrimeNewOutgoingMessage %p current msg %p was "
"deflated [origLength=%d, newLength=%d].\n", this, mCurrentOut
, mCurrentOut->OrigLength(), mCurrentOut->Length()); } }
while (0)
2183 ("WebSocketChannel::PrimeNewOutgoingMessage %p current msg %p was "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::PrimeNewOutgoingMessage %p current msg %p was "
"deflated [origLength=%d, newLength=%d].\n", this, mCurrentOut
, mCurrentOut->OrigLength(), mCurrentOut->Length()); } }
while (0)
2184 "deflated [origLength=%d, newLength=%d].\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::PrimeNewOutgoingMessage %p current msg %p was "
"deflated [origLength=%d, newLength=%d].\n", this, mCurrentOut
, mCurrentOut->OrigLength(), mCurrentOut->Length()); } }
while (0)
2185 this, mCurrentOut, mCurrentOut->OrigLength(),do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::PrimeNewOutgoingMessage %p current msg %p was "
"deflated [origLength=%d, newLength=%d].\n", this, mCurrentOut
, mCurrentOut->OrigLength(), mCurrentOut->Length()); } }
while (0)
2186 mCurrentOut->Length()))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::PrimeNewOutgoingMessage %p current msg %p was "
"deflated [origLength=%d, newLength=%d].\n", this, mCurrentOut
, mCurrentOut->OrigLength(), mCurrentOut->Length()); } }
while (0)
;
2187 }
2188 }
2189
2190 if (mCurrentOut->Length() < 126) {
2191 mOutHeader[1] = mCurrentOut->Length() | maskBit;
2192 mHdrOutToSend = 2 + maskSize;
2193 } else if (mCurrentOut->Length() <= 0xffff) {
2194 mOutHeader[1] = 126 | maskBit;
2195 NetworkEndian::writeUint16(mOutHeader + sizeof(uint16_t),
2196 mCurrentOut->Length());
2197 mHdrOutToSend = 4 + maskSize;
2198 } else {
2199 mOutHeader[1] = 127 | maskBit;
2200 NetworkEndian::writeUint64(mOutHeader + 2, mCurrentOut->Length());
2201 mHdrOutToSend = 10 + maskSize;
2202 }
2203 payload = mOutHeader + mHdrOutToSend;
2204 }
2205
2206 MOZ_ASSERT(payload, "payload offset not found")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(payload)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(payload))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("payload" " (" "payload offset not found"
")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 2206); AnnotateMozCrashReason("MOZ_ASSERT" "(" "payload" ") ("
"payload offset not found" ")"); do { MOZ_CrashSequence(__null
, 2206); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
2207
2208 uint32_t mask = 0;
2209 if (!mIsServerSide) {
2210 // Perform the sending mask. Never use a zero mask
2211 do {
2212 static_assert(4 == sizeof(mask), "Size of the mask should be equal to 4");
2213 nsresult rv = mRandomGenerator->GenerateRandomBytesInto(mask);
2214 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
2215 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::PrimeNewOutgoingMessage(): "
"GenerateRandomBytes failure %" "x" "\n", static_cast<uint32_t
>(rv)); } } while (0)
2216 ("WebSocketChannel::PrimeNewOutgoingMessage(): "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::PrimeNewOutgoingMessage(): "
"GenerateRandomBytes failure %" "x" "\n", static_cast<uint32_t
>(rv)); } } while (0)
2217 "GenerateRandomBytes failure %" PRIx32 "\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::PrimeNewOutgoingMessage(): "
"GenerateRandomBytes failure %" "x" "\n", static_cast<uint32_t
>(rv)); } } while (0)
2218 static_cast<uint32_t>(rv)))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::PrimeNewOutgoingMessage(): "
"GenerateRandomBytes failure %" "x" "\n", static_cast<uint32_t
>(rv)); } } while (0)
;
2219 AbortSession(rv);
2220 return;
2221 }
2222 } while (!mask);
2223 NetworkEndian::writeUint32(payload - sizeof(uint32_t), mask);
2224 }
2225
2226 LOG(("WebSocketChannel::PrimeNewOutgoingMessage() using mask %08x\n", mask))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::PrimeNewOutgoingMessage() using mask %08x\n"
, mask); } } while (0)
;
2227
2228 // We don't mask the framing, but occasionally we stick a little payload
2229 // data in the buffer used for the framing. Close frames are the current
2230 // example. This data needs to be masked, but it is never more than a
2231 // handful of bytes and might rotate the mask, so we can just do it locally.
2232 // For real data frames we ship the bulk of the payload off to ApplyMask()
2233
2234 RefPtr<WebSocketFrame> frame = mService->CreateFrameIfNeeded(
2235 mOutHeader[0] & WebSocketChannel::kFinalFragBit,
2236 mOutHeader[0] & WebSocketChannel::kRsv1Bit,
2237 mOutHeader[0] & WebSocketChannel::kRsv2Bit,
2238 mOutHeader[0] & WebSocketChannel::kRsv3Bit,
2239 mOutHeader[0] & WebSocketChannel::kOpcodeBitsMask,
2240 mOutHeader[1] & WebSocketChannel::kMaskBit, mask, payload,
2241 mHdrOutToSend - (payload - mOutHeader), mCurrentOut->BeginOrigReading(),
2242 mCurrentOut->OrigLength());
2243
2244 if (frame) {
2245 mService->FrameSent(mSerial, mInnerWindowID, frame.forget());
2246 }
2247
2248 if (mask) {
2249 while (payload < (mOutHeader + mHdrOutToSend)) {
2250 *payload ^= mask >> 24;
2251 mask = RotateLeft(mask, 8);
2252 payload++;
2253 }
2254
2255 // Mask the real message payloads
2256 ApplyMask(mask, mCurrentOut->BeginWriting(), mCurrentOut->Length());
2257 }
2258
2259 int32_t len = mCurrentOut->Length();
2260
2261 // for small frames, copy it all together for a contiguous write
2262 if (len && len <= kCopyBreak) {
2263 memcpy(mOutHeader + mHdrOutToSend, mCurrentOut->BeginWriting(), len);
2264 mHdrOutToSend += len;
2265 mCurrentOutSent = len;
2266 }
2267
2268 // Transmitting begins - mHdrOutToSend bytes from mOutHeader and
2269 // mCurrentOut->Length() bytes from mCurrentOut. The latter may be
2270 // coaleseced into the former for small messages or as the result of the
2271 // compression process.
2272
2273 cleanupAfterFailure.release();
2274}
2275
2276void WebSocketChannel::DeleteCurrentOutGoingMessage() {
2277 delete mCurrentOut;
2278 mCurrentOut = nullptr;
2279 mCurrentOutSent = 0;
2280}
2281
2282void WebSocketChannel::EnsureHdrOut(uint32_t size) {
2283 LOG(("WebSocketChannel::EnsureHdrOut() %p [%d]\n", this, size))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::EnsureHdrOut() %p [%d]\n"
, this, size); } } while (0)
;
2284
2285 if (mDynamicOutputSize < size) {
2286 mDynamicOutputSize = size;
2287 mDynamicOutput = (uint8_t*)moz_xrealloc(mDynamicOutput, mDynamicOutputSize);
2288 }
2289
2290 mHdrOut = mDynamicOutput;
2291}
2292
2293namespace {
2294
2295class RemoveObserverRunnable : public Runnable {
2296 RefPtr<WebSocketChannel> mChannel;
2297
2298 public:
2299 explicit RemoveObserverRunnable(WebSocketChannel* aChannel)
2300 : Runnable("net::RemoveObserverRunnable"), mChannel(aChannel) {}
2301
2302 NS_IMETHODvirtual nsresult Run() override {
2303 nsCOMPtr<nsIObserverService> observerService =
2304 mozilla::services::GetObserverService();
2305 if (!observerService) {
2306 NS_WARNING("failed to get observer service")NS_DebugBreak(NS_DEBUG_WARNING, "failed to get observer service"
, nullptr, "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 2306)
;
2307 return NS_OK;
2308 }
2309
2310 observerService->RemoveObserver(mChannel, NS_NETWORK_LINK_TOPIC"network:link-status-changed");
2311 return NS_OK;
2312 }
2313};
2314
2315} // namespace
2316
2317void WebSocketChannel::CleanupConnection() {
2318 // normally this should be called on socket thread, but it may be called
2319 // on MainThread
2320
2321 LOG(("WebSocketChannel::CleanupConnection() %p", this))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::CleanupConnection() %p"
, this); } } while (0)
;
2322 // This needs to run on the IOThread so we don't need to lock a bunch of these
2323 if (!mIOThread->IsOnCurrentThread()) {
2324 mIOThread->Dispatch(
2325 NewRunnableMethod("net::WebSocketChannel::CleanupConnection", this,
2326 &WebSocketChannel::CleanupConnection),
2327 NS_DISPATCH_NORMALnsIEventTarget::DISPATCH_NORMAL);
2328 return;
2329 }
2330
2331 if (mLingeringCloseTimer) {
2332 mLingeringCloseTimer->Cancel();
2333 mLingeringCloseTimer = nullptr;
2334 }
2335
2336 if (mSocketIn) {
2337 if (mDataStarted) {
2338 mSocketIn->AsyncWait(nullptr, 0, 0, nullptr);
2339 }
2340 mSocketIn = nullptr;
2341 }
2342
2343 if (mSocketOut) {
2344 mSocketOut->AsyncWait(nullptr, 0, 0, nullptr);
2345 mSocketOut = nullptr;
2346 }
2347
2348 if (mTransport) {
2349 mTransport->SetSecurityCallbacks(nullptr);
2350 mTransport->SetEventSink(nullptr, nullptr);
2351 mTransport->Close(NS_BASE_STREAM_CLOSED);
2352 mTransport = nullptr;
2353 }
2354
2355 if (mConnection) {
2356 mConnection->Close();
2357 mConnection = nullptr;
2358 }
2359
2360 if (mConnectionLogService && !mPrivateBrowsing) {
2361 mConnectionLogService->RemoveHost(mHost, mSerial);
2362 }
2363
2364 // The observer has to be removed on the main-thread.
2365 NS_DispatchToMainThread(new RemoveObserverRunnable(this));
2366
2367 DecrementSessionCount();
2368}
2369
2370void WebSocketChannel::StopSession(nsresult reason) {
2371 LOG(("WebSocketChannel::StopSession() %p [%" PRIx32 "]\n", this,do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::StopSession() %p [%"
"x" "]\n", this, static_cast<uint32_t>(reason)); } } while
(0)
2372 static_cast<uint32_t>(reason)))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::StopSession() %p [%"
"x" "]\n", this, static_cast<uint32_t>(reason)); } } while
(0)
;
2373
2374 {
2375 MutexAutoLock lock(mMutex);
2376 if (mStopped) {
2377 return;
2378 }
2379 mStopped = true;
2380 }
2381
2382 DoStopSession(reason);
2383}
2384
2385void WebSocketChannel::DoStopSession(nsresult reason) {
2386 LOG(("WebSocketChannel::DoStopSession() %p [%" PRIx32 "]\n", this,do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::DoStopSession() %p [%"
"x" "]\n", this, static_cast<uint32_t>(reason)); } } while
(0)
2387 static_cast<uint32_t>(reason)))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::DoStopSession() %p [%"
"x" "]\n", this, static_cast<uint32_t>(reason)); } } while
(0)
;
2388
2389 // normally this should be called on socket thread, but it is ok to call it
2390 // from OnStartRequest before the socket thread machine has gotten underway.
2391 // If mDataStarted is false, this is called on MainThread for Close().
2392 // Otherwise it should be called on the IO thread
2393
2394 MOZ_ASSERT(mStopped)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mStopped)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mStopped))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("mStopped", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 2394); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mStopped" ")"
); do { MOZ_CrashSequence(__null, 2394); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2395 MOZ_ASSERT(mIOThread->IsOnCurrentThread() || mTCPClosed || !mDataStarted)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mIOThread->IsOnCurrentThread() || mTCPClosed || !
mDataStarted)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!(mIOThread->IsOnCurrentThread()
|| mTCPClosed || !mDataStarted))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("mIOThread->IsOnCurrentThread() || mTCPClosed || !mDataStarted"
, "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 2395); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mIOThread->IsOnCurrentThread() || mTCPClosed || !mDataStarted"
")"); do { MOZ_CrashSequence(__null, 2395); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2396
2397 if (!mOpenedHttpChannel) {
2398 // The HTTP channel information will never be used in this case
2399 NS_ReleaseOnMainThread("WebSocketChannel::mChannel", mChannel.forget());
2400 NS_ReleaseOnMainThread("WebSocketChannel::mHttpChannel",
2401 mHttpChannel.forget());
2402 NS_ReleaseOnMainThread("WebSocketChannel::mLoadGroup", mLoadGroup.forget());
2403 NS_ReleaseOnMainThread("WebSocketChannel::mCallbacks", mCallbacks.forget());
2404 }
2405
2406 if (mCloseTimer) {
2407 mCloseTimer->Cancel();
2408 mCloseTimer = nullptr;
2409 }
2410
2411 // mOpenTimer must be null if mDataStarted is true and we're not on MainThread
2412 if (mOpenTimer) {
2413 MOZ_ASSERT(NS_IsMainThread(), "not main thread")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
" (" "not main thread" ")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 2413); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
") (" "not main thread" ")"); do { MOZ_CrashSequence(__null,
2413); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false)
;
2414 mOpenTimer->Cancel();
2415 mOpenTimer = nullptr;
2416 }
2417
2418 {
2419 MutexAutoLock lock(mMutex);
2420 if (mReconnectDelayTimer) {
2421 mReconnectDelayTimer->Cancel();
2422 NS_ReleaseOnMainThread("WebSocketChannel::mMutex",
2423 mReconnectDelayTimer.forget());
2424 }
2425 }
2426
2427 if (mPingTimer) {
2428 mPingTimer->Cancel();
2429 mPingTimer = nullptr;
2430 }
2431
2432 if (!mTCPClosed && mDataStarted) {
2433 if (mSocketIn) {
2434 // Drain, within reason, this socket. if we leave any data
2435 // unconsumed (including the tcp fin) a RST will be generated
2436 // The right thing to do here is shutdown(SHUT_WR) and then wait
2437 // a little while to see if any data comes in.. but there is no
2438 // reason to delay things for that when the websocket handshake
2439 // is supposed to guarantee a quiet connection except for that fin.
2440
2441 char buffer[512];
2442 uint32_t count = 0;
2443 uint32_t total = 0;
2444 nsresult rv;
2445 do {
2446 total += count;
2447 rv = mSocketIn->Read(buffer, 512, &count);
2448 if (rv != NS_BASE_STREAM_WOULD_BLOCK && (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) || count == 0)) {
2449 mTCPClosed = true;
2450 }
2451 } while (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) && count > 0 && total < 32000);
2452 } else if (mConnection) {
2453 mConnection->DrainSocketData();
2454 }
2455 }
2456
2457 int32_t sessionCount = kLingeringCloseThreshold;
2458 nsWSAdmissionManager::GetSessionCount(sessionCount);
2459
2460 if (!mTCPClosed && (mTransport || mConnection) &&
2461 sessionCount < kLingeringCloseThreshold) {
2462 // 7.1.1 says that the client SHOULD wait for the server to close the TCP
2463 // connection. This is so we can reuse port numbers before 2 MSL expires,
2464 // which is not really as much of a concern for us as the amount of state
2465 // that might be accrued by keeping this channel object around waiting for
2466 // the server. We handle the SHOULD by waiting a short time in the common
2467 // case, but not waiting in the case of high concurrency.
2468 //
2469 // Normally this will be taken care of in AbortSession() after mTCPClosed
2470 // is set when the server close arrives without waiting for the timeout to
2471 // expire.
2472
2473 LOG(("WebSocketChannel::DoStopSession: Wait for Server TCP close"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::DoStopSession: Wait for Server TCP close"
); } } while (0)
;
2474
2475 nsresult rv;
2476 rv = NS_NewTimerWithCallback(getter_AddRefs(mLingeringCloseTimer), this,
2477 kLingeringCloseTimeout,
2478 nsITimer::TYPE_ONE_SHOT);
2479 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) CleanupConnection();
2480 } else {
2481 CleanupConnection();
2482 }
2483
2484 {
2485 MutexAutoLock lock(mMutex);
2486 if (mCancelable) {
2487 mCancelable->Cancel(NS_ERROR_UNEXPECTED);
2488 mCancelable = nullptr;
2489 }
2490 }
2491
2492 {
2493 MutexAutoLock lock(mCompressorMutex);
2494 mPMCECompressor = nullptr;
2495 }
2496 if (!mCalledOnStop) {
2497 mCalledOnStop = true;
2498
2499 nsWSAdmissionManager::OnStopSession(this, reason);
2500
2501 RefPtr<CallOnStop> runnable =
2502 new CallOnStop(this, TakeListenerMT(), reason);
2503 if (nsCOMPtr<nsIEventTarget> target = GetTargetThread()) {
2504 target->Dispatch(runnable, NS_DISPATCH_NORMALnsIEventTarget::DISPATCH_NORMAL);
2505 }
2506 }
2507}
2508
2509// Called from MainThread, and called from IOThread in
2510// PrimeNewOutgoingMessage
2511void WebSocketChannel::AbortSession(nsresult reason) {
2512 LOG(("WebSocketChannel::AbortSession() %p [reason %" PRIx32do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::AbortSession() %p [reason %"
"x" "] stopped = %d\n", this, static_cast<uint32_t>(reason
), !!mStopped); } } while (0)
2513 "] stopped = %d\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::AbortSession() %p [reason %"
"x" "] stopped = %d\n", this, static_cast<uint32_t>(reason
), !!mStopped); } } while (0)
2514 this, static_cast<uint32_t>(reason), !!mStopped))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::AbortSession() %p [reason %"
"x" "] stopped = %d\n", this, static_cast<uint32_t>(reason
), !!mStopped); } } while (0)
;
2515
2516 MOZ_ASSERT(NS_FAILED(reason), "reason must be a failure!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(((bool)(__builtin_expect(!!(NS_FAILED_impl(reason)),
0))))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(((bool)(__builtin_expect(!!(NS_FAILED_impl(reason)),
0)))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("((bool)(__builtin_expect(!!(NS_FAILED_impl(reason)), 0)))" " ("
"reason must be a failure!" ")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 2516); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(NS_FAILED_impl(reason)), 0)))"
") (" "reason must be a failure!" ")"); do { MOZ_CrashSequence
(__null, 2516); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2517
2518 // normally this should be called on socket thread, but it is ok to call it
2519 // from the main thread before StartWebsocketData() has completed
2520 MOZ_ASSERT(mIOThread->IsOnCurrentThread() || !mDataStarted)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mIOThread->IsOnCurrentThread() || !mDataStarted)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(mIOThread->IsOnCurrentThread() || !mDataStarted))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("mIOThread->IsOnCurrentThread() || !mDataStarted"
, "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 2520); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mIOThread->IsOnCurrentThread() || !mDataStarted"
")"); do { MOZ_CrashSequence(__null, 2520); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2521
2522 // When we are failing we need to close the TCP connection immediately
2523 // as per 7.1.1
2524 mTCPClosed = true;
2525
2526 if (mLingeringCloseTimer) {
2527 MOZ_ASSERT(mStopped, "Lingering without Stop")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mStopped)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mStopped))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("mStopped" " (" "Lingering without Stop"
")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 2527); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mStopped" ") ("
"Lingering without Stop" ")"); do { MOZ_CrashSequence(__null
, 2527); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
2528 LOG(("WebSocketChannel:: Cleanup connection based on TCP Close"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel:: Cleanup connection based on TCP Close"
); } } while (0)
;
2529 CleanupConnection();
2530 return;
2531 }
2532
2533 {
2534 MutexAutoLock lock(mMutex);
2535 if (mStopped) {
2536 return;
2537 }
2538
2539 if ((mTransport || mConnection) && reason != NS_BASE_STREAM_CLOSED &&
2540 !mRequestedClose && !mClientClosed && !mServerClosed && mDataStarted) {
2541 mRequestedClose = true;
2542 mStopOnClose = reason;
2543 mIOThread->Dispatch(
2544 new OutboundEnqueuer(this,
2545 new OutboundMessage(kMsgTypeFin, VoidCString())),
2546 nsIEventTarget::DISPATCH_NORMAL);
2547 return;
2548 }
2549
2550 mStopped = true;
2551 }
2552
2553 DoStopSession(reason);
2554}
2555
2556// ReleaseSession is called on orderly shutdown
2557void WebSocketChannel::ReleaseSession() {
2558 LOG(("WebSocketChannel::ReleaseSession() %p stopped = %d\n", this,do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::ReleaseSession() %p stopped = %d\n"
, this, !!mStopped); } } while (0)
2559 !!mStopped))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::ReleaseSession() %p stopped = %d\n"
, this, !!mStopped); } } while (0)
;
2560 MOZ_ASSERT(mIOThread->IsOnCurrentThread(), "not on right thread")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mIOThread->IsOnCurrentThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mIOThread->IsOnCurrentThread
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mIOThread->IsOnCurrentThread()" " (" "not on right thread"
")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 2560); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mIOThread->IsOnCurrentThread()"
") (" "not on right thread" ")"); do { MOZ_CrashSequence(__null
, 2560); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
2561
2562 StopSession(NS_OK);
2563}
2564
2565void WebSocketChannel::IncrementSessionCount() {
2566 if (!mIncrementedSessionCount) {
2567 nsWSAdmissionManager::IncrementSessionCount();
2568 mIncrementedSessionCount = true;
2569 }
2570}
2571
2572void WebSocketChannel::DecrementSessionCount() {
2573 // Make sure we decrement session count only once, and only if we incremented
2574 // it. This code is thread-safe: sWebSocketAdmissions->DecrementSessionCount
2575 // is atomic, and mIncrementedSessionCount/mDecrementedSessionCount are set at
2576 // times when they'll never be a race condition for checking/setting them.
2577 if (mIncrementedSessionCount && !mDecrementedSessionCount) {
2578 nsWSAdmissionManager::DecrementSessionCount();
2579 mDecrementedSessionCount = true;
2580 }
2581}
2582
2583namespace {
2584enum ExtensionParseMode { eParseServerSide, eParseClientSide };
2585}
2586
2587static nsresult ParseWebSocketExtension(const nsACString& aExtension,
2588 ExtensionParseMode aMode,
2589 bool& aClientNoContextTakeover,
2590 bool& aServerNoContextTakeover,
2591 int32_t& aClientMaxWindowBits,
2592 int32_t& aServerMaxWindowBits) {
2593 nsCCharSeparatedTokenizer tokens(aExtension, ';');
2594
2595 if (!tokens.hasMoreTokens() ||
2596 !tokens.nextToken().EqualsLiteral("permessage-deflate")) {
2597 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::ParseWebSocketExtension: "
"HTTP Sec-WebSocket-Extensions negotiated unknown value %s\n"
, TPromiseFlatString<char>(aExtension).get()); } } while
(0)
2598 ("WebSocketChannel::ParseWebSocketExtension: "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::ParseWebSocketExtension: "
"HTTP Sec-WebSocket-Extensions negotiated unknown value %s\n"
, TPromiseFlatString<char>(aExtension).get()); } } while
(0)
2599 "HTTP Sec-WebSocket-Extensions negotiated unknown value %s\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::ParseWebSocketExtension: "
"HTTP Sec-WebSocket-Extensions negotiated unknown value %s\n"
, TPromiseFlatString<char>(aExtension).get()); } } while
(0)
2600 PromiseFlatCString(aExtension).get()))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::ParseWebSocketExtension: "
"HTTP Sec-WebSocket-Extensions negotiated unknown value %s\n"
, TPromiseFlatString<char>(aExtension).get()); } } while
(0)
;
2601 return NS_ERROR_ILLEGAL_VALUE;
2602 }
2603
2604 aClientNoContextTakeover = aServerNoContextTakeover = false;
2605 aClientMaxWindowBits = aServerMaxWindowBits = -1;
2606
2607 while (tokens.hasMoreTokens()) {
2608 auto token = tokens.nextToken();
2609
2610 int32_t nameEnd, valueStart;
2611 int32_t delimPos = token.FindChar('=');
2612 if (delimPos == kNotFound) {
2613 nameEnd = token.Length();
2614 valueStart = token.Length();
2615 } else {
2616 nameEnd = delimPos;
2617 valueStart = delimPos + 1;
2618 }
2619
2620 auto paramName = Substring(token, 0, nameEnd);
2621 auto paramValue = Substring(token, valueStart);
2622
2623 if (paramName.EqualsLiteral("client_no_context_takeover")) {
2624 if (!paramValue.IsEmpty()) {
2625 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::ParseWebSocketExtension: parameter "
"client_no_context_takeover must not have value, found %s\n"
, TPromiseFlatString<char>(paramValue).get()); } } while
(0)
2626 ("WebSocketChannel::ParseWebSocketExtension: parameter "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::ParseWebSocketExtension: parameter "
"client_no_context_takeover must not have value, found %s\n"
, TPromiseFlatString<char>(paramValue).get()); } } while
(0)
2627 "client_no_context_takeover must not have value, found %s\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::ParseWebSocketExtension: parameter "
"client_no_context_takeover must not have value, found %s\n"
, TPromiseFlatString<char>(paramValue).get()); } } while
(0)
2628 PromiseFlatCString(paramValue).get()))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::ParseWebSocketExtension: parameter "
"client_no_context_takeover must not have value, found %s\n"
, TPromiseFlatString<char>(paramValue).get()); } } while
(0)
;
2629 return NS_ERROR_ILLEGAL_VALUE;
2630 }
2631 if (aClientNoContextTakeover) {
2632 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::ParseWebSocketExtension: found multiple "
"parameters client_no_context_takeover\n"); } } while (0)
2633 ("WebSocketChannel::ParseWebSocketExtension: found multiple "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::ParseWebSocketExtension: found multiple "
"parameters client_no_context_takeover\n"); } } while (0)
2634 "parameters client_no_context_takeover\n"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::ParseWebSocketExtension: found multiple "
"parameters client_no_context_takeover\n"); } } while (0)
;
2635 return NS_ERROR_ILLEGAL_VALUE;
2636 }
2637 aClientNoContextTakeover = true;
2638 } else if (paramName.EqualsLiteral("server_no_context_takeover")) {
2639 if (!paramValue.IsEmpty()) {
2640 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::ParseWebSocketExtension: parameter "
"server_no_context_takeover must not have value, found %s\n"
, TPromiseFlatString<char>(paramValue).get()); } } while
(0)
2641 ("WebSocketChannel::ParseWebSocketExtension: parameter "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::ParseWebSocketExtension: parameter "
"server_no_context_takeover must not have value, found %s\n"
, TPromiseFlatString<char>(paramValue).get()); } } while
(0)
2642 "server_no_context_takeover must not have value, found %s\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::ParseWebSocketExtension: parameter "
"server_no_context_takeover must not have value, found %s\n"
, TPromiseFlatString<char>(paramValue).get()); } } while
(0)
2643 PromiseFlatCString(paramValue).get()))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::ParseWebSocketExtension: parameter "
"server_no_context_takeover must not have value, found %s\n"
, TPromiseFlatString<char>(paramValue).get()); } } while
(0)
;
2644 return NS_ERROR_ILLEGAL_VALUE;
2645 }
2646 if (aServerNoContextTakeover) {
2647 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::ParseWebSocketExtension: found multiple "
"parameters server_no_context_takeover\n"); } } while (0)
2648 ("WebSocketChannel::ParseWebSocketExtension: found multiple "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::ParseWebSocketExtension: found multiple "
"parameters server_no_context_takeover\n"); } } while (0)
2649 "parameters server_no_context_takeover\n"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::ParseWebSocketExtension: found multiple "
"parameters server_no_context_takeover\n"); } } while (0)
;
2650 return NS_ERROR_ILLEGAL_VALUE;
2651 }
2652 aServerNoContextTakeover = true;
2653 } else if (paramName.EqualsLiteral("client_max_window_bits")) {
2654 if (aClientMaxWindowBits != -1) {
2655 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::ParseWebSocketExtension: found multiple "
"parameters client_max_window_bits\n"); } } while (0)
2656 ("WebSocketChannel::ParseWebSocketExtension: found multiple "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::ParseWebSocketExtension: found multiple "
"parameters client_max_window_bits\n"); } } while (0)
2657 "parameters client_max_window_bits\n"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::ParseWebSocketExtension: found multiple "
"parameters client_max_window_bits\n"); } } while (0)
;
2658 return NS_ERROR_ILLEGAL_VALUE;
2659 }
2660
2661 if (aMode == eParseServerSide && paramValue.IsEmpty()) {
2662 // Use -2 to indicate that "client_max_window_bits" has been parsed,
2663 // but had no value.
2664 aClientMaxWindowBits = -2;
2665 } else {
2666 nsresult errcode;
2667 aClientMaxWindowBits =
2668 PromiseFlatCStringTPromiseFlatString<char>(paramValue).ToInteger(&errcode);
2669 if (NS_FAILED(errcode)((bool)(__builtin_expect(!!(NS_FAILED_impl(errcode)), 0))) || aClientMaxWindowBits < 8 ||
2670 aClientMaxWindowBits > 15) {
2671 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::ParseWebSocketExtension: found invalid "
"parameter client_max_window_bits %s\n", TPromiseFlatString<
char>(paramValue).get()); } } while (0)
2672 ("WebSocketChannel::ParseWebSocketExtension: found invalid "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::ParseWebSocketExtension: found invalid "
"parameter client_max_window_bits %s\n", TPromiseFlatString<
char>(paramValue).get()); } } while (0)
2673 "parameter client_max_window_bits %s\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::ParseWebSocketExtension: found invalid "
"parameter client_max_window_bits %s\n", TPromiseFlatString<
char>(paramValue).get()); } } while (0)
2674 PromiseFlatCString(paramValue).get()))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::ParseWebSocketExtension: found invalid "
"parameter client_max_window_bits %s\n", TPromiseFlatString<
char>(paramValue).get()); } } while (0)
;
2675 return NS_ERROR_ILLEGAL_VALUE;
2676 }
2677 }
2678 } else if (paramName.EqualsLiteral("server_max_window_bits")) {
2679 if (aServerMaxWindowBits != -1) {
2680 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::ParseWebSocketExtension: found multiple "
"parameters server_max_window_bits\n"); } } while (0)
2681 ("WebSocketChannel::ParseWebSocketExtension: found multiple "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::ParseWebSocketExtension: found multiple "
"parameters server_max_window_bits\n"); } } while (0)
2682 "parameters server_max_window_bits\n"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::ParseWebSocketExtension: found multiple "
"parameters server_max_window_bits\n"); } } while (0)
;
2683 return NS_ERROR_ILLEGAL_VALUE;
2684 }
2685
2686 nsresult errcode;
2687 aServerMaxWindowBits = PromiseFlatCStringTPromiseFlatString<char>(paramValue).ToInteger(&errcode);
2688 if (NS_FAILED(errcode)((bool)(__builtin_expect(!!(NS_FAILED_impl(errcode)), 0))) || aServerMaxWindowBits < 8 ||
2689 aServerMaxWindowBits > 15) {
2690 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::ParseWebSocketExtension: found invalid "
"parameter server_max_window_bits %s\n", TPromiseFlatString<
char>(paramValue).get()); } } while (0)
2691 ("WebSocketChannel::ParseWebSocketExtension: found invalid "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::ParseWebSocketExtension: found invalid "
"parameter server_max_window_bits %s\n", TPromiseFlatString<
char>(paramValue).get()); } } while (0)
2692 "parameter server_max_window_bits %s\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::ParseWebSocketExtension: found invalid "
"parameter server_max_window_bits %s\n", TPromiseFlatString<
char>(paramValue).get()); } } while (0)
2693 PromiseFlatCString(paramValue).get()))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::ParseWebSocketExtension: found invalid "
"parameter server_max_window_bits %s\n", TPromiseFlatString<
char>(paramValue).get()); } } while (0)
;
2694 return NS_ERROR_ILLEGAL_VALUE;
2695 }
2696 } else {
2697 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::ParseWebSocketExtension: found unknown "
"parameter %s\n", TPromiseFlatString<char>(paramName).
get()); } } while (0)
2698 ("WebSocketChannel::ParseWebSocketExtension: found unknown "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::ParseWebSocketExtension: found unknown "
"parameter %s\n", TPromiseFlatString<char>(paramName).
get()); } } while (0)
2699 "parameter %s\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::ParseWebSocketExtension: found unknown "
"parameter %s\n", TPromiseFlatString<char>(paramName).
get()); } } while (0)
2700 PromiseFlatCString(paramName).get()))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::ParseWebSocketExtension: found unknown "
"parameter %s\n", TPromiseFlatString<char>(paramName).
get()); } } while (0)
;
2701 return NS_ERROR_ILLEGAL_VALUE;
2702 }
2703 }
2704
2705 if (aClientMaxWindowBits == -2) {
2706 aClientMaxWindowBits = -1;
2707 }
2708
2709 return NS_OK;
2710}
2711
2712nsresult WebSocketChannel::HandleExtensions() {
2713 LOG(("WebSocketChannel::HandleExtensions() %p\n", this))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::HandleExtensions() %p\n"
, this); } } while (0)
;
2714
2715 nsresult rv;
2716 nsAutoCString extensions;
2717
2718 MOZ_ASSERT(NS_IsMainThread(), "not main thread")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
" (" "not main thread" ")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 2718); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
") (" "not main thread" ")"); do { MOZ_CrashSequence(__null,
2718); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false)
;
2719
2720 rv = mHttpChannel->GetResponseHeader("Sec-WebSocket-Extensions"_ns,
Value stored to 'rv' is never read
2721 extensions);
2722 extensions.CompressWhitespace();
2723 if (extensions.IsEmpty()) {
2724 return NS_OK;
2725 }
2726
2727 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::HandleExtensions: received "
"Sec-WebSocket-Extensions header: %s\n", extensions.get()); }
} while (0)
2728 ("WebSocketChannel::HandleExtensions: received "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::HandleExtensions: received "
"Sec-WebSocket-Extensions header: %s\n", extensions.get()); }
} while (0)
2729 "Sec-WebSocket-Extensions header: %s\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::HandleExtensions: received "
"Sec-WebSocket-Extensions header: %s\n", extensions.get()); }
} while (0)
2730 extensions.get()))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::HandleExtensions: received "
"Sec-WebSocket-Extensions header: %s\n", extensions.get()); }
} while (0)
;
2731
2732 bool clientNoContextTakeover;
2733 bool serverNoContextTakeover;
2734 int32_t clientMaxWindowBits;
2735 int32_t serverMaxWindowBits;
2736
2737 rv = ParseWebSocketExtension(extensions, eParseClientSide,
2738 clientNoContextTakeover, serverNoContextTakeover,
2739 clientMaxWindowBits, serverMaxWindowBits);
2740 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
2741 AbortSession(rv);
2742 return rv;
2743 }
2744
2745 if (clientMaxWindowBits == -1) {
2746 clientMaxWindowBits = 15;
2747 }
2748 if (serverMaxWindowBits == -1) {
2749 serverMaxWindowBits = 15;
2750 }
2751
2752 MutexAutoLock lock(mCompressorMutex);
2753 mPMCECompressor = MakeUnique<PMCECompression>(
2754 clientNoContextTakeover, clientMaxWindowBits, serverMaxWindowBits);
2755 if (mPMCECompressor->Active()) {
2756 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::HandleExtensions: PMCE negotiated, %susing "
"context takeover, clientMaxWindowBits=%d, " "serverMaxWindowBits=%d\n"
, clientNoContextTakeover ? "NOT " : "", clientMaxWindowBits,
serverMaxWindowBits); } } while (0)
2757 ("WebSocketChannel::HandleExtensions: PMCE negotiated, %susing "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::HandleExtensions: PMCE negotiated, %susing "
"context takeover, clientMaxWindowBits=%d, " "serverMaxWindowBits=%d\n"
, clientNoContextTakeover ? "NOT " : "", clientMaxWindowBits,
serverMaxWindowBits); } } while (0)
2758 "context takeover, clientMaxWindowBits=%d, "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::HandleExtensions: PMCE negotiated, %susing "
"context takeover, clientMaxWindowBits=%d, " "serverMaxWindowBits=%d\n"
, clientNoContextTakeover ? "NOT " : "", clientMaxWindowBits,
serverMaxWindowBits); } } while (0)
2759 "serverMaxWindowBits=%d\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::HandleExtensions: PMCE negotiated, %susing "
"context takeover, clientMaxWindowBits=%d, " "serverMaxWindowBits=%d\n"
, clientNoContextTakeover ? "NOT " : "", clientMaxWindowBits,
serverMaxWindowBits); } } while (0)
2760 clientNoContextTakeover ? "NOT " : "", clientMaxWindowBits,do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::HandleExtensions: PMCE negotiated, %susing "
"context takeover, clientMaxWindowBits=%d, " "serverMaxWindowBits=%d\n"
, clientNoContextTakeover ? "NOT " : "", clientMaxWindowBits,
serverMaxWindowBits); } } while (0)
2761 serverMaxWindowBits))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::HandleExtensions: PMCE negotiated, %susing "
"context takeover, clientMaxWindowBits=%d, " "serverMaxWindowBits=%d\n"
, clientNoContextTakeover ? "NOT " : "", clientMaxWindowBits,
serverMaxWindowBits); } } while (0)
;
2762
2763 mNegotiatedExtensions = "permessage-deflate";
2764 } else {
2765 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::HandleExtensions: Cannot init PMCE "
"compression object\n"); } } while (0)
2766 ("WebSocketChannel::HandleExtensions: Cannot init PMCE "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::HandleExtensions: Cannot init PMCE "
"compression object\n"); } } while (0)
2767 "compression object\n"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::HandleExtensions: Cannot init PMCE "
"compression object\n"); } } while (0)
;
2768 mPMCECompressor = nullptr;
2769 AbortSession(NS_ERROR_UNEXPECTED);
2770 return NS_ERROR_UNEXPECTED;
2771 }
2772
2773 return NS_OK;
2774}
2775
2776void ProcessServerWebSocketExtensions(const nsACString& aExtensions,
2777 nsACString& aNegotiatedExtensions) {
2778 aNegotiatedExtensions.Truncate();
2779
2780 for (const auto& ext :
2781 nsCCharSeparatedTokenizer(aExtensions, ',').ToRange()) {
2782 bool clientNoContextTakeover;
2783 bool serverNoContextTakeover;
2784 int32_t clientMaxWindowBits;
2785 int32_t serverMaxWindowBits;
2786
2787 nsresult rv = ParseWebSocketExtension(
2788 ext, eParseServerSide, clientNoContextTakeover, serverNoContextTakeover,
2789 clientMaxWindowBits, serverMaxWindowBits);
2790 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
2791 // Ignore extensions that we can't parse
2792 continue;
2793 }
2794
2795 aNegotiatedExtensions.AssignLiteral("permessage-deflate");
2796 if (clientNoContextTakeover) {
2797 aNegotiatedExtensions.AppendLiteral(";client_no_context_takeover");
2798 }
2799 if (serverNoContextTakeover) {
2800 aNegotiatedExtensions.AppendLiteral(";server_no_context_takeover");
2801 }
2802 if (clientMaxWindowBits != -1) {
2803 aNegotiatedExtensions.AppendLiteral(";client_max_window_bits=");
2804 aNegotiatedExtensions.AppendInt(clientMaxWindowBits);
2805 }
2806 if (serverMaxWindowBits != -1) {
2807 aNegotiatedExtensions.AppendLiteral(";server_max_window_bits=");
2808 aNegotiatedExtensions.AppendInt(serverMaxWindowBits);
2809 }
2810
2811 return;
2812 }
2813}
2814
2815nsresult CalculateWebSocketHashedSecret(const nsACString& aKey,
2816 nsACString& aHash) {
2817 nsresult rv;
2818 nsCString key = aKey + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"_ns;
2819 nsCOMPtr<nsICryptoHash> hasher =
2820 do_CreateInstance(NS_CRYPTO_HASH_CONTRACTID"@mozilla.org/security/hash;1", &rv);
2821 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 2821); return rv; } } while (false)
;
2822 rv = hasher->Init(nsICryptoHash::SHA1);
2823 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 2823); return rv; } } while (false)
;
2824 rv = hasher->Update((const uint8_t*)key.BeginWriting(), key.Length());
2825 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 2825); return rv; } } while (false)
;
2826 return hasher->Finish(true, aHash);
2827}
2828
2829nsresult WebSocketChannel::SetupRequest() {
2830 LOG(("WebSocketChannel::SetupRequest() %p\n", this))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::SetupRequest() %p\n"
, this); } } while (0)
;
2831
2832 nsresult rv;
2833
2834 if (mLoadGroup) {
2835 rv = mHttpChannel->SetLoadGroup(mLoadGroup);
2836 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 2836); return rv; } } while (false)
;
2837 }
2838
2839 rv = mHttpChannel->SetLoadFlags(
2840 nsIRequest::LOAD_BACKGROUND | nsIRequest::INHIBIT_CACHING |
2841 nsIRequest::LOAD_BYPASS_CACHE | nsIChannel::LOAD_BYPASS_SERVICE_WORKER);
2842 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 2842); return rv; } } while (false)
;
2843
2844 // we never let websockets be blocked by head CSS/JS loads to avoid
2845 // potential deadlock where server generation of CSS/JS requires
2846 // an XHR signal.
2847 nsCOMPtr<nsIClassOfService> cos(do_QueryInterface(mChannel));
2848 if (cos) {
2849 cos->AddClassFlags(nsIClassOfService::Unblocked);
2850 }
2851
2852 // draft-ietf-hybi-thewebsocketprotocol-07 illustrates Upgrade: websocket
2853 // in lower case, so go with that. It is technically case insensitive.
2854 rv = mChannel->HTTPUpgrade("websocket"_ns, this);
2855 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 2855); return rv; } } while (false)
;
2856
2857 rv = mHttpChannel->SetRequestHeader("Sec-WebSocket-Version"_ns,
2858 nsLiteralCString(SEC_WEBSOCKET_VERSION"13"),
2859 false);
2860 MOZ_ASSERT(NS_SUCCEEDED(rv))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
)))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 2860); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))"
")"); do { MOZ_CrashSequence(__null, 2860); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2861
2862 if (!mOrigin.IsEmpty()) {
2863 rv = mHttpChannel->SetRequestHeader("Origin"_ns, mOrigin, false);
2864 MOZ_ASSERT(NS_SUCCEEDED(rv))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
)))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 2864); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))"
")"); do { MOZ_CrashSequence(__null, 2864); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2865 }
2866
2867 if (!mProtocol.IsEmpty()) {
2868 rv = mHttpChannel->SetRequestHeader("Sec-WebSocket-Protocol"_ns, mProtocol,
2869 true);
2870 MOZ_ASSERT(NS_SUCCEEDED(rv))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
)))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 2870); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))"
")"); do { MOZ_CrashSequence(__null, 2870); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2871 }
2872
2873 rv = mHttpChannel->SetRequestHeader("Sec-WebSocket-Extensions"_ns,
2874 "permessage-deflate"_ns, false);
2875 MOZ_ASSERT(NS_SUCCEEDED(rv))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
)))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 2875); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))"
")"); do { MOZ_CrashSequence(__null, 2875); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2876
2877 uint8_t* secKey;
2878 nsAutoCString secKeyString;
2879
2880 rv = mRandomGenerator->GenerateRandomBytes(16, &secKey);
2881 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 2881); return rv; } } while (false)
;
2882 rv = Base64Encode(reinterpret_cast<const char*>(secKey), 16, secKeyString);
2883 free(secKey);
2884 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
2885 return rv;
2886 }
2887
2888 rv = mHttpChannel->SetRequestHeader("Sec-WebSocket-Key"_ns, secKeyString,
2889 false);
2890 MOZ_ASSERT(NS_SUCCEEDED(rv))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
)))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 2890); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))"
")"); do { MOZ_CrashSequence(__null, 2890); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2891 LOG(("WebSocketChannel::SetupRequest: client key %s\n", secKeyString.get()))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::SetupRequest: client key %s\n"
, secKeyString.get()); } } while (0)
;
2892
2893 // prepare the value we expect to see in
2894 // the sec-websocket-accept response header
2895 rv = CalculateWebSocketHashedSecret(secKeyString, mHashedSecret);
2896 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 2896); return rv; } } while (false)
;
2897 LOG(("WebSocketChannel::SetupRequest: expected server key %s\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::SetupRequest: expected server key %s\n"
, mHashedSecret.get()); } } while (0)
2898 mHashedSecret.get()))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::SetupRequest: expected server key %s\n"
, mHashedSecret.get()); } } while (0)
;
2899
2900 mHttpChannelId = mHttpChannel->ChannelId();
2901
2902 return NS_OK;
2903}
2904
2905nsresult WebSocketChannel::DoAdmissionDNS() {
2906 nsresult rv;
2907
2908 nsCString hostName;
2909 rv = mURI->GetHost(hostName);
2910 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 2910); return rv; } } while (false)
;
2911 mAddress = hostName;
2912 nsCString path;
2913 rv = mURI->GetFilePath(path);
2914 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 2914); return rv; } } while (false)
;
2915 mPath = std::move(path);
2916 rv = mURI->GetPort(&mPort);
2917 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 2917); return rv; } } while (false)
;
2918 if (mPort == -1) mPort = (mEncrypted ? kDefaultWSSPort : kDefaultWSPort);
2919 nsCOMPtr<nsIDNSService> dns;
2920 dns = mozilla::components::DNS::Service(&rv);
2921 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 2921); return rv; } } while (false)
;
2922 nsCOMPtr<nsIEventTarget> main = GetMainThreadSerialEventTarget();
2923 nsCOMPtr<nsICancelable> cancelable;
2924 rv = dns->AsyncResolveNative(hostName, nsIDNSService::RESOLVE_TYPE_DEFAULT,
2925 nsIDNSService::RESOLVE_DEFAULT_FLAGS, nullptr,
2926 this, main, mLoadInfo->GetOriginAttributes(),
2927 getter_AddRefs(cancelable));
2928 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
2929 return rv;
2930 }
2931
2932 MutexAutoLock lock(mMutex);
2933 MOZ_ASSERT(!mCancelable)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mCancelable)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mCancelable))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("!mCancelable", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 2933); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mCancelable"
")"); do { MOZ_CrashSequence(__null, 2933); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2934 mCancelable = std::move(cancelable);
2935 return rv;
2936}
2937
2938nsresult WebSocketChannel::ApplyForAdmission() {
2939 LOG(("WebSocketChannel::ApplyForAdmission() %p\n", this))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::ApplyForAdmission() %p\n"
, this); } } while (0)
;
2940
2941 // Websockets has a policy of 1 session at a time being allowed in the
2942 // CONNECTING state per server IP address (not hostname)
2943
2944 // Check to see if a proxy is being used before making DNS call
2945 nsCOMPtr<nsIProtocolProxyService> pps;
2946 pps = mozilla::components::ProtocolProxy::Service();
2947
2948 if (!pps) {
2949 // go straight to DNS
2950 // expect the callback in ::OnLookupComplete
2951 LOG((do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::ApplyForAdmission: checking for concurrent open\n"
); } } while (0)
2952 "WebSocketChannel::ApplyForAdmission: checking for concurrent open\n"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::ApplyForAdmission: checking for concurrent open\n"
); } } while (0)
;
2953 return DoAdmissionDNS();
2954 }
2955
2956 nsresult rv;
2957 nsCOMPtr<nsICancelable> cancelable;
2958 rv = pps->AsyncResolve(
2959 mHttpChannel,
2960 nsIProtocolProxyService::RESOLVE_PREFER_SOCKS_PROXY |
2961 nsIProtocolProxyService::RESOLVE_PREFER_HTTPS_PROXY |
2962 nsIProtocolProxyService::RESOLVE_ALWAYS_TUNNEL,
2963 this, nullptr, getter_AddRefs(cancelable));
2964
2965 MutexAutoLock lock(mMutex);
2966 MOZ_ASSERT(!mCancelable)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mCancelable)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mCancelable))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("!mCancelable", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 2966); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mCancelable"
")"); do { MOZ_CrashSequence(__null, 2966); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2967 mCancelable = std::move(cancelable);
2968 return rv;
2969}
2970
2971// Called after both OnStartRequest and OnTransportAvailable have
2972// executed. This essentially ends the handshake and starts the websockets
2973// protocol state machine.
2974nsresult WebSocketChannel::CallStartWebsocketData() {
2975 LOG(("WebSocketChannel::CallStartWebsocketData() %p", this))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::CallStartWebsocketData() %p"
, this); } } while (0)
;
2976 MOZ_ASSERT(NS_IsMainThread(), "not main thread")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
" (" "not main thread" ")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 2976); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
") (" "not main thread" ")"); do { MOZ_CrashSequence(__null,
2976); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false)
;
2977
2978 if (mOpenTimer) {
2979 mOpenTimer->Cancel();
2980 mOpenTimer = nullptr;
2981 }
2982
2983 nsCOMPtr<nsIEventTarget> target = GetTargetThread();
2984 if (target && !target->IsOnCurrentThread()) {
2985 return target->Dispatch(
2986 NewRunnableMethod("net::WebSocketChannel::StartWebsocketData", this,
2987 &WebSocketChannel::StartWebsocketData),
2988 NS_DISPATCH_NORMALnsIEventTarget::DISPATCH_NORMAL);
2989 }
2990
2991 return StartWebsocketData();
2992}
2993
2994nsresult WebSocketChannel::StartWebsocketData() {
2995 {
2996 MutexAutoLock lock(mMutex);
2997 LOG(("WebSocketChannel::StartWebsocketData() %p", this))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::StartWebsocketData() %p"
, this); } } while (0)
;
2998 MOZ_ASSERT(!mDataStarted, "StartWebsocketData twice")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mDataStarted)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mDataStarted))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("!mDataStarted" " ("
"StartWebsocketData twice" ")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 2998); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mDataStarted"
") (" "StartWebsocketData twice" ")"); do { MOZ_CrashSequence
(__null, 2998); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2999
3000 if (mStopped) {
3001 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::StartWebsocketData channel already closed, not "
"starting data"); } } while (0)
3002 ("WebSocketChannel::StartWebsocketData channel already closed, not "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::StartWebsocketData channel already closed, not "
"starting data"); } } while (0)
3003 "starting data"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::StartWebsocketData channel already closed, not "
"starting data"); } } while (0)
;
3004 return NS_ERROR_NOT_AVAILABLE;
3005 }
3006 }
3007
3008 RefPtr<WebSocketChannel> self = this;
3009 mIOThread->Dispatch(NS_NewRunnableFunction(
3010 "WebSocketChannel::StartWebsocketData", [self{std::move(self)}] {
3011 LOG(("WebSocketChannel::DoStartWebsocketData() %p", self.get()))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::DoStartWebsocketData() %p"
, self.get()); } } while (0)
;
3012 {
3013 MutexAutoLock lock(self->mMutex);
3014 if (self->mStopped) {
3015 return;
3016 }
3017 self->mDataStarted = true;
3018 }
3019
3020 NS_DispatchToMainThread(
3021 NewRunnableMethod("net::WebSocketChannel::NotifyOnStart", self,
3022 &WebSocketChannel::NotifyOnStart),
3023 NS_DISPATCH_NORMALnsIEventTarget::DISPATCH_NORMAL);
3024
3025 nsresult rv = self->mConnection ? self->mConnection->StartReading()
3026 : self->mSocketIn->AsyncWait(
3027 self, 0, 0, self->mIOThread);
3028 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
3029 self->AbortSession(rv);
3030 }
3031
3032 if (self->mPingInterval) {
3033 rv = self->StartPinging();
3034 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
3035 LOG((do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::StartWebsocketData Could not start pinging, "
"rv=0x%08" "x", static_cast<uint32_t>(rv)); } } while (
0)
3036 "WebSocketChannel::StartWebsocketData Could not start pinging, "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::StartWebsocketData Could not start pinging, "
"rv=0x%08" "x", static_cast<uint32_t>(rv)); } } while (
0)
3037 "rv=0x%08" PRIx32,do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::StartWebsocketData Could not start pinging, "
"rv=0x%08" "x", static_cast<uint32_t>(rv)); } } while (
0)
3038 static_cast<uint32_t>(rv)))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::StartWebsocketData Could not start pinging, "
"rv=0x%08" "x", static_cast<uint32_t>(rv)); } } while (
0)
;
3039 self->AbortSession(rv);
3040 }
3041 }
3042 }));
3043
3044 return NS_OK;
3045}
3046
3047void WebSocketChannel::NotifyOnStart() {
3048 RefPtr<BaseWebSocketChannel::ListenerAndContextContainer> listener =
3049 GetListenerMT();
3050 LOG(("WebSocketChannel::NotifyOnStart Notifying Listener %p",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::NotifyOnStart Notifying Listener %p"
, listener ? listener->mListener.get() : nullptr); } } while
(0)
3051 listener ? listener->mListener.get() : nullptr))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::NotifyOnStart Notifying Listener %p"
, listener ? listener->mListener.get() : nullptr); } } while
(0)
;
3052 if (listener) {
3053 nsresult rv = listener->mListener->OnStart(listener->mContext);
3054 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
3055 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::NotifyOnStart "
"listener->mListener->OnStart() failed with error 0x%08"
"x", static_cast<uint32_t>(rv)); } } while (0)
3056 ("WebSocketChannel::NotifyOnStart "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::NotifyOnStart "
"listener->mListener->OnStart() failed with error 0x%08"
"x", static_cast<uint32_t>(rv)); } } while (0)
3057 "listener->mListener->OnStart() failed with error 0x%08" PRIx32,do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::NotifyOnStart "
"listener->mListener->OnStart() failed with error 0x%08"
"x", static_cast<uint32_t>(rv)); } } while (0)
3058 static_cast<uint32_t>(rv)))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::NotifyOnStart "
"listener->mListener->OnStart() failed with error 0x%08"
"x", static_cast<uint32_t>(rv)); } } while (0)
;
3059 }
3060 }
3061}
3062
3063nsresult WebSocketChannel::StartPinging() {
3064 LOG(("WebSocketChannel::StartPinging() %p", this))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::StartPinging() %p"
, this); } } while (0)
;
3065 MOZ_ASSERT(mIOThread->IsOnCurrentThread(), "not on right thread")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mIOThread->IsOnCurrentThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mIOThread->IsOnCurrentThread
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mIOThread->IsOnCurrentThread()" " (" "not on right thread"
")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 3065); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mIOThread->IsOnCurrentThread()"
") (" "not on right thread" ")"); do { MOZ_CrashSequence(__null
, 3065); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
3066 MOZ_ASSERT(mPingInterval)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mPingInterval)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mPingInterval))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("mPingInterval",
"./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 3066); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mPingInterval"
")"); do { MOZ_CrashSequence(__null, 3066); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3067 MOZ_ASSERT(!mPingTimer)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mPingTimer)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mPingTimer))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("!mPingTimer", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 3067); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mPingTimer"
")"); do { MOZ_CrashSequence(__null, 3067); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3068
3069 nsresult rv;
3070 rv = NS_NewTimerWithCallback(getter_AddRefs(mPingTimer), this, mPingInterval,
3071 nsITimer::TYPE_ONE_SHOT);
3072 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
3073 LOG(("WebSocketChannel will generate ping after %d ms of receive silence\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel will generate ping after %d ms of receive silence\n"
, (uint32_t)mPingInterval); } } while (0)
3074 (uint32_t)mPingInterval))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel will generate ping after %d ms of receive silence\n"
, (uint32_t)mPingInterval); } } while (0)
;
3075 } else {
3076 NS_WARNING("unable to create ping timer. Carrying on.")NS_DebugBreak(NS_DEBUG_WARNING, "unable to create ping timer. Carrying on."
, nullptr, "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 3076)
;
3077 }
3078
3079 return NS_OK;
3080}
3081
3082void WebSocketChannel::ReportConnectionTelemetry(nsresult aStatusCode) {
3083 // 3 bits are used. high bit is for wss, middle bit for failed,
3084 // and low bit for proxy..
3085 // 0 - 7 : ws-ok-plain, ws-ok-proxy, ws-failed-plain, ws-failed-proxy,
3086 // wss-ok-plain, wss-ok-proxy, wss-failed-plain, wss-failed-proxy
3087
3088 bool didProxy = false;
3089
3090 nsCOMPtr<nsIProxyInfo> pi;
3091 nsCOMPtr<nsIProxiedChannel> pc = do_QueryInterface(mChannel);
3092 if (pc) pc->GetProxyInfo(getter_AddRefs(pi));
3093 if (pi) {
3094 nsAutoCString proxyType;
3095 pi->GetType(proxyType);
3096 if (!proxyType.IsEmpty() && !proxyType.EqualsLiteral("direct")) {
3097 didProxy = true;
3098 }
3099 }
3100
3101 uint8_t value =
3102 (mEncrypted ? (1 << 2) : 0) |
3103 (!(mGotUpgradeOK && NS_SUCCEEDED(aStatusCode)((bool)(__builtin_expect(!!(!NS_FAILED_impl(aStatusCode)), 1)
))
) ? (1 << 1) : 0) |
3104 (didProxy ? (1 << 0) : 0);
3105
3106 LOG(("WebSocketChannel::ReportConnectionTelemetry() %p %d", this, value))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::ReportConnectionTelemetry() %p %d"
, this, value); } } while (0)
;
3107 glean::websockets::handshake_type.AccumulateSingleSample(value);
3108}
3109
3110// nsIDNSListener
3111
3112NS_IMETHODIMPnsresult
3113WebSocketChannel::OnLookupComplete(nsICancelable* aRequest,
3114 nsIDNSRecord* aRecord, nsresult aStatus) {
3115 LOG(("WebSocketChannel::OnLookupComplete() %p [%p %p %" PRIx32 "]\n", this,do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OnLookupComplete() %p [%p %p %"
"x" "]\n", this, aRequest, aRecord, static_cast<uint32_t>
(aStatus)); } } while (0)
3116 aRequest, aRecord, static_cast<uint32_t>(aStatus)))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OnLookupComplete() %p [%p %p %"
"x" "]\n", this, aRequest, aRecord, static_cast<uint32_t>
(aStatus)); } } while (0)
;
3117
3118 MOZ_ASSERT(NS_IsMainThread(), "not main thread")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
" (" "not main thread" ")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 3118); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
") (" "not main thread" ")"); do { MOZ_CrashSequence(__null,
3118); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false)
;
3119
3120 {
3121 MutexAutoLock lock(mMutex);
3122 mCancelable = nullptr;
3123 }
3124
3125 if (mStopped) {
3126 LOG(("WebSocketChannel::OnLookupComplete: Request Already Stopped\n"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OnLookupComplete: Request Already Stopped\n"
); } } while (0)
;
3127 return NS_OK;
3128 }
3129
3130 // These failures are not fatal - we just use the hostname as the key
3131 if (NS_FAILED(aStatus)((bool)(__builtin_expect(!!(NS_FAILED_impl(aStatus)), 0)))) {
3132 LOG(("WebSocketChannel::OnLookupComplete: No DNS Response\n"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OnLookupComplete: No DNS Response\n"
); } } while (0)
;
3133
3134 // set host in case we got here without calling DoAdmissionDNS()
3135 mURI->GetHost(mAddress);
3136 } else {
3137 nsCOMPtr<nsIDNSAddrRecord> record = do_QueryInterface(aRecord);
3138 MOZ_ASSERT(record)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(record)>::isValid, "invalid assertion condition")
; if ((__builtin_expect(!!(!(!!(record))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("record", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 3138); AnnotateMozCrashReason("MOZ_ASSERT" "(" "record" ")"
); do { MOZ_CrashSequence(__null, 3138); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3139 nsresult rv = record->GetNextAddrAsString(mAddress);
3140 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
3141 LOG(("WebSocketChannel::OnLookupComplete: Failed GetNextAddr\n"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OnLookupComplete: Failed GetNextAddr\n"
); } } while (0)
;
3142 }
3143 }
3144
3145 LOG(("WebSocket OnLookupComplete: Proceeding to ConditionallyConnect\n"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocket OnLookupComplete: Proceeding to ConditionallyConnect\n"
); } } while (0)
;
3146 nsWSAdmissionManager::ConditionallyConnect(this);
3147
3148 return NS_OK;
3149}
3150
3151// nsIProtocolProxyCallback
3152NS_IMETHODIMPnsresult
3153WebSocketChannel::OnProxyAvailable(nsICancelable* aRequest,
3154 nsIChannel* aChannel, nsIProxyInfo* pi,
3155 nsresult status) {
3156 {
3157 MutexAutoLock lock(mMutex);
3158 MOZ_ASSERT(!mCancelable || (aRequest == mCancelable))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mCancelable || (aRequest == mCancelable))>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!(!mCancelable || (aRequest == mCancelable)))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("!mCancelable || (aRequest == mCancelable)"
, "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 3158); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mCancelable || (aRequest == mCancelable)"
")"); do { MOZ_CrashSequence(__null, 3158); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3159 mCancelable = nullptr;
3160 }
3161
3162 if (mStopped) {
3163 LOG(("WebSocketChannel::OnProxyAvailable: [%p] Request Already Stopped\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OnProxyAvailable: [%p] Request Already Stopped\n"
, this); } } while (0)
3164 this))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OnProxyAvailable: [%p] Request Already Stopped\n"
, this); } } while (0)
;
3165 return NS_OK;
3166 }
3167
3168 nsAutoCString type;
3169 if (NS_SUCCEEDED(status)((bool)(__builtin_expect(!!(!NS_FAILED_impl(status)), 1))) && pi && NS_SUCCEEDED(pi->GetType(type))((bool)(__builtin_expect(!!(!NS_FAILED_impl(pi->GetType(type
))), 1)))
&&
3170 !type.EqualsLiteral("direct")) {
3171 LOG(("WebSocket OnProxyAvailable [%p] Proxy found skip DNS lookup\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocket OnProxyAvailable [%p] Proxy found skip DNS lookup\n"
, this); } } while (0)
3172 this))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocket OnProxyAvailable [%p] Proxy found skip DNS lookup\n"
, this); } } while (0)
;
3173 // call DNS callback directly without DNS resolver
3174 OnLookupComplete(nullptr, nullptr, NS_ERROR_FAILURE);
3175 } else {
3176 LOG(("WebSocketChannel::OnProxyAvailable[%p] checking DNS resolution\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OnProxyAvailable[%p] checking DNS resolution\n"
, this); } } while (0)
3177 this))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OnProxyAvailable[%p] checking DNS resolution\n"
, this); } } while (0)
;
3178 nsresult rv = DoAdmissionDNS();
3179 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
3180 LOG(("WebSocket OnProxyAvailable [%p] DNS lookup failed\n", this))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocket OnProxyAvailable [%p] DNS lookup failed\n"
, this); } } while (0)
;
3181 // call DNS callback directly without DNS resolver
3182 OnLookupComplete(nullptr, nullptr, NS_ERROR_FAILURE);
3183 }
3184 }
3185
3186 // notify listener of OnProxyAvailable
3187 RefPtr<BaseWebSocketChannel::ListenerAndContextContainer> listener =
3188 GetListenerMT();
3189 LOG(("WebSocketChannel::OnProxyAvailable Notifying Listener %p",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OnProxyAvailable Notifying Listener %p"
, listener ? listener->mListener.get() : nullptr); } } while
(0)
3190 listener ? listener->mListener.get() : nullptr))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OnProxyAvailable Notifying Listener %p"
, listener ? listener->mListener.get() : nullptr); } } while
(0)
;
3191 if (!listener) {
3192 return NS_OK;
3193 }
3194 nsresult rv;
3195 nsCOMPtr<nsIProtocolProxyCallback> ppc(
3196 do_QueryInterface(listener->mListener, &rv));
3197 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
3198 rv = ppc->OnProxyAvailable(aRequest, aChannel, pi, status);
3199 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
3200 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OnProxyAvailable notify"
" failed with error 0x%08" "x", static_cast<uint32_t>(
rv)); } } while (0)
3201 ("WebSocketChannel::OnProxyAvailable notify"do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OnProxyAvailable notify"
" failed with error 0x%08" "x", static_cast<uint32_t>(
rv)); } } while (0)
3202 " failed with error 0x%08" PRIx32,do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OnProxyAvailable notify"
" failed with error 0x%08" "x", static_cast<uint32_t>(
rv)); } } while (0)
3203 static_cast<uint32_t>(rv)))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OnProxyAvailable notify"
" failed with error 0x%08" "x", static_cast<uint32_t>(
rv)); } } while (0)
;
3204 }
3205 }
3206
3207 return NS_OK;
3208}
3209
3210// nsIInterfaceRequestor
3211
3212NS_IMETHODIMPnsresult
3213WebSocketChannel::GetInterface(const nsIID& iid, void** result) {
3214 LOG(("WebSocketChannel::GetInterface() %p\n", this))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::GetInterface() %p\n"
, this); } } while (0)
;
3215
3216 if (iid.Equals(NS_GET_IID(nsIChannelEventSink)(nsIChannelEventSink::kIID))) {
3217 return QueryInterface(iid, result);
3218 }
3219
3220 if (mCallbacks) return mCallbacks->GetInterface(iid, result);
3221
3222 return NS_ERROR_NO_INTERFACE;
3223}
3224
3225// nsIChannelEventSink
3226
3227NS_IMETHODIMPnsresult
3228WebSocketChannel::AsyncOnChannelRedirect(
3229 nsIChannel* oldChannel, nsIChannel* newChannel, uint32_t flags,
3230 nsIAsyncVerifyRedirectCallback* callback) {
3231 LOG(("WebSocketChannel::AsyncOnChannelRedirect() %p\n", this))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::AsyncOnChannelRedirect() %p\n"
, this); } } while (0)
;
3232
3233 MOZ_ASSERT(NS_IsMainThread(), "not main thread")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
" (" "not main thread" ")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 3233); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
") (" "not main thread" ")"); do { MOZ_CrashSequence(__null,
3233); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false)
;
3234
3235 nsresult rv;
3236
3237 nsCOMPtr<nsIURI> newuri;
3238 rv = newChannel->GetURI(getter_AddRefs(newuri));
3239 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 3239); return rv; } } while (false)
;
3240
3241 // newuri is expected to be http or https
3242 bool newuriIsHttps = newuri->SchemeIs("https");
3243
3244 // allow insecure->secure redirects for HTTP Strict Transport Security (from
3245 // ws://FOO to https://FOO (mapped to wss://FOO)
3246 if (!(flags & (nsIChannelEventSink::REDIRECT_INTERNAL |
3247 nsIChannelEventSink::REDIRECT_STS_UPGRADE))) {
3248 nsAutoCString newSpec;
3249 rv = newuri->GetSpec(newSpec);
3250 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 3250); return rv; } } while (false)
;
3251
3252 LOG(("WebSocketChannel: Redirect to %s denied by configuration\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel: Redirect to %s denied by configuration\n"
, newSpec.get()); } } while (0)
3253 newSpec.get()))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel: Redirect to %s denied by configuration\n"
, newSpec.get()); } } while (0)
;
3254 return NS_ERROR_FAILURE;
3255 }
3256
3257 if (mEncrypted && !newuriIsHttps) {
3258 nsAutoCString spec;
3259 if (NS_SUCCEEDED(newuri->GetSpec(spec))((bool)(__builtin_expect(!!(!NS_FAILED_impl(newuri->GetSpec
(spec))), 1)))
) {
3260 LOG(("WebSocketChannel: Redirect to %s violates encryption rule\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel: Redirect to %s violates encryption rule\n"
, spec.get()); } } while (0)
3261 spec.get()))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel: Redirect to %s violates encryption rule\n"
, spec.get()); } } while (0)
;
3262 }
3263 return NS_ERROR_FAILURE;
3264 }
3265
3266 nsCOMPtr<nsIHttpChannel> newHttpChannel = do_QueryInterface(newChannel, &rv);
3267 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
3268 LOG(("WebSocketChannel: Redirect could not QI to HTTP\n"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel: Redirect could not QI to HTTP\n"
); } } while (0)
;
3269 return rv;
3270 }
3271
3272 nsCOMPtr<nsIHttpChannelInternal> newUpgradeChannel =
3273 do_QueryInterface(newChannel, &rv);
3274
3275 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
3276 LOG(("WebSocketChannel: Redirect could not QI to HTTP Upgrade\n"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel: Redirect could not QI to HTTP Upgrade\n"
); } } while (0)
;
3277 return rv;
3278 }
3279
3280 // The redirect is likely OK
3281
3282 newChannel->SetNotificationCallbacks(this);
3283
3284 mEncrypted = newuriIsHttps;
3285 rv = NS_MutateURI(newuri)
3286 .SetScheme(mEncrypted ? "wss"_ns : "ws"_ns)
3287 .Finalize(mURI);
3288
3289 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
3290 LOG(("WebSocketChannel: Could not set the proper scheme\n"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel: Could not set the proper scheme\n"
); } } while (0)
;
3291 return rv;
3292 }
3293
3294 mHttpChannel = newHttpChannel;
3295 mChannel = newUpgradeChannel;
3296 rv = SetupRequest();
3297 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
3298 LOG(("WebSocketChannel: Redirect could not SetupRequest()\n"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel: Redirect could not SetupRequest()\n"
); } } while (0)
;
3299 return rv;
3300 }
3301
3302 // Redirected-to URI may need to be delayed by 1-connecting-per-host and
3303 // delay-after-fail algorithms. So hold off calling OnRedirectVerifyCallback
3304 // until BeginOpen, when we know it's OK to proceed with new channel.
3305 mRedirectCallback = callback;
3306
3307 // Mark old channel as successfully connected so we'll clear any FailDelay
3308 // associated with the old URI. Note: no need to also call OnStopSession:
3309 // it's a no-op for successful, already-connected channels.
3310 nsWSAdmissionManager::OnConnected(this);
3311
3312 // ApplyForAdmission as if we were starting from fresh...
3313 mAddress.Truncate();
3314 mOpenedHttpChannel = false;
3315 rv = ApplyForAdmission();
3316 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
3317 LOG(("WebSocketChannel: Redirect failed due to DNS failure\n"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel: Redirect failed due to DNS failure\n"
); } } while (0)
;
3318 mRedirectCallback = nullptr;
3319 return rv;
3320 }
3321
3322 return NS_OK;
3323}
3324
3325// nsITimerCallback
3326
3327NS_IMETHODIMPnsresult
3328WebSocketChannel::Notify(nsITimer* timer) {
3329 LOG(("WebSocketChannel::Notify() %p [%p]\n", this, timer))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::Notify() %p [%p]\n"
, this, timer); } } while (0)
;
3330
3331 if (timer == mCloseTimer) {
3332 MOZ_ASSERT(mClientClosed, "Close Timeout without local close")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mClientClosed)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mClientClosed))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("mClientClosed" " ("
"Close Timeout without local close" ")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 3332); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mClientClosed"
") (" "Close Timeout without local close" ")"); do { MOZ_CrashSequence
(__null, 3332); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
3333 MOZ_ASSERT(mIOThread->IsOnCurrentThread(), "not on right thread")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mIOThread->IsOnCurrentThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mIOThread->IsOnCurrentThread
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mIOThread->IsOnCurrentThread()" " (" "not on right thread"
")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 3333); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mIOThread->IsOnCurrentThread()"
") (" "not on right thread" ")"); do { MOZ_CrashSequence(__null
, 3333); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
3334
3335 mCloseTimer = nullptr;
3336 if (mStopped || mServerClosed) { /* no longer relevant */
3337 return NS_OK;
3338 }
3339
3340 LOG(("WebSocketChannel:: Expecting Server Close - Timed Out\n"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel:: Expecting Server Close - Timed Out\n"
); } } while (0)
;
3341 AbortSession(NS_ERROR_NET_TIMEOUT_EXTERNAL);
3342 } else if (timer == mOpenTimer) {
3343 MOZ_ASSERT(NS_IsMainThread(), "not main thread")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
" (" "not main thread" ")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 3343); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
") (" "not main thread" ")"); do { MOZ_CrashSequence(__null,
3343); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false)
;
3344
3345 mOpenTimer = nullptr;
3346 LOG(("WebSocketChannel:: Connection Timed Out\n"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel:: Connection Timed Out\n"
); } } while (0)
;
3347 if (mStopped || mServerClosed) { /* no longer relevant */
3348 return NS_OK;
3349 }
3350
3351 AbortSession(NS_ERROR_NET_TIMEOUT_EXTERNAL);
3352 MOZ_PUSH_IGNORE_THREAD_SAFETYGCC diagnostic push GCC diagnostic ignored "-Wthread-safety"
3353 // mReconnectDelayTimer is only modified on MainThread, we can read it
3354 // without a lock, but ONLY if we're on MainThread! And if we're not
3355 // on MainThread, it can't be mReconnectDelayTimer
3356 } else if (NS_IsMainThread() && timer == mReconnectDelayTimer) {
3357 MOZ_POP_THREAD_SAFETYGCC diagnostic pop
3358 MOZ_ASSERT(mConnecting == CONNECTING_DELAYED,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mConnecting == CONNECTING_DELAYED)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mConnecting == CONNECTING_DELAYED
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"mConnecting == CONNECTING_DELAYED" " (" "woke up from delay w/o being delayed?"
")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 3359); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mConnecting == CONNECTING_DELAYED"
") (" "woke up from delay w/o being delayed?" ")"); do { MOZ_CrashSequence
(__null, 3359); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
3359 "woke up from delay w/o being delayed?")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mConnecting == CONNECTING_DELAYED)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mConnecting == CONNECTING_DELAYED
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"mConnecting == CONNECTING_DELAYED" " (" "woke up from delay w/o being delayed?"
")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 3359); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mConnecting == CONNECTING_DELAYED"
") (" "woke up from delay w/o being delayed?" ")"); do { MOZ_CrashSequence
(__null, 3359); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
3360
3361 {
3362 MutexAutoLock lock(mMutex);
3363 mReconnectDelayTimer = nullptr;
3364 }
3365 LOG(("WebSocketChannel: connecting [this=%p] after reconnect delay", this))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel: connecting [this=%p] after reconnect delay"
, this); } } while (0)
;
3366 BeginOpen(false);
3367 } else if (timer == mPingTimer) {
3368 MOZ_ASSERT(mIOThread->IsOnCurrentThread(), "not on right thread")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mIOThread->IsOnCurrentThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mIOThread->IsOnCurrentThread
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mIOThread->IsOnCurrentThread()" " (" "not on right thread"
")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 3368); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mIOThread->IsOnCurrentThread()"
") (" "not on right thread" ")"); do { MOZ_CrashSequence(__null
, 3368); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
3369
3370 if (mClientClosed || mServerClosed || mRequestedClose) {
3371 // no point in worrying about ping now
3372 mPingTimer = nullptr;
3373 return NS_OK;
3374 }
3375
3376 if (!mPingOutstanding) {
3377 // Ping interval must be non-null or PING was forced by OnNetworkChanged()
3378 MOZ_ASSERT(mPingInterval || mPingForced)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mPingInterval || mPingForced)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mPingInterval || mPingForced
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"mPingInterval || mPingForced", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 3378); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mPingInterval || mPingForced"
")"); do { MOZ_CrashSequence(__null, 3378); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3379 LOG(("nsWebSocketChannel:: Generating Ping\n"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "nsWebSocketChannel:: Generating Ping\n"
); } } while (0)
;
3380 mPingOutstanding = 1;
3381 mPingForced = false;
3382 mPingTimer->InitWithCallback(this, mPingResponseTimeout,
3383 nsITimer::TYPE_ONE_SHOT);
3384 GeneratePing();
3385 } else {
3386 LOG(("nsWebSocketChannel:: Timed out Ping\n"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "nsWebSocketChannel:: Timed out Ping\n"
); } } while (0)
;
3387 mPingTimer = nullptr;
3388 AbortSession(NS_ERROR_NET_TIMEOUT_EXTERNAL);
3389 }
3390 } else if (timer == mLingeringCloseTimer) {
3391 LOG(("WebSocketChannel:: Lingering Close Timer"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel:: Lingering Close Timer"
); } } while (0)
;
3392 CleanupConnection();
3393 } else {
3394 MOZ_ASSERT(0, "Unknown Timer")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(0)>::isValid, "invalid assertion condition"); if (
(__builtin_expect(!!(!(!!(0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("0" " (" "Unknown Timer" ")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 3394); AnnotateMozCrashReason("MOZ_ASSERT" "(" "0" ") (" "Unknown Timer"
")"); do { MOZ_CrashSequence(__null, 3394); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3395 }
3396
3397 return NS_OK;
3398}
3399
3400// nsINamed
3401
3402NS_IMETHODIMPnsresult
3403WebSocketChannel::GetName(nsACString& aName) {
3404 aName.AssignLiteral("WebSocketChannel");
3405 return NS_OK;
3406}
3407
3408// nsIWebSocketChannel
3409
3410NS_IMETHODIMPnsresult
3411WebSocketChannel::GetSecurityInfo(nsITransportSecurityInfo** aSecurityInfo) {
3412 LOG(("WebSocketChannel::GetSecurityInfo() %p\n", this))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::GetSecurityInfo() %p\n"
, this); } } while (0)
;
3413 MOZ_ASSERT(NS_IsMainThread(), "not main thread")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
" (" "not main thread" ")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 3413); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
") (" "not main thread" ")"); do { MOZ_CrashSequence(__null,
3413); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false)
;
3414
3415 *aSecurityInfo = nullptr;
3416
3417 if (mConnection) {
3418 nsresult rv = mConnection->GetSecurityInfo(aSecurityInfo);
3419 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
3420 return rv;
3421 }
3422 return NS_OK;
3423 }
3424
3425 if (mTransport) {
3426 nsCOMPtr<nsITLSSocketControl> tlsSocketControl;
3427 nsresult rv =
3428 mTransport->GetTlsSocketControl(getter_AddRefs(tlsSocketControl));
3429 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
3430 return rv;
3431 }
3432 nsCOMPtr<nsITransportSecurityInfo> securityInfo(
3433 do_QueryInterface(tlsSocketControl));
3434 if (securityInfo) {
3435 securityInfo.forget(aSecurityInfo);
3436 }
3437 }
3438 return NS_OK;
3439}
3440
3441NS_IMETHODIMPnsresult
3442WebSocketChannel::AsyncOpen(nsIURI* aURI, const nsACString& aOrigin,
3443 JS::Handle<JS::Value> aOriginAttributes,
3444 uint64_t aInnerWindowID,
3445 nsIWebSocketListener* aListener,
3446 nsISupports* aContext, JSContext* aCx) {
3447 OriginAttributes attrs;
3448 if (!aOriginAttributes.isObject() || !attrs.Init(aCx, aOriginAttributes)) {
3449 return NS_ERROR_INVALID_ARG;
3450 }
3451 return AsyncOpenNative(aURI, aOrigin, attrs, aInnerWindowID, aListener,
3452 aContext);
3453}
3454
3455NS_IMETHODIMPnsresult
3456WebSocketChannel::AsyncOpenNative(nsIURI* aURI, const nsACString& aOrigin,
3457 const OriginAttributes& aOriginAttributes,
3458 uint64_t aInnerWindowID,
3459 nsIWebSocketListener* aListener,
3460 nsISupports* aContext) {
3461 LOG(("WebSocketChannel::AsyncOpen() %p\n", this))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::AsyncOpen() %p\n"
, this); } } while (0)
;
3462
3463 aOriginAttributes.CreateSuffix(mOriginSuffix);
3464
3465 if (!NS_IsMainThread()) {
3466 MOZ_ASSERT(false, "not main thread")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "not main thread"
")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 3466); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"not main thread" ")"); do { MOZ_CrashSequence(__null, 3466)
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
;
3467 LOG(("WebSocketChannel::AsyncOpen() called off the main thread"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::AsyncOpen() called off the main thread"
); } } while (0)
;
3468 return NS_ERROR_UNEXPECTED;
3469 }
3470
3471 if ((!aURI && !mIsServerSide) || !aListener) {
3472 LOG(("WebSocketChannel::AsyncOpen() Uri or Listener null"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::AsyncOpen() Uri or Listener null"
); } } while (0)
;
3473 return NS_ERROR_UNEXPECTED;
3474 }
3475
3476 {
3477 MutexAutoLock lock(mMutex);
3478 if (mWasOpened || mListenerMT) return NS_ERROR_ALREADY_OPENED;
3479 }
3480
3481 nsresult rv;
3482
3483 // Ensure target thread is set if RetargetDeliveryTo isn't called
3484 {
3485 auto lock = mTargetThread.Lock();
3486 if (!lock.ref()) {
3487 lock.ref() = GetMainThreadSerialEventTarget();
3488 }
3489 }
3490
3491 mIOThread = mozilla::components::SocketTransport::Service(&rv);
3492 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
3493 NS_WARNING("unable to continue without socket transport service")NS_DebugBreak(NS_DEBUG_WARNING, "unable to continue without socket transport service"
, nullptr, "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 3493)
;
3494 return rv;
3495 }
3496
3497 nsCOMPtr<nsIPrefBranch> prefService;
3498 prefService = mozilla::components::Preferences::Service();
3499
3500 if (prefService) {
3501 int32_t intpref;
3502 rv =
3503 prefService->GetIntPref("network.websocket.max-message-size", &intpref);
3504 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
3505 mMaxMessageSize = std::clamp(intpref, 1024, INT32_MAX(2147483647));
3506 }
3507 rv = prefService->GetIntPref("network.websocket.timeout.close", &intpref);
3508 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
3509 mCloseTimeout = std::clamp(intpref, 1, 1800) * 1000;
3510 }
3511 rv = prefService->GetIntPref("network.websocket.timeout.open", &intpref);
3512 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
3513 mOpenTimeout = std::clamp(intpref, 1, 1800) * 1000;
3514 }
3515 rv = prefService->GetIntPref("network.websocket.timeout.ping.request",
3516 &intpref);
3517 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) && !mClientSetPingInterval) {
3518 mPingInterval = std::clamp(intpref, 0, 86400) * 1000;
3519 }
3520 rv = prefService->GetIntPref("network.websocket.timeout.ping.response",
3521 &intpref);
3522 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) && !mClientSetPingTimeout) {
3523 mPingResponseTimeout = std::clamp(intpref, 1, 3600) * 1000;
3524 }
3525 rv = prefService->GetIntPref("network.websocket.max-connections", &intpref);
3526 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
3527 mMaxConcurrentConnections = std::clamp(intpref, 1, 0xffff);
3528 }
3529 }
3530
3531 int32_t sessionCount = -1;
3532 nsWSAdmissionManager::GetSessionCount(sessionCount);
3533 if (sessionCount >= 0) {
3534 LOG(("WebSocketChannel::AsyncOpen %p sessionCount=%d max=%d\n", this,do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::AsyncOpen %p sessionCount=%d max=%d\n"
, this, sessionCount, mMaxConcurrentConnections); } } while (
0)
3535 sessionCount, mMaxConcurrentConnections))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::AsyncOpen %p sessionCount=%d max=%d\n"
, this, sessionCount, mMaxConcurrentConnections); } } while (
0)
;
3536 }
3537
3538 if (sessionCount >= mMaxConcurrentConnections) {
3539 LOG(("WebSocketChannel: max concurrency %d exceeded (%d)",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel: max concurrency %d exceeded (%d)"
, mMaxConcurrentConnections, sessionCount); } } while (0)
3540 mMaxConcurrentConnections, sessionCount))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel: max concurrency %d exceeded (%d)"
, mMaxConcurrentConnections, sessionCount); } } while (0)
;
3541
3542 // WebSocket connections are expected to be long lived, so return
3543 // an error here instead of queueing
3544 return NS_ERROR_SOCKET_CREATE_FAILED;
3545 }
3546
3547 mInnerWindowID = aInnerWindowID;
3548 mOriginalURI = aURI;
3549 mURI = mOriginalURI;
3550 mOrigin = aOrigin;
3551
3552 if (mIsServerSide) {
3553 // IncrementSessionCount();
3554 mWasOpened = 1;
3555 {
3556 MutexAutoLock lock(mMutex);
3557 mListenerMT =
3558 MakeRefPtr<ListenerAndContextContainer>(aListener, aContext);
3559 }
3560 rv = mServerTransportProvider->SetListener(this);
3561 MOZ_ASSERT(NS_SUCCEEDED(rv))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
)))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 3561); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))"
")"); do { MOZ_CrashSequence(__null, 3561); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3562 mServerTransportProvider = nullptr;
3563
3564 return NS_OK;
3565 }
3566
3567 mURI->GetHostPort(mHost);
3568
3569 mRandomGenerator = mozilla::components::RandomGenerator::Service(&rv);
3570 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
3571 NS_WARNING("unable to continue without random number generator")NS_DebugBreak(NS_DEBUG_WARNING, "unable to continue without random number generator"
, nullptr, "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 3571)
;
3572 return rv;
3573 }
3574
3575 nsCOMPtr<nsIURI> localURI;
3576 nsCOMPtr<nsIChannel> localChannel;
3577
3578 LOG(("WebSocketChannel::AsyncOpen uri=%s", mURI->GetSpecOrDefault().get()))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::AsyncOpen uri=%s"
, mURI->GetSpecOrDefault().get()); } } while (0)
;
3579
3580 rv = NS_MutateURI(mURI)
3581 .SetScheme(mEncrypted ? "https"_ns : "http"_ns)
3582 .Finalize(localURI);
3583 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 3583); return rv; } } while (false)
;
3584
3585 nsCOMPtr<nsIIOService> ioService;
3586 ioService = mozilla::components::IO::Service(&rv);
3587 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
3588 NS_WARNING("unable to continue without io service")NS_DebugBreak(NS_DEBUG_WARNING, "unable to continue without io service"
, nullptr, "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 3588)
;
3589 return rv;
3590 }
3591
3592 rv = ioService->NewChannelFromURIWithProxyFlagsAndLoadInfo(
3593 localURI, mURI,
3594 nsIProtocolProxyService::RESOLVE_PREFER_SOCKS_PROXY |
3595 nsIProtocolProxyService::RESOLVE_PREFER_HTTPS_PROXY |
3596 nsIProtocolProxyService::RESOLVE_ALWAYS_TUNNEL,
3597 mLoadInfo, getter_AddRefs(localChannel));
3598 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 3598); return rv; } } while (false)
;
3599
3600 // Pass most GetInterface() requests through to our instantiator, but handle
3601 // nsIChannelEventSink in this object in order to deal with redirects
3602 localChannel->SetNotificationCallbacks(this);
3603
3604 class MOZ_STACK_CLASS CleanUpOnFailure {
3605 public:
3606 explicit CleanUpOnFailure(WebSocketChannel* aWebSocketChannel)
3607 : mWebSocketChannel(aWebSocketChannel) {}
3608
3609 ~CleanUpOnFailure() {
3610 if (!mWebSocketChannel->mWasOpened) {
3611 mWebSocketChannel->mChannel = nullptr;
3612 mWebSocketChannel->mHttpChannel = nullptr;
3613 }
3614 }
3615
3616 WebSocketChannel* mWebSocketChannel;
3617 };
3618
3619 CleanUpOnFailure cuof(this);
3620
3621 mChannel = do_QueryInterface(localChannel, &rv);
3622 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 3622); return rv; } } while (false)
;
3623
3624 mHttpChannel = do_QueryInterface(localChannel, &rv);
3625 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 3625); return rv; } } while (false)
;
3626
3627 rv = SetupRequest();
3628 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) return rv;
3629
3630 mPrivateBrowsing = NS_UsePrivateBrowsing(localChannel);
3631
3632 if (mConnectionLogService && !mPrivateBrowsing) {
3633 mConnectionLogService->AddHost(mHost, mSerial,
3634 BaseWebSocketChannel::mEncrypted);
3635 }
3636
3637 rv = ApplyForAdmission();
3638 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) return rv;
3639
3640 // Register for prefs change notifications
3641 nsCOMPtr<nsIObserverService> observerService =
3642 mozilla::services::GetObserverService();
3643 if (!observerService) {
3644 NS_WARNING("failed to get observer service")NS_DebugBreak(NS_DEBUG_WARNING, "failed to get observer service"
, nullptr, "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 3644)
;
3645 return NS_ERROR_FAILURE;
3646 }
3647
3648 rv = observerService->AddObserver(this, NS_NETWORK_LINK_TOPIC"network:link-status-changed", false);
3649 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 3649)
) {
3650 return rv;
3651 }
3652
3653 // Only set these if the open was successful:
3654 //
3655 mWasOpened = 1;
3656 {
3657 MutexAutoLock lock(mMutex);
3658 mListenerMT = MakeRefPtr<ListenerAndContextContainer>(aListener, aContext);
3659 }
3660 IncrementSessionCount();
3661
3662 return rv;
3663}
3664
3665NS_IMETHODIMPnsresult
3666WebSocketChannel::Close(uint16_t code, const nsACString& reason) {
3667 LOG(("WebSocketChannel::Close() %p\n", this))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::Close() %p\n"
, this); } } while (0)
;
3668 MOZ_ASSERT(NS_IsMainThread(), "not main thread")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
" (" "not main thread" ")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 3668); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
") (" "not main thread" ")"); do { MOZ_CrashSequence(__null,
3668); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false)
;
3669
3670 {
3671 MutexAutoLock lock(mMutex);
3672
3673 if (mRequestedClose) {
3674 return NS_OK;
3675 }
3676
3677 if (mStopped) {
3678 return NS_ERROR_NOT_AVAILABLE;
3679 }
3680
3681 // The API requires the UTF-8 string to be 123 or less bytes
3682 if (reason.Length() > 123) return NS_ERROR_ILLEGAL_VALUE;
3683
3684 mRequestedClose = true;
3685 mScriptCloseReason = reason;
3686 mScriptCloseCode = code;
3687
3688 if (mDataStarted) {
3689 return mIOThread->Dispatch(
3690 new OutboundEnqueuer(this,
3691 new OutboundMessage(kMsgTypeFin, VoidCString())),
3692 nsIEventTarget::DISPATCH_NORMAL);
3693 }
3694
3695 mStopped = true;
3696 }
3697
3698 nsresult rv;
3699 if (code == CLOSE_GOING_AWAY) {
3700 // Not an error: for example, tab has closed or navigated away
3701 LOG(("WebSocketChannel::Close() GOING_AWAY without transport."))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::Close() GOING_AWAY without transport."
); } } while (0)
;
3702 rv = NS_OK;
3703 } else {
3704 LOG(("WebSocketChannel::Close() without transport - error."))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::Close() without transport - error."
); } } while (0)
;
3705 rv = NS_ERROR_NOT_CONNECTED;
3706 }
3707
3708 DoStopSession(rv);
3709 return rv;
3710}
3711
3712NS_IMETHODIMPnsresult
3713WebSocketChannel::SendMsg(const nsACString& aMsg) {
3714 LOG(("WebSocketChannel::SendMsg() %p\n", this))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::SendMsg() %p\n"
, this); } } while (0)
;
3715
3716 return SendMsgCommon(aMsg, false, aMsg.Length());
3717}
3718
3719NS_IMETHODIMPnsresult
3720WebSocketChannel::SendBinaryMsg(const nsACString& aMsg) {
3721 LOG(("WebSocketChannel::SendBinaryMsg() %p len=%zu\n", this, aMsg.Length()))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::SendBinaryMsg() %p len=%zu\n"
, this, aMsg.Length()); } } while (0)
;
3722 return SendMsgCommon(aMsg, true, aMsg.Length());
3723}
3724
3725NS_IMETHODIMPnsresult
3726WebSocketChannel::SendBinaryStream(nsIInputStream* aStream, uint32_t aLength) {
3727 LOG(("WebSocketChannel::SendBinaryStream() %p\n", this))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::SendBinaryStream() %p\n"
, this); } } while (0)
;
3728
3729 return SendMsgCommon(VoidCString(), true, aLength, aStream);
3730}
3731
3732nsresult WebSocketChannel::SendMsgCommon(const nsACString& aMsg, bool aIsBinary,
3733 uint32_t aLength,
3734 nsIInputStream* aStream) {
3735 MOZ_ASSERT(IsOnTargetThread(), "not target thread")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(IsOnTargetThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(IsOnTargetThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("IsOnTargetThread()"
" (" "not target thread" ")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 3735); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsOnTargetThread()"
") (" "not target thread" ")"); do { MOZ_CrashSequence(__null
, 3735); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
3736
3737 if (!mDataStarted) {
3738 LOG(("WebSocketChannel:: Error: data not started yet\n"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel:: Error: data not started yet\n"
); } } while (0)
;
3739 return NS_ERROR_UNEXPECTED;
3740 }
3741
3742 if (mRequestedClose) {
3743 LOG(("WebSocketChannel:: Error: send when closed\n"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel:: Error: send when closed\n"
); } } while (0)
;
3744 return NS_ERROR_UNEXPECTED;
3745 }
3746
3747 if (mStopped) {
3748 LOG(("WebSocketChannel:: Error: send when stopped\n"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel:: Error: send when stopped\n"
); } } while (0)
;
3749 return NS_ERROR_NOT_CONNECTED;
3750 }
3751
3752 MOZ_ASSERT(mMaxMessageSize >= 0, "max message size negative")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mMaxMessageSize >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mMaxMessageSize >= 0))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("mMaxMessageSize >= 0"
" (" "max message size negative" ")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 3752); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mMaxMessageSize >= 0"
") (" "max message size negative" ")"); do { MOZ_CrashSequence
(__null, 3752); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
3753 if (aLength > static_cast<uint32_t>(mMaxMessageSize)) {
3754 LOG(("WebSocketChannel:: Error: message too big\n"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel:: Error: message too big\n"
); } } while (0)
;
3755 return NS_ERROR_FILE_TOO_BIG;
3756 }
3757
3758 if (mConnectionLogService && !mPrivateBrowsing) {
3759 mConnectionLogService->NewMsgSent(mHost, mSerial, aLength);
3760 LOG(("Added new msg sent for %s", mHost.get()))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "Added new msg sent for %s"
, mHost.get()); } } while (0)
;
3761 }
3762
3763 return mIOThread->Dispatch(
3764 aStream
3765 ? new OutboundEnqueuer(this, new OutboundMessage(aStream, aLength))
3766 : new OutboundEnqueuer(
3767 this,
3768 new OutboundMessage(
3769 aIsBinary ? kMsgTypeBinaryString : kMsgTypeString, aMsg)),
3770 nsIEventTarget::DISPATCH_NORMAL);
3771}
3772
3773// nsIHttpUpgradeListener
3774
3775NS_IMETHODIMPnsresult
3776WebSocketChannel::OnTransportAvailable(nsISocketTransport* aTransport,
3777 nsIAsyncInputStream* aSocketIn,
3778 nsIAsyncOutputStream* aSocketOut) {
3779 if (!NS_IsMainThread()) {
3780 return NS_DispatchToMainThread(
3781 new CallOnTransportAvailable(this, aTransport, aSocketIn, aSocketOut));
3782 }
3783
3784 LOG(("WebSocketChannel::OnTransportAvailable %p [%p %p %p] rcvdonstart=%d\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OnTransportAvailable %p [%p %p %p] rcvdonstart=%d\n"
, this, aTransport, aSocketIn, aSocketOut, mGotUpgradeOK); } }
while (0)
3785 this, aTransport, aSocketIn, aSocketOut, mGotUpgradeOK))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OnTransportAvailable %p [%p %p %p] rcvdonstart=%d\n"
, this, aTransport, aSocketIn, aSocketOut, mGotUpgradeOK); } }
while (0)
;
3786
3787 if (mStopped) {
3788 LOG(("WebSocketChannel::OnTransportAvailable: Already stopped"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OnTransportAvailable: Already stopped"
); } } while (0)
;
3789 return NS_OK;
3790 }
3791
3792 MOZ_ASSERT(NS_IsMainThread(), "not main thread")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
" (" "not main thread" ")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 3792); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
") (" "not main thread" ")"); do { MOZ_CrashSequence(__null,
3792); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false)
;
3793 MOZ_ASSERT(!mRecvdHttpUpgradeTransport, "OTA duplicated")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mRecvdHttpUpgradeTransport)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mRecvdHttpUpgradeTransport)
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!mRecvdHttpUpgradeTransport"
" (" "OTA duplicated" ")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 3793); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mRecvdHttpUpgradeTransport"
") (" "OTA duplicated" ")"); do { MOZ_CrashSequence(__null, 3793
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
;
3794 MOZ_ASSERT(aSocketIn, "OTA with invalid socketIn")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aSocketIn)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aSocketIn))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("aSocketIn" " (" "OTA with invalid socketIn"
")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 3794); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aSocketIn" ") ("
"OTA with invalid socketIn" ")"); do { MOZ_CrashSequence(__null
, 3794); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
3795
3796 mTransport = aTransport;
3797 mSocketIn = aSocketIn;
3798 mSocketOut = aSocketOut;
3799
3800 nsresult rv;
3801 rv = mTransport->SetEventSink(nullptr, nullptr);
3802 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 3802)
) return rv;
3803 rv = mTransport->SetSecurityCallbacks(this);
3804 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 3804)
) return rv;
3805
3806 return OnTransportAvailableInternal();
3807}
3808
3809NS_IMETHODIMPnsresult
3810WebSocketChannel::OnWebSocketConnectionAvailable(
3811 WebSocketConnectionBase* aConnection) {
3812 if (!NS_IsMainThread()) {
3813 RefPtr<WebSocketChannel> self = this;
3814 RefPtr<WebSocketConnectionBase> connection = aConnection;
3815 return NS_DispatchToMainThread(NS_NewRunnableFunction(
3816 "WebSocketChannel::OnWebSocketConnectionAvailable",
3817 [self, connection]() {
3818 self->OnWebSocketConnectionAvailable(connection);
3819 }));
3820 }
3821
3822 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OnWebSocketConnectionAvailable %p [%p] "
"rcvdonstart=%d\n", this, aConnection, mGotUpgradeOK); } } while
(0)
3823 ("WebSocketChannel::OnWebSocketConnectionAvailable %p [%p] "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OnWebSocketConnectionAvailable %p [%p] "
"rcvdonstart=%d\n", this, aConnection, mGotUpgradeOK); } } while
(0)
3824 "rcvdonstart=%d\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OnWebSocketConnectionAvailable %p [%p] "
"rcvdonstart=%d\n", this, aConnection, mGotUpgradeOK); } } while
(0)
3825 this, aConnection, mGotUpgradeOK))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OnWebSocketConnectionAvailable %p [%p] "
"rcvdonstart=%d\n", this, aConnection, mGotUpgradeOK); } } while
(0)
;
3826
3827 MOZ_ASSERT(NS_IsMainThread(), "not main thread")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
" (" "not main thread" ")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 3827); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
") (" "not main thread" ")"); do { MOZ_CrashSequence(__null,
3827); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false)
;
3828 MOZ_ASSERT(!mRecvdHttpUpgradeTransport,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mRecvdHttpUpgradeTransport)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mRecvdHttpUpgradeTransport)
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!mRecvdHttpUpgradeTransport"
" (" "OnWebSocketConnectionAvailable duplicated" ")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 3829); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mRecvdHttpUpgradeTransport"
") (" "OnWebSocketConnectionAvailable duplicated" ")"); do {
MOZ_CrashSequence(__null, 3829); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
3829 "OnWebSocketConnectionAvailable duplicated")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mRecvdHttpUpgradeTransport)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mRecvdHttpUpgradeTransport)
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!mRecvdHttpUpgradeTransport"
" (" "OnWebSocketConnectionAvailable duplicated" ")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 3829); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mRecvdHttpUpgradeTransport"
") (" "OnWebSocketConnectionAvailable duplicated" ")"); do {
MOZ_CrashSequence(__null, 3829); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
3830 MOZ_ASSERT(aConnection)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aConnection)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aConnection))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("aConnection", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 3830); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aConnection"
")"); do { MOZ_CrashSequence(__null, 3830); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3831
3832 if (mStopped) {
3833 LOG(("WebSocketChannel::OnWebSocketConnectionAvailable: Already stopped"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OnWebSocketConnectionAvailable: Already stopped"
); } } while (0)
;
3834 aConnection->Close();
3835 return NS_OK;
3836 }
3837
3838 nsresult rv = aConnection->Init(this);
3839 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
3840 return rv;
3841 }
3842
3843 mConnection = aConnection;
3844 // Note: mIOThread will be IPDL background thread.
3845 mConnection->GetIoTarget(getter_AddRefs(mIOThread));
3846 return OnTransportAvailableInternal();
3847}
3848
3849nsresult WebSocketChannel::OnTransportAvailableInternal() {
3850 MOZ_ASSERT(NS_IsMainThread(), "not main thread")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
" (" "not main thread" ")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 3850); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
") (" "not main thread" ")"); do { MOZ_CrashSequence(__null,
3850); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false)
;
3851 MOZ_ASSERT(!mRecvdHttpUpgradeTransport,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mRecvdHttpUpgradeTransport)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mRecvdHttpUpgradeTransport)
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!mRecvdHttpUpgradeTransport"
" (" "OnWebSocketConnectionAvailable duplicated" ")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 3852); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mRecvdHttpUpgradeTransport"
") (" "OnWebSocketConnectionAvailable duplicated" ")"); do {
MOZ_CrashSequence(__null, 3852); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
3852 "OnWebSocketConnectionAvailable duplicated")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mRecvdHttpUpgradeTransport)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mRecvdHttpUpgradeTransport)
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!mRecvdHttpUpgradeTransport"
" (" "OnWebSocketConnectionAvailable duplicated" ")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 3852); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mRecvdHttpUpgradeTransport"
") (" "OnWebSocketConnectionAvailable duplicated" ")"); do {
MOZ_CrashSequence(__null, 3852); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
3853 MOZ_ASSERT(mSocketIn || mConnection)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mSocketIn || mConnection)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mSocketIn || mConnection))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("mSocketIn || mConnection"
, "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 3853); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mSocketIn || mConnection"
")"); do { MOZ_CrashSequence(__null, 3853); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3854
3855 mRecvdHttpUpgradeTransport = 1;
3856 if (mGotUpgradeOK) {
3857 // We're now done CONNECTING, which means we can now open another,
3858 // perhaps parallel, connection to the same host if one
3859 // is pending
3860 nsWSAdmissionManager::OnConnected(this);
3861
3862 return CallStartWebsocketData();
3863 }
3864
3865 if (mIsServerSide) {
3866 if (!mNegotiatedExtensions.IsEmpty()) {
3867 bool clientNoContextTakeover;
3868 bool serverNoContextTakeover;
3869 int32_t clientMaxWindowBits;
3870 int32_t serverMaxWindowBits;
3871
3872 nsresult rv = ParseWebSocketExtension(
3873 mNegotiatedExtensions, eParseServerSide, clientNoContextTakeover,
3874 serverNoContextTakeover, clientMaxWindowBits, serverMaxWindowBits);
3875 MOZ_RELEASE_ASSERT(NS_SUCCEEDED(rv), "illegal value provided by server")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
)))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))" " ("
"illegal value provided by server" ")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 3875); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))"
") (" "illegal value provided by server" ")"); do { MOZ_CrashSequence
(__null, 3875); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
3876
3877 if (clientMaxWindowBits == -1) {
3878 clientMaxWindowBits = 15;
3879 }
3880 if (serverMaxWindowBits == -1) {
3881 serverMaxWindowBits = 15;
3882 }
3883
3884 MutexAutoLock lock(mCompressorMutex);
3885 mPMCECompressor = MakeUnique<PMCECompression>(
3886 serverNoContextTakeover, serverMaxWindowBits, clientMaxWindowBits);
3887 if (mPMCECompressor->Active()) {
3888 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OnTransportAvailable: PMCE negotiated, %susing "
"context takeover, serverMaxWindowBits=%d, " "clientMaxWindowBits=%d\n"
, serverNoContextTakeover ? "NOT " : "", serverMaxWindowBits,
clientMaxWindowBits); } } while (0)
3889 ("WebSocketChannel::OnTransportAvailable: PMCE negotiated, %susing "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OnTransportAvailable: PMCE negotiated, %susing "
"context takeover, serverMaxWindowBits=%d, " "clientMaxWindowBits=%d\n"
, serverNoContextTakeover ? "NOT " : "", serverMaxWindowBits,
clientMaxWindowBits); } } while (0)
3890 "context takeover, serverMaxWindowBits=%d, "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OnTransportAvailable: PMCE negotiated, %susing "
"context takeover, serverMaxWindowBits=%d, " "clientMaxWindowBits=%d\n"
, serverNoContextTakeover ? "NOT " : "", serverMaxWindowBits,
clientMaxWindowBits); } } while (0)
3891 "clientMaxWindowBits=%d\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OnTransportAvailable: PMCE negotiated, %susing "
"context takeover, serverMaxWindowBits=%d, " "clientMaxWindowBits=%d\n"
, serverNoContextTakeover ? "NOT " : "", serverMaxWindowBits,
clientMaxWindowBits); } } while (0)
3892 serverNoContextTakeover ? "NOT " : "", serverMaxWindowBits,do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OnTransportAvailable: PMCE negotiated, %susing "
"context takeover, serverMaxWindowBits=%d, " "clientMaxWindowBits=%d\n"
, serverNoContextTakeover ? "NOT " : "", serverMaxWindowBits,
clientMaxWindowBits); } } while (0)
3893 clientMaxWindowBits))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OnTransportAvailable: PMCE negotiated, %susing "
"context takeover, serverMaxWindowBits=%d, " "clientMaxWindowBits=%d\n"
, serverNoContextTakeover ? "NOT " : "", serverMaxWindowBits,
clientMaxWindowBits); } } while (0)
;
3894
3895 mNegotiatedExtensions = "permessage-deflate";
3896 } else {
3897 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OnTransportAvailable: Cannot init PMCE "
"compression object\n"); } } while (0)
3898 ("WebSocketChannel::OnTransportAvailable: Cannot init PMCE "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OnTransportAvailable: Cannot init PMCE "
"compression object\n"); } } while (0)
3899 "compression object\n"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OnTransportAvailable: Cannot init PMCE "
"compression object\n"); } } while (0)
;
3900 mPMCECompressor = nullptr;
3901 AbortSession(NS_ERROR_UNEXPECTED);
3902 return NS_ERROR_UNEXPECTED;
3903 }
3904 }
3905
3906 return CallStartWebsocketData();
3907 }
3908
3909 return NS_OK;
3910}
3911
3912NS_IMETHODIMPnsresult
3913WebSocketChannel::OnUpgradeFailed(nsresult aErrorCode) {
3914 // When socket process is enabled, this could be called on background thread.
3915
3916 LOG(("WebSocketChannel::OnUpgradeFailed() %p [aErrorCode %" PRIx32 "]", this,do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OnUpgradeFailed() %p [aErrorCode %"
"x" "]", this, static_cast<uint32_t>(aErrorCode)); } }
while (0)
3917 static_cast<uint32_t>(aErrorCode)))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OnUpgradeFailed() %p [aErrorCode %"
"x" "]", this, static_cast<uint32_t>(aErrorCode)); } }
while (0)
;
3918
3919 if (mStopped) {
3920 LOG(("WebSocketChannel::OnUpgradeFailed: Already stopped"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OnUpgradeFailed: Already stopped"
); } } while (0)
;
3921 return NS_OK;
3922 }
3923
3924 MOZ_ASSERT(!mRecvdHttpUpgradeTransport, "OTA already called")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mRecvdHttpUpgradeTransport)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mRecvdHttpUpgradeTransport)
)), 0))) { do { } while (false); MOZ_ReportAssertionFailure("!mRecvdHttpUpgradeTransport"
" (" "OTA already called" ")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 3924); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mRecvdHttpUpgradeTransport"
") (" "OTA already called" ")"); do { MOZ_CrashSequence(__null
, 3924); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
3925
3926 AbortSession(aErrorCode);
3927 return NS_OK;
3928}
3929
3930// nsIRequestObserver (from nsIStreamListener)
3931
3932NS_IMETHODIMPnsresult
3933WebSocketChannel::OnStartRequest(nsIRequest* aRequest) {
3934 LOG(("WebSocketChannel::OnStartRequest(): %p [%p %p] recvdhttpupgrade=%d\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OnStartRequest(): %p [%p %p] recvdhttpupgrade=%d\n"
, this, aRequest, mHttpChannel.get(), mRecvdHttpUpgradeTransport
); } } while (0)
3935 this, aRequest, mHttpChannel.get(), mRecvdHttpUpgradeTransport))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OnStartRequest(): %p [%p %p] recvdhttpupgrade=%d\n"
, this, aRequest, mHttpChannel.get(), mRecvdHttpUpgradeTransport
); } } while (0)
;
3936 MOZ_ASSERT(NS_IsMainThread(), "not main thread")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
" (" "not main thread" ")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 3936); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
") (" "not main thread" ")"); do { MOZ_CrashSequence(__null,
3936); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false)
;
3937 MOZ_ASSERT(!mGotUpgradeOK, "OTA duplicated")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!mGotUpgradeOK)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!mGotUpgradeOK))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("!mGotUpgradeOK"
" (" "OTA duplicated" ")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 3937); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mGotUpgradeOK"
") (" "OTA duplicated" ")"); do { MOZ_CrashSequence(__null, 3937
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
;
3938
3939 if (mStopped) {
3940 LOG(("WebSocketChannel::OnStartRequest: Channel Already Done\n"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OnStartRequest: Channel Already Done\n"
); } } while (0)
;
3941 AbortSession(NS_ERROR_WEBSOCKET_CONNECTION_REFUSED);
3942 return NS_ERROR_WEBSOCKET_CONNECTION_REFUSED;
3943 }
3944
3945 nsresult rv;
3946 uint32_t status;
3947 char *val, *token;
3948
3949 rv = mHttpChannel->GetResponseStatus(&status);
3950 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
3951 nsresult httpStatus;
3952 rv = NS_ERROR_WEBSOCKET_CONNECTION_REFUSED;
3953
3954 // If we failed to connect due to unsuccessful TLS handshake, we must
3955 // propagate a specific error to mozilla::dom::WebSocketImpl so it can set
3956 // status code to 1015. Otherwise return
3957 // NS_ERROR_WEBSOCKET_CONNECTION_REFUSED.
3958 if (NS_SUCCEEDED(mHttpChannel->GetStatus(&httpStatus))((bool)(__builtin_expect(!!(!NS_FAILED_impl(mHttpChannel->
GetStatus(&httpStatus))), 1)))
) {
3959 uint32_t errorClass;
3960 nsCOMPtr<nsINSSErrorsService> errSvc;
3961 errSvc = mozilla::components::NSSErrors::Service();
3962 // If GetErrorClass succeeds httpStatus is TLS related failure.
3963 if (errSvc &&
3964 NS_SUCCEEDED(errSvc->GetErrorClass(httpStatus, &errorClass))((bool)(__builtin_expect(!!(!NS_FAILED_impl(errSvc->GetErrorClass
(httpStatus, &errorClass))), 1)))
) {
3965 rv = NS_ERROR_NET_INADEQUATE_SECURITY;
3966 }
3967 }
3968
3969 LOG(("WebSocketChannel::OnStartRequest: No HTTP Response\n"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OnStartRequest: No HTTP Response\n"
); } } while (0)
;
3970 AbortSession(rv);
3971 return rv;
3972 }
3973
3974 LOG(("WebSocketChannel::OnStartRequest: HTTP status %d\n", status))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OnStartRequest: HTTP status %d\n"
, status); } } while (0)
;
3975 nsCOMPtr<nsIHttpChannelInternal> internalChannel =
3976 do_QueryInterface(mHttpChannel);
3977 uint32_t versionMajor, versionMinor;
3978 rv = internalChannel->GetResponseVersion(&versionMajor, &versionMinor);
3979 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) ||
3980 !((versionMajor == 1 && versionMinor != 0) || versionMajor == 2) ||
3981 (versionMajor == 1 && status != 101) ||
3982 (versionMajor == 2 && status != 200)) {
3983 AbortSession(NS_ERROR_WEBSOCKET_CONNECTION_REFUSED);
3984 return NS_ERROR_WEBSOCKET_CONNECTION_REFUSED;
3985 }
3986
3987 if (versionMajor == 1) {
3988 // These are only present on http/1.x websocket upgrades
3989 nsAutoCString respUpgrade;
3990 rv = mHttpChannel->GetResponseHeader("Upgrade"_ns, respUpgrade);
3991
3992 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
3993 rv = NS_ERROR_ILLEGAL_VALUE;
3994 if (!respUpgrade.IsEmpty()) {
3995 val = respUpgrade.BeginWriting();
3996 while ((token = nsCRT::strtok(val, ", \t", &val))) {
3997 if (nsCRT::strcasecmp(token, "Websocket") == 0) {
3998 rv = NS_OK;
3999 break;
4000 }
4001 }
4002 }
4003 }
4004
4005 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
4006 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OnStartRequest: "
"HTTP response header Upgrade: websocket not found\n"); } } while
(0)
4007 ("WebSocketChannel::OnStartRequest: "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OnStartRequest: "
"HTTP response header Upgrade: websocket not found\n"); } } while
(0)
4008 "HTTP response header Upgrade: websocket not found\n"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OnStartRequest: "
"HTTP response header Upgrade: websocket not found\n"); } } while
(0)
;
4009 AbortSession(NS_ERROR_ILLEGAL_VALUE);
4010 return rv;
4011 }
4012
4013 nsAutoCString respConnection;
4014 rv = mHttpChannel->GetResponseHeader("Connection"_ns, respConnection);
4015
4016 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
4017 rv = NS_ERROR_ILLEGAL_VALUE;
4018 if (!respConnection.IsEmpty()) {
4019 val = respConnection.BeginWriting();
4020 while ((token = nsCRT::strtok(val, ", \t", &val))) {
4021 if (nsCRT::strcasecmp(token, "Upgrade") == 0) {
4022 rv = NS_OK;
4023 break;
4024 }
4025 }
4026 }
4027 }
4028
4029 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
4030 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OnStartRequest: "
"HTTP response header 'Connection: Upgrade' not found\n"); }
} while (0)
4031 ("WebSocketChannel::OnStartRequest: "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OnStartRequest: "
"HTTP response header 'Connection: Upgrade' not found\n"); }
} while (0)
4032 "HTTP response header 'Connection: Upgrade' not found\n"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OnStartRequest: "
"HTTP response header 'Connection: Upgrade' not found\n"); }
} while (0)
;
4033 AbortSession(NS_ERROR_ILLEGAL_VALUE);
4034 return rv;
4035 }
4036
4037 nsAutoCString respAccept;
4038 rv = mHttpChannel->GetResponseHeader("Sec-WebSocket-Accept"_ns, respAccept);
4039
4040 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) || respAccept.IsEmpty() ||
4041 !respAccept.Equals(mHashedSecret)) {
4042 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OnStartRequest: "
"HTTP response header Sec-WebSocket-Accept check failed\n");
} } while (0)
4043 ("WebSocketChannel::OnStartRequest: "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OnStartRequest: "
"HTTP response header Sec-WebSocket-Accept check failed\n");
} } while (0)
4044 "HTTP response header Sec-WebSocket-Accept check failed\n"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OnStartRequest: "
"HTTP response header Sec-WebSocket-Accept check failed\n");
} } while (0)
;
4045 LOG(("WebSocketChannel::OnStartRequest: Expected %s received %s\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OnStartRequest: Expected %s received %s\n"
, mHashedSecret.get(), respAccept.get()); } } while (0)
4046 mHashedSecret.get(), respAccept.get()))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OnStartRequest: Expected %s received %s\n"
, mHashedSecret.get(), respAccept.get()); } } while (0)
;
4047#ifdef FUZZING
4048 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) || respAccept.IsEmpty()) {
4049#endif
4050 AbortSession(NS_ERROR_ILLEGAL_VALUE);
4051 return NS_ERROR_ILLEGAL_VALUE;
4052#ifdef FUZZING
4053 }
4054#endif
4055 }
4056 }
4057
4058 // If we sent a sub protocol header, verify the response matches.
4059 // If response contains protocol that was not in request, fail.
4060 // If response contained no protocol header, set to "" so the protocol
4061 // attribute of the WebSocket JS object reflects that
4062 if (!mProtocol.IsEmpty()) {
4063 nsAutoCString respProtocol;
4064 rv = mHttpChannel->GetResponseHeader("Sec-WebSocket-Protocol"_ns,
4065 respProtocol);
4066 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
4067 rv = NS_ERROR_ILLEGAL_VALUE;
4068 val = mProtocol.BeginWriting();
4069 while ((token = nsCRT::strtok(val, ", \t", &val))) {
4070 if (strcmp(token, respProtocol.get()) == 0) {
4071 rv = NS_OK;
4072 break;
4073 }
4074 }
4075
4076 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
4077 LOG(("WebsocketChannel::OnStartRequest: subprotocol %s confirmed",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebsocketChannel::OnStartRequest: subprotocol %s confirmed"
, respProtocol.get()); } } while (0)
4078 respProtocol.get()))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebsocketChannel::OnStartRequest: subprotocol %s confirmed"
, respProtocol.get()); } } while (0)
;
4079 mProtocol = std::move(respProtocol);
4080 } else {
4081 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebsocketChannel::OnStartRequest: "
"Server replied with non-matching subprotocol [%s]: aborting"
, respProtocol.get()); } } while (0)
4082 ("WebsocketChannel::OnStartRequest: "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebsocketChannel::OnStartRequest: "
"Server replied with non-matching subprotocol [%s]: aborting"
, respProtocol.get()); } } while (0)
4083 "Server replied with non-matching subprotocol [%s]: aborting",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebsocketChannel::OnStartRequest: "
"Server replied with non-matching subprotocol [%s]: aborting"
, respProtocol.get()); } } while (0)
4084 respProtocol.get()))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebsocketChannel::OnStartRequest: "
"Server replied with non-matching subprotocol [%s]: aborting"
, respProtocol.get()); } } while (0)
;
4085 mProtocol.Truncate();
4086 AbortSession(NS_ERROR_ILLEGAL_VALUE);
4087 return NS_ERROR_ILLEGAL_VALUE;
4088 }
4089 } else {
4090 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebsocketChannel::OnStartRequest "
"subprotocol [%s] not found - none returned", mProtocol.get(
)); } } while (0)
4091 ("WebsocketChannel::OnStartRequest "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebsocketChannel::OnStartRequest "
"subprotocol [%s] not found - none returned", mProtocol.get(
)); } } while (0)
4092 "subprotocol [%s] not found - none returned",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebsocketChannel::OnStartRequest "
"subprotocol [%s] not found - none returned", mProtocol.get(
)); } } while (0)
4093 mProtocol.get()))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebsocketChannel::OnStartRequest "
"subprotocol [%s] not found - none returned", mProtocol.get(
)); } } while (0)
;
4094 mProtocol.Truncate();
4095 }
4096 }
4097
4098 rv = HandleExtensions();
4099 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) return rv;
4100
4101 // Update mEffectiveURL for off main thread URI access.
4102 nsCOMPtr<nsIURI> uri = mURI ? mURI : mOriginalURI;
4103 nsAutoCString spec;
4104 rv = uri->GetSpec(spec);
4105 MOZ_ASSERT(NS_SUCCEEDED(rv))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
)))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)
))))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 4105); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))"
")"); do { MOZ_CrashSequence(__null, 4105); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4106 CopyUTF8toUTF16(spec, mEffectiveURL);
4107
4108 mGotUpgradeOK = 1;
4109 if (mRecvdHttpUpgradeTransport) {
4110 // We're now done CONNECTING, which means we can now open another,
4111 // perhaps parallel, connection to the same host if one
4112 // is pending
4113 nsWSAdmissionManager::OnConnected(this);
4114
4115 return CallStartWebsocketData();
4116 }
4117
4118 return NS_OK;
4119}
4120
4121NS_IMETHODIMPnsresult
4122WebSocketChannel::OnStopRequest(nsIRequest* aRequest, nsresult aStatusCode) {
4123 LOG(("WebSocketChannel::OnStopRequest() %p [%p %p %" PRIx32 "]\n", this,do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OnStopRequest() %p [%p %p %"
"x" "]\n", this, aRequest, mHttpChannel.get(), static_cast<
uint32_t>(aStatusCode)); } } while (0)
4124 aRequest, mHttpChannel.get(), static_cast<uint32_t>(aStatusCode)))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OnStopRequest() %p [%p %p %"
"x" "]\n", this, aRequest, mHttpChannel.get(), static_cast<
uint32_t>(aStatusCode)); } } while (0)
;
4125 MOZ_ASSERT(NS_IsMainThread(), "not main thread")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
" (" "not main thread" ")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 4125); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
") (" "not main thread" ")"); do { MOZ_CrashSequence(__null,
4125); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false)
;
4126
4127 // OnTransportAvailable won't be called if the request is stopped with
4128 // an error. Abort the session now instead of waiting for timeout.
4129 if (NS_FAILED(aStatusCode)((bool)(__builtin_expect(!!(NS_FAILED_impl(aStatusCode)), 0))
)
&& !mRecvdHttpUpgradeTransport) {
4130 AbortSession(aStatusCode);
4131 }
4132
4133 ReportConnectionTelemetry(aStatusCode);
4134
4135 // This is the end of the HTTP upgrade transaction, the
4136 // upgraded streams live on
4137
4138 mChannel = nullptr;
4139 mHttpChannel = nullptr;
4140 mLoadGroup = nullptr;
4141 mCallbacks = nullptr;
4142
4143 return NS_OK;
4144}
4145
4146// nsIInputStreamCallback
4147
4148NS_IMETHODIMPnsresult
4149WebSocketChannel::OnInputStreamReady(nsIAsyncInputStream* aStream) {
4150 LOG(("WebSocketChannel::OnInputStreamReady() %p\n", this))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OnInputStreamReady() %p\n"
, this); } } while (0)
;
4151 MOZ_DIAGNOSTIC_ASSERT(mIOThread->IsOnCurrentThread(), "not on right thread")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mIOThread->IsOnCurrentThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mIOThread->IsOnCurrentThread
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mIOThread->IsOnCurrentThread()" " (" "not on right thread"
")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 4151); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "mIOThread->IsOnCurrentThread()"
") (" "not on right thread" ")"); do { MOZ_CrashSequence(__null
, 4151); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
4152
4153 if (!mSocketIn) { // did we we clean up the socket after scheduling
4154 // InputReady?
4155 return NS_OK;
4156 }
4157
4158 // this is after the http upgrade - so we are speaking websockets
4159 char buffer[2048];
4160 uint32_t count;
4161 nsresult rv;
4162
4163 do {
4164 rv = mSocketIn->Read((char*)buffer, sizeof(buffer), &count);
4165 LOG(("WebSocketChannel::OnInputStreamReady: read %u rv %" PRIx32 "\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OnInputStreamReady: read %u rv %"
"x" "\n", count, static_cast<uint32_t>(rv)); } } while
(0)
4166 count, static_cast<uint32_t>(rv)))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OnInputStreamReady: read %u rv %"
"x" "\n", count, static_cast<uint32_t>(rv)); } } while
(0)
;
4167
4168 if (rv == NS_BASE_STREAM_WOULD_BLOCK) {
4169 mSocketIn->AsyncWait(this, 0, 0, mIOThread);
4170 return NS_OK;
4171 }
4172
4173 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
4174 AbortSession(rv);
4175 return rv;
4176 }
4177
4178 if (count == 0) {
4179 AbortSession(NS_BASE_STREAM_CLOSED);
4180 return NS_OK;
4181 }
4182
4183 if (mStopped) {
4184 continue;
4185 }
4186
4187 rv = ProcessInput((uint8_t*)buffer, count);
4188 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
4189 AbortSession(rv);
4190 return rv;
4191 }
4192 } while (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) && mSocketIn);
4193
4194 return NS_OK;
4195}
4196
4197// nsIOutputStreamCallback
4198
4199NS_IMETHODIMPnsresult
4200WebSocketChannel::OnOutputStreamReady(nsIAsyncOutputStream* aStream) {
4201 LOG(("WebSocketChannel::OnOutputStreamReady() %p\n", this))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OnOutputStreamReady() %p\n"
, this); } } while (0)
;
4202 MOZ_DIAGNOSTIC_ASSERT(mIOThread->IsOnCurrentThread(), "not on right thread")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mIOThread->IsOnCurrentThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mIOThread->IsOnCurrentThread
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mIOThread->IsOnCurrentThread()" " (" "not on right thread"
")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 4202); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "mIOThread->IsOnCurrentThread()"
") (" "not on right thread" ")"); do { MOZ_CrashSequence(__null
, 4202); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
4203 nsresult rv;
4204
4205 if (!mCurrentOut) PrimeNewOutgoingMessage();
4206
4207 while (mCurrentOut && mSocketOut) {
4208 const char* sndBuf;
4209 uint32_t toSend;
4210 uint32_t amtSent;
4211
4212 if (mHdrOut) {
4213 sndBuf = (const char*)mHdrOut;
4214 toSend = mHdrOutToSend;
4215 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OnOutputStreamReady: "
"Try to send %u of hdr/copybreak\n", toSend); } } while (0)
4216 ("WebSocketChannel::OnOutputStreamReady: "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OnOutputStreamReady: "
"Try to send %u of hdr/copybreak\n", toSend); } } while (0)
4217 "Try to send %u of hdr/copybreak\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OnOutputStreamReady: "
"Try to send %u of hdr/copybreak\n", toSend); } } while (0)
4218 toSend))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OnOutputStreamReady: "
"Try to send %u of hdr/copybreak\n", toSend); } } while (0)
;
4219 } else {
4220 sndBuf = (char*)mCurrentOut->BeginReading() + mCurrentOutSent;
4221 toSend = mCurrentOut->Length() - mCurrentOutSent;
4222 if (toSend > 0) {
4223 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OnOutputStreamReady [%p]: "
"Try to send %u of data\n", this, toSend); } } while (0)
4224 ("WebSocketChannel::OnOutputStreamReady [%p]: "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OnOutputStreamReady [%p]: "
"Try to send %u of data\n", this, toSend); } } while (0)
4225 "Try to send %u of data\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OnOutputStreamReady [%p]: "
"Try to send %u of data\n", this, toSend); } } while (0)
4226 this, toSend))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OnOutputStreamReady [%p]: "
"Try to send %u of data\n", this, toSend); } } while (0)
;
4227 }
4228 }
4229
4230 if (toSend == 0) {
4231 amtSent = 0;
4232 } else {
4233 rv = mSocketOut->Write(sndBuf, toSend, &amtSent);
4234 LOG(("WebSocketChannel::OnOutputStreamReady [%p]: write %u rv %" PRIx32do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OnOutputStreamReady [%p]: write %u rv %"
"x" "\n", this, amtSent, static_cast<uint32_t>(rv)); }
} while (0)
4235 "\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OnOutputStreamReady [%p]: write %u rv %"
"x" "\n", this, amtSent, static_cast<uint32_t>(rv)); }
} while (0)
4236 this, amtSent, static_cast<uint32_t>(rv)))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OnOutputStreamReady [%p]: write %u rv %"
"x" "\n", this, amtSent, static_cast<uint32_t>(rv)); }
} while (0)
;
4237
4238 if (rv == NS_BASE_STREAM_WOULD_BLOCK) {
4239 mSocketOut->AsyncWait(this, 0, 0, mIOThread);
4240 return NS_OK;
4241 }
4242
4243 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
4244 AbortSession(rv);
4245 return NS_OK;
4246 }
4247 }
4248
4249 if (mHdrOut) {
4250 if (amtSent == toSend) {
4251 mHdrOut = nullptr;
4252 mHdrOutToSend = 0;
4253 } else {
4254 mHdrOut += amtSent;
4255 mHdrOutToSend -= amtSent;
4256 mSocketOut->AsyncWait(this, 0, 0, mIOThread);
4257 }
4258 } else {
4259 if (amtSent == toSend) {
4260 if (RefPtr<BaseWebSocketChannel::ListenerAndContextContainer> listener =
4261 GetListenerMT()) {
4262 if (nsCOMPtr<nsIEventTarget> target = GetTargetThread()) {
4263 target->Dispatch(new CallAcknowledge(this, std::move(listener),
4264 mCurrentOut->OrigLength()),
4265 NS_DISPATCH_NORMALnsIEventTarget::DISPATCH_NORMAL);
4266 } else {
4267 return NS_ERROR_UNEXPECTED;
4268 }
4269 }
4270 DeleteCurrentOutGoingMessage();
4271 PrimeNewOutgoingMessage();
4272 } else {
4273 mCurrentOutSent += amtSent;
4274 mSocketOut->AsyncWait(this, 0, 0, mIOThread);
4275 }
4276 }
4277 }
4278
4279 if (mReleaseOnTransmit) ReleaseSession();
4280 return NS_OK;
4281}
4282
4283// nsIStreamListener
4284
4285NS_IMETHODIMPnsresult
4286WebSocketChannel::OnDataAvailable(nsIRequest* aRequest,
4287 nsIInputStream* aInputStream,
4288 uint64_t aOffset, uint32_t aCount) {
4289 LOG(("WebSocketChannel::OnDataAvailable() %p [%p %p %p %" PRIu64 " %u]\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OnDataAvailable() %p [%p %p %p %"
"l" "u" " %u]\n", this, aRequest, mHttpChannel.get(), aInputStream
, aOffset, aCount); } } while (0)
4290 this, aRequest, mHttpChannel.get(), aInputStream, aOffset, aCount))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OnDataAvailable() %p [%p %p %p %"
"l" "u" " %u]\n", this, aRequest, mHttpChannel.get(), aInputStream
, aOffset, aCount); } } while (0)
;
4291
4292 // This is the HTTP OnDataAvailable Method, which means this is http data in
4293 // response to the upgrade request and there should be no http response body
4294 // if the upgrade succeeded. This generally should be caught by a non 101
4295 // response code in OnStartRequest().. so we can ignore the data here
4296
4297 LOG(("WebSocketChannel::OnDataAvailable: HTTP data unexpected len>=%u\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OnDataAvailable: HTTP data unexpected len>=%u\n"
, aCount); } } while (0)
4298 aCount))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::OnDataAvailable: HTTP data unexpected len>=%u\n"
, aCount); } } while (0)
;
4299
4300 return NS_OK;
4301}
4302
4303void WebSocketChannel::DoEnqueueOutgoingMessage() {
4304 LOG(("WebSocketChannel::DoEnqueueOutgoingMessage() %p\n", this))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::DoEnqueueOutgoingMessage() %p\n"
, this); } } while (0)
;
4305 MOZ_ASSERT(mIOThread->IsOnCurrentThread(), "not on right thread")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mIOThread->IsOnCurrentThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mIOThread->IsOnCurrentThread
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mIOThread->IsOnCurrentThread()" " (" "not on right thread"
")", "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 4305); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mIOThread->IsOnCurrentThread()"
") (" "not on right thread" ")"); do { MOZ_CrashSequence(__null
, 4305); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
4306
4307 if (!mCurrentOut) {
4308 PrimeNewOutgoingMessage();
4309 }
4310
4311 while (mCurrentOut && mConnection) {
4312 nsresult rv = NS_OK;
4313 if (mCurrentOut->Length() - mCurrentOutSent == 0) {
4314 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::DoEnqueueOutgoingMessage: "
"Try to send %u of hdr/copybreak\n", mHdrOutToSend); } } while
(0)
4315 ("WebSocketChannel::DoEnqueueOutgoingMessage: "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::DoEnqueueOutgoingMessage: "
"Try to send %u of hdr/copybreak\n", mHdrOutToSend); } } while
(0)
4316 "Try to send %u of hdr/copybreak\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::DoEnqueueOutgoingMessage: "
"Try to send %u of hdr/copybreak\n", mHdrOutToSend); } } while
(0)
4317 mHdrOutToSend))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::DoEnqueueOutgoingMessage: "
"Try to send %u of hdr/copybreak\n", mHdrOutToSend); } } while
(0)
;
4318 rv = mConnection->WriteOutputData(mOutHeader, mHdrOutToSend, nullptr, 0);
4319 } else {
4320 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::DoEnqueueOutgoingMessage: "
"Try to send %u of hdr and %u of data\n", mHdrOutToSend, mCurrentOut
->Length()); } } while (0)
4321 ("WebSocketChannel::DoEnqueueOutgoingMessage: "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::DoEnqueueOutgoingMessage: "
"Try to send %u of hdr and %u of data\n", mHdrOutToSend, mCurrentOut
->Length()); } } while (0)
4322 "Try to send %u of hdr and %u of data\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::DoEnqueueOutgoingMessage: "
"Try to send %u of hdr and %u of data\n", mHdrOutToSend, mCurrentOut
->Length()); } } while (0)
4323 mHdrOutToSend, mCurrentOut->Length()))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::DoEnqueueOutgoingMessage: "
"Try to send %u of hdr and %u of data\n", mHdrOutToSend, mCurrentOut
->Length()); } } while (0)
;
4324 rv = mConnection->WriteOutputData(mOutHeader, mHdrOutToSend,
4325 (uint8_t*)mCurrentOut->BeginReading(),
4326 mCurrentOut->Length());
4327 }
4328
4329 LOG(("WebSocketChannel::DoEnqueueOutgoingMessage: rv %" PRIx32 "\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::DoEnqueueOutgoingMessage: rv %"
"x" "\n", static_cast<uint32_t>(rv)); } } while (0)
4330 static_cast<uint32_t>(rv)))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::DoEnqueueOutgoingMessage: rv %"
"x" "\n", static_cast<uint32_t>(rv)); } } while (0)
;
4331 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
4332 AbortSession(rv);
4333 return;
4334 }
4335
4336 if (RefPtr<BaseWebSocketChannel::ListenerAndContextContainer> listener =
4337 GetListenerMT()) {
4338 // TODO: Currently, we assume that data is completely written to the
4339 // socket after sending it to socket process, but it's not true. The data
4340 // could be queued in socket process and waiting for the socket to be able
4341 // to write. We should implement flow control for this in bug 1726552.
4342 if (nsCOMPtr<nsIEventTarget> target = GetTargetThread()) {
4343 target->Dispatch(new CallAcknowledge(this, std::move(listener),
4344 mCurrentOut->OrigLength()),
4345 NS_DISPATCH_NORMALnsIEventTarget::DISPATCH_NORMAL);
4346 } else {
4347 AbortSession(NS_ERROR_UNEXPECTED);
4348 return;
4349 }
4350 }
4351 DeleteCurrentOutGoingMessage();
4352 PrimeNewOutgoingMessage();
4353 }
4354
4355 if (mReleaseOnTransmit) {
4356 ReleaseSession();
4357 }
4358}
4359
4360void WebSocketChannel::OnError(nsresult aStatus) { AbortSession(aStatus); }
4361
4362void WebSocketChannel::OnTCPClosed() { mTCPClosed = true; }
4363
4364nsresult WebSocketChannel::OnDataReceived(uint8_t* aData, uint32_t aCount) {
4365 nsresult rv = ProcessInput(aData, aCount);
4366 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
4367 mFragmentAccumulator = 0;
4368 mFragmentOpcode = nsIWebSocketFrame::OPCODE_CONTINUATION;
4369 mBuffered = 0;
4370 }
4371 return rv;
4372}
4373
4374} // namespace mozilla::net
4375
4376#undef CLOSE_GOING_AWAY