Bug Summary

File:root/firefox-clang/obj-x86_64-pc-linux-gnu/netwerk/protocol/websocket/./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp
Warning:line 2712, 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/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-11-12-001017-1011516-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 "WebSocketFrame.h"
10#include "WebSocketLog.h"
11#include "mozilla/Atomics.h"
12#include "mozilla/Attributes.h"
13#include "mozilla/Base64.h"
14#include "mozilla/Components.h"
15#include "mozilla/EndianUtils.h"
16#include "mozilla/MathAlgorithms.h"
17#include "mozilla/ScopeExit.h"
18#include "mozilla/StaticMutex.h"
19#include "mozilla/StaticPrefs_privacy.h"
20#include "mozilla/TimeStamp.h"
21#include "mozilla/Utf8.h"
22#include "mozilla/glean/NetwerkProtocolWebsocketMetrics.h"
23#include "mozilla/net/WebSocketEventService.h"
24#include "nsCRT.h"
25#include "nsCharSeparatedTokenizer.h"
26#include "nsComponentManagerUtils.h"
27#include "nsError.h"
28#include "nsIAsyncVerifyRedirectCallback.h"
29#include "nsICancelable.h"
30#include "nsIChannel.h"
31#include "nsIClassOfService.h"
32#include "nsICryptoHash.h"
33#include "nsIDNSRecord.h"
34#include "nsIDNSService.h"
35#include "nsIDashboardEventNotifier.h"
36#include "nsIEventTarget.h"
37#include "nsIHttpChannel.h"
38#include "nsIIOService.h"
39#include "nsINSSErrorsService.h"
40#include "nsINetworkLinkService.h"
41#include "nsINode.h"
42#include "nsIObserverService.h"
43#include "nsIPrefBranch.h"
44#include "nsIProtocolProxyService.h"
45#include "nsIProxiedChannel.h"
46#include "nsIProxyInfo.h"
47#include "nsIRandomGenerator.h"
48#include "nsIRunnable.h"
49#include "nsISocketTransport.h"
50#include "nsITLSSocketControl.h"
51#include "nsITransportProvider.h"
52#include "nsITransportSecurityInfo.h"
53#include "nsIURI.h"
54#include "nsIURIMutator.h"
55#include "nsNetCID.h"
56#include "nsNetUtil.h"
57#include "nsProxyRelease.h"
58#include "nsServiceManagerUtils.h"
59#include "nsSocketTransportService2.h"
60#include "nsStringStream.h"
61#include "nsThreadUtils.h"
62#include "plbase64.h"
63#include "prmem.h"
64#include "prnetdb.h"
65#include "zlib.h"
66
67// rather than slurp up all of nsIWebSocket.idl, which lives outside necko, just
68// dupe one constant we need from it
69#define CLOSE_GOING_AWAY 1001
70
71using namespace mozilla;
72using namespace mozilla::net;
73
74namespace mozilla::net {
75
76NS_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"
, 81); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { MOZ_CrashSequence(__null, 81
); __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"
, 81); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"WebSocketChannel\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 81); __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"
, 81); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { MOZ_CrashSequence(__null, 81)
; __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"
, 81); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"WebSocketChannel\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 81); __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"
, 81); 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; }
77 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"
, 81); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { MOZ_CrashSequence(__null, 81
); __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"
, 81); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"WebSocketChannel\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 81); __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"
, 81); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { MOZ_CrashSequence(__null, 81)
; __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"
, 81); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"WebSocketChannel\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 81); __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"
, 81); 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 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"
, 81); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { MOZ_CrashSequence(__null, 81
); __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"
, 81); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"WebSocketChannel\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 81); __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"
, 81); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { MOZ_CrashSequence(__null, 81)
; __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"
, 81); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"WebSocketChannel\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 81); __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"
, 81); 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 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"
, 81); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { MOZ_CrashSequence(__null, 81
); __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"
, 81); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"WebSocketChannel\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 81); __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"
, 81); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { MOZ_CrashSequence(__null, 81)
; __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"
, 81); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"WebSocketChannel\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 81); __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"
, 81); 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 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"
, 81); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { MOZ_CrashSequence(__null, 81
); __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"
, 81); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"WebSocketChannel\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 81); __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"
, 81); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { MOZ_CrashSequence(__null, 81)
; __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"
, 81); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"WebSocketChannel\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 81); __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"
, 81); 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 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"
, 81); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { MOZ_CrashSequence(__null, 81
); __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"
, 81); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"WebSocketChannel\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 81); __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"
, 81); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { MOZ_CrashSequence(__null, 81)
; __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"
, 81); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"WebSocketChannel\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 81); __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"
, 81); 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
83// We implement RFC 6455, which uses Sec-WebSocket-Version: 13 on the wire.
84#define SEC_WEBSOCKET_VERSION"13" "13"
85
86/*
87 * About SSL unsigned certificates
88 *
89 * wss will not work to a host using an unsigned certificate unless there
90 * is already an exception (i.e. it cannot popup a dialog asking for
91 * a security exception). This is similar to how an inlined img will
92 * fail without a dialog if fails for the same reason. This should not
93 * be a problem in practice as it is expected the websocket javascript
94 * is served from the same host as the websocket server (or of course,
95 * a valid cert could just be provided).
96 *
97 */
98
99// some helper classes
100
101//-----------------------------------------------------------------------------
102// FailDelayManager
103//
104// Stores entries (searchable by {host, port}) of connections that have recently
105// failed, so we can do delay of reconnects per RFC 6455 Section 7.2.3
106//-----------------------------------------------------------------------------
107
108// Initial reconnect delay is randomly chosen between 200-400 ms.
109// This is a gentler backoff than the 0-5 seconds the spec offhandedly suggests.
110const uint32_t kWSReconnectInitialBaseDelay = 200;
111const uint32_t kWSReconnectInitialRandomDelay = 200;
112
113// Base lifetime (in ms) of a FailDelay: kept longer if more failures occur
114const uint32_t kWSReconnectBaseLifeTime = 60 * 1000;
115// Maximum reconnect delay (in ms)
116const uint32_t kWSReconnectMaxDelay = 60 * 1000;
117
118// hold record of failed connections, and calculates needed delay for reconnects
119// to same host/path/port.
120class FailDelay {
121 public:
122 FailDelay(nsCString address, nsCString path, int32_t port,
123 nsCString originSuffix)
124 : mAddress(std::move(address)),
125 mPath(std::move(path)),
126 mPort(port),
127 mOriginSuffix(std::move(originSuffix)) {
128 mLastFailure = TimeStamp::Now();
129 mNextDelay = kWSReconnectInitialBaseDelay +
130 (rand() % kWSReconnectInitialRandomDelay);
131 }
132
133 // Called to update settings when connection fails again.
134 void FailedAgain() {
135 mLastFailure = TimeStamp::Now();
136 // We use a truncated exponential backoff as suggested by RFC 6455,
137 // but multiply by 1.5 instead of 2 to be more gradual.
138 mNextDelay = static_cast<uint32_t>(
139 std::min<double>(kWSReconnectMaxDelay, mNextDelay * 1.5));
140 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)
141 ("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)
142 "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)
143 "%" 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)
144 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)
;
145 }
146
147 // returns 0 if there is no need to delay (i.e. delay interval is over)
148 uint32_t RemainingDelay(TimeStamp rightNow) {
149 TimeDuration dur = rightNow - mLastFailure;
150 uint32_t sinceFail = (uint32_t)dur.ToMilliseconds();
151 if (sinceFail > mNextDelay) return 0;
152
153 return mNextDelay - sinceFail;
154 }
155
156 bool IsExpired(TimeStamp rightNow) {
157 return (mLastFailure + TimeDuration::FromMilliseconds(
158 kWSReconnectBaseLifeTime + mNextDelay)) <=
159 rightNow;
160 }
161
162 nsCString mAddress; // IP address (or hostname if using proxy)
163 nsCString mPath;
164 int32_t mPort;
165 nsCString mOriginSuffix;
166
167 private:
168 TimeStamp mLastFailure; // Time of last failed attempt
169 // mLastFailure + mNextDelay is the soonest we'll allow a reconnect
170 uint32_t mNextDelay; // milliseconds
171};
172
173class FailDelayManager {
174 public:
175 FailDelayManager() {
176 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)
;
177
178 mDelaysDisabled = false;
179
180 nsCOMPtr<nsIPrefBranch> prefService;
181 prefService = mozilla::components::Preferences::Service();
182 if (!prefService) {
183 return;
184 }
185 bool boolpref = true;
186 nsresult rv;
187 rv = prefService->GetBoolPref("network.websocket.delay-failed-reconnects",
188 &boolpref);
189 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) && !boolpref) {
190 mDelaysDisabled = true;
191 }
192 }
193
194 ~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)
; }
195
196 void Add(nsCString& address, nsCString& path, int32_t port,
197 nsCString& originSuffix) {
198 if (mDelaysDisabled) {
199 return;
200 }
201
202 mEntries.AppendElement(
203 std::make_unique<FailDelay>(address, path, port, originSuffix));
204 }
205
206 // Element returned may not be valid after next main thread event: don't keep
207 // pointer to it around
208 FailDelay* Lookup(nsCString& address, nsCString& path, int32_t port,
209 nsCString& originSuffix, uint32_t* outIndex = nullptr) {
210 if (mDelaysDisabled) {
211 return nullptr;
212 }
213
214 FailDelay* result = nullptr;
215 TimeStamp rightNow = TimeStamp::Now();
216
217 // We also remove expired entries during search: iterate from end to make
218 // indexing simpler
219 for (int32_t i = mEntries.Length() - 1; i >= 0; --i) {
220 FailDelay* fail = mEntries[i].get();
221 if (fail->mAddress.Equals(address) && fail->mPath.Equals(path) &&
222 fail->mPort == port && fail->mOriginSuffix.Equals(originSuffix)) {
223 if (outIndex) *outIndex = i;
224 result = fail;
225 // break here: removing more entries would mess up *outIndex.
226 // Any remaining expired entries will be deleted next time Lookup
227 // finds nothing, which is the most common case anyway.
228 break;
229 }
230 if (fail->IsExpired(rightNow)) {
231 mEntries.RemoveElementAt(i);
232 }
233 }
234 return result;
235 }
236
237 // returns true if channel connects immediately, or false if it's delayed
238 void DelayOrBegin(WebSocketChannel* ws) {
239 if (!mDelaysDisabled) {
240 uint32_t failIndex = 0;
241 FailDelay* fail = Lookup(ws->mAddress, ws->mPath, ws->mPort,
242 ws->mOriginSuffix, &failIndex);
243
244 if (fail) {
245 TimeStamp rightNow = TimeStamp::Now();
246
247 uint32_t remainingDelay = fail->RemainingDelay(rightNow);
248 if (remainingDelay) {
249 // reconnecting within delay interval: delay by remaining time
250 nsresult rv;
251 MutexAutoLock lock(ws->mMutex);
252 rv = NS_NewTimerWithCallback(getter_AddRefs(ws->mReconnectDelayTimer),
253 ws, remainingDelay,
254 nsITimer::TYPE_ONE_SHOT);
255 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
256 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)
257 ("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)
258 " 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)
259 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)
;
260 ws->mConnecting = CONNECTING_DELAYED;
261 return;
262 }
263 // if timer fails (which is very unlikely), drop down to BeginOpen
264 // call
265 } else if (fail->IsExpired(rightNow)) {
266 mEntries.RemoveElementAt(failIndex);
267 }
268 }
269 }
270
271 // Delays disabled, or no previous failure, or we're reconnecting after
272 // scheduled delay interval has passed: connect.
273 ws->BeginOpen(true);
274 }
275
276 // Remove() also deletes all expired entries as it iterates: better for
277 // battery life than using a periodic timer.
278 void Remove(nsCString& address, nsCString& path, int32_t port,
279 nsCString& originSuffix) {
280 TimeStamp rightNow = TimeStamp::Now();
281
282 // iterate from end, to make deletion indexing easier
283 for (int32_t i = mEntries.Length() - 1; i >= 0; --i) {
284 FailDelay* entry = mEntries[i].get();
285 if ((entry->mAddress.Equals(address) && entry->mPath.Equals(path) &&
286 entry->mPort == port && entry->mOriginSuffix.Equals(originSuffix)) ||
287 entry->IsExpired(rightNow)) {
288 mEntries.RemoveElementAt(i);
289 }
290 }
291 }
292
293 private:
294 nsTArray<UniquePtr<FailDelay>> mEntries;
295 bool mDelaysDisabled;
296};
297
298//-----------------------------------------------------------------------------
299// nsWSAdmissionManager
300//
301// 1) Ensures that only one websocket at a time is CONNECTING to a given IP
302// address (or hostname, if using proxy), per RFC 6455 Section 4.1.
303// 2) Delays reconnects to IP/host after connection failure, per Section 7.2.3
304//-----------------------------------------------------------------------------
305
306class nsWSAdmissionManager {
307 public:
308 static void Init() {
309 StaticMutexAutoLock lock(sLock);
310 if (!sManager) {
311 sManager = new nsWSAdmissionManager();
312 }
313 }
314
315 static void Shutdown() {
316 StaticMutexAutoLock lock(sLock);
317 delete sManager;
318 sManager = nullptr;
319 }
320
321 // Determine if we will open connection immediately (returns true), or
322 // delay/queue the connection (returns false)
323 static void ConditionallyConnect(WebSocketChannel* ws) {
324 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)
;
325 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"
, 325); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
") (" "not main thread" ")"); do { MOZ_CrashSequence(__null,
325); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false)
;
326 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"
, 326); AnnotateMozCrashReason("MOZ_ASSERT" "(" "ws->mConnecting == NOT_CONNECTING"
") (" "opening state" ")"); do { MOZ_CrashSequence(__null, 326
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
;
327
328 StaticMutexAutoLock lock(sLock);
329 if (!sManager) {
330 return;
331 }
332
333 // If there is already another WS channel connecting to this IP address,
334 // defer BeginOpen and mark as waiting in queue.
335 bool hostFound = (sManager->IndexOf(ws->mAddress, ws->mOriginSuffix) >= 0);
336
337 uint32_t failIndex = 0;
338 FailDelay* fail = sManager->mFailures.Lookup(
339 ws->mAddress, ws->mPath, ws->mPort, ws->mOriginSuffix, &failIndex);
340 bool existingFail = fail != nullptr;
341
342 // Always add ourselves to queue, even if we'll connect immediately
343 auto newdata = std::make_unique<nsOpenConn>(ws->mAddress, ws->mOriginSuffix,
344 existingFail, ws);
345
346 // If a connection has not previously failed then prioritize it over
347 // connections that have
348 if (existingFail) {
349 sManager->mQueue.AppendElement(std::move(newdata));
350 } else {
351 uint32_t insertionIndex = sManager->IndexOfFirstFailure();
352 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"
, 353); AnnotateMozCrashReason("MOZ_ASSERT" "(" "insertionIndex <= sManager->mQueue.Length()"
") (" "Insertion index outside bounds" ")"); do { MOZ_CrashSequence
(__null, 353); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
353 "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"
, 353); AnnotateMozCrashReason("MOZ_ASSERT" "(" "insertionIndex <= sManager->mQueue.Length()"
") (" "Insertion index outside bounds" ")"); do { MOZ_CrashSequence
(__null, 353); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
354 sManager->mQueue.InsertElementAt(insertionIndex, std::move(newdata));
355 }
356
357 if (hostFound) {
358 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)
359 ("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)
360 "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)
;
361 ws->mConnecting = CONNECTING_QUEUED;
362 } else {
363 sManager->mFailures.DelayOrBegin(ws);
364 }
365 }
366
367 static void OnConnected(WebSocketChannel* aChannel) {
368 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)
;
369
370 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"
, 370); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
") (" "not main thread" ")"); do { MOZ_CrashSequence(__null,
370); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false)
;
371 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"
, 372); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChannel->mConnecting == CONNECTING_IN_PROGRESS"
") (" "Channel completed connect, but not connecting?" ")");
do { MOZ_CrashSequence(__null, 372); __attribute__((nomerge)
) ::abort(); } while (false); } } while (false)
372 "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"
, 372); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChannel->mConnecting == CONNECTING_IN_PROGRESS"
") (" "Channel completed connect, but not connecting?" ")");
do { MOZ_CrashSequence(__null, 372); __attribute__((nomerge)
) ::abort(); } while (false); } } while (false)
;
373
374 StaticMutexAutoLock lock(sLock);
375 if (!sManager) {
376 return;
377 }
378
379 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)
;
380 aChannel->mConnecting = NOT_CONNECTING;
381
382 // Remove from queue
383 sManager->RemoveFromQueue(aChannel);
384
385 // Connection succeeded, so stop keeping track of any previous failures
386 sManager->mFailures.Remove(aChannel->mAddress, aChannel->mPath,
387 aChannel->mPort, aChannel->mOriginSuffix);
388
389 // Check for queued connections to same host.
390 // Note: still need to check for failures, since next websocket with same
391 // host may have different port
392 sManager->ConnectNext(aChannel->mAddress, aChannel->mOriginSuffix);
393 }
394
395 // Called every time a websocket channel ends its session (including going
396 // away w/o ever successfully creating a connection)
397 static void OnStopSession(WebSocketChannel* aChannel, nsresult aReason) {
398 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)
399 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)
;
400
401 StaticMutexAutoLock lock(sLock);
402 if (!sManager) {
403 return;
404 }
405
406 if (NS_FAILED(aReason)((bool)(__builtin_expect(!!(NS_FAILED_impl(aReason)), 0)))) {
407 // Have we seen this failure before?
408 FailDelay* knownFailure =
409 sManager->mFailures.Lookup(aChannel->mAddress, aChannel->mPath,
410 aChannel->mPort, aChannel->mOriginSuffix);
411 if (knownFailure) {
412 if (aReason == NS_ERROR_NOT_CONNECTED) {
413 // Don't count close() before connection as a network error
414 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)
415 ("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)
416 " [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)
417 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)
418 (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)
;
419 } else {
420 // repeated failure to connect: increase delay for next connection
421 knownFailure->FailedAgain();
422 }
423 } else {
424 // new connection failure: record it.
425 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)
426 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)
427 (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)
;
428 sManager->mFailures.Add(aChannel->mAddress, aChannel->mPath,
429 aChannel->mPort, aChannel->mOriginSuffix);
430 }
431 }
432
433 if (NS_IsMainThread()) {
434 ContinueOnStopSession(aChannel, aReason);
435 } else {
436 NS_DispatchToMainThread(NS_NewRunnableFunction(
437 "nsWSAdmissionManager::ContinueOnStopSession",
438 [channel = RefPtr{aChannel}, reason = aReason]() {
439 StaticMutexAutoLock lock(sLock);
440 if (!sManager) {
441 return;
442 }
443
444 nsWSAdmissionManager::ContinueOnStopSession(channel, reason);
445 }));
446 }
447 }
448
449 static void ContinueOnStopSession(WebSocketChannel* aChannel,
450 nsresult aReason) {
451 sLock.AssertCurrentThreadOwns();
452 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"
, 452); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
") (" "not main thread" ")"); do { MOZ_CrashSequence(__null,
452); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false)
;
453
454 if (!aChannel->mConnecting) {
455 return;
456 }
457
458 // Only way a connecting channel may get here w/o failing is if it
459 // was closed with GOING_AWAY (1001) because of navigation, tab
460 // close, etc.
461#ifdef DEBUG1
462 {
463 MutexAutoLock lock(aChannel->mMutex);
464 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"
, 466); 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, 466); __attribute__((nomerge)
) ::abort(); } while (false); } } while (false)
465 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"
, 466); 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, 466); __attribute__((nomerge)
) ::abort(); } while (false); } } while (false)
466 "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"
, 466); 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, 466); __attribute__((nomerge)
) ::abort(); } while (false); } } while (false)
;
467 }
468#endif
469 (void)aReason;
470
471 sManager->RemoveFromQueue(aChannel);
472
473 bool wasNotQueued = (aChannel->mConnecting != CONNECTING_QUEUED);
474 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)
;
475 aChannel->mConnecting = NOT_CONNECTING;
476 if (wasNotQueued) {
477 sManager->ConnectNext(aChannel->mAddress, aChannel->mOriginSuffix);
478 }
479 }
480
481 static void IncrementSessionCount() {
482 StaticMutexAutoLock lock(sLock);
483 if (!sManager) {
484 return;
485 }
486 sManager->mSessionCount++;
487 }
488
489 static void DecrementSessionCount() {
490 StaticMutexAutoLock lock(sLock);
491 if (!sManager) {
492 return;
493 }
494 sManager->mSessionCount--;
495 }
496
497 static void GetSessionCount(int32_t& aSessionCount) {
498 StaticMutexAutoLock lock(sLock);
499 if (!sManager) {
500 return;
501 }
502 aSessionCount = sManager->mSessionCount;
503 }
504
505 private:
506 nsWSAdmissionManager() : mSessionCount(0) {
507 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)
;
508 }
509
510 ~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)
; }
511
512 class nsOpenConn {
513 public:
514 nsOpenConn(nsCString& addr, nsCString& originSuffix, bool failed,
515 WebSocketChannel* channel)
516 : mAddress(addr),
517 mOriginSuffix(originSuffix),
518 mFailed(failed),
519 mChannel(channel) {
520 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)
;
521 }
522 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); }
523
524 nsCString mAddress;
525 nsCString mOriginSuffix;
526 bool mFailed = false;
527 RefPtr<WebSocketChannel> mChannel;
528 };
529
530 void ConnectNext(nsCString& hostName, nsCString& originSuffix) {
531 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"
, 531); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
") (" "not main thread" ")"); do { MOZ_CrashSequence(__null,
531); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false)
;
532
533 int32_t index = IndexOf(hostName, originSuffix);
534 if (index >= 0) {
535 WebSocketChannel* chan = mQueue[index]->mChannel;
536
537 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"
, 538); AnnotateMozCrashReason("MOZ_ASSERT" "(" "chan->mConnecting == CONNECTING_QUEUED"
") (" "transaction not queued but in queue" ")"); do { MOZ_CrashSequence
(__null, 538); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
538 "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"
, 538); AnnotateMozCrashReason("MOZ_ASSERT" "(" "chan->mConnecting == CONNECTING_QUEUED"
") (" "transaction not queued but in queue" ")"); do { MOZ_CrashSequence
(__null, 538); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
539 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)
;
540
541 mFailures.DelayOrBegin(chan);
542 }
543 }
544
545 void RemoveFromQueue(WebSocketChannel* aChannel) {
546 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)
;
547 int32_t index = IndexOf(aChannel);
548 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"
, 548); AnnotateMozCrashReason("MOZ_ASSERT" "(" "index >= 0"
") (" "connection to remove not in queue" ")"); do { MOZ_CrashSequence
(__null, 548); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
549 if (index >= 0) {
550 mQueue.RemoveElementAt(index);
551 }
552 }
553
554 int32_t IndexOf(nsCString& aAddress, nsCString& aOriginSuffix) {
555 for (uint32_t i = 0; i < mQueue.Length(); i++) {
556 if (aAddress == mQueue[i]->mAddress &&
557 aOriginSuffix == mQueue[i]->mOriginSuffix) {
558 return i;
559 }
560 }
561 return -1;
562 }
563
564 int32_t IndexOf(WebSocketChannel* aChannel) {
565 for (uint32_t i = 0; i < mQueue.Length(); i++) {
566 if (aChannel == mQueue[i]->mChannel) {
567 return i;
568 }
569 }
570 return -1;
571 }
572
573 // Returns the index of the first entry that failed, or else the last entry if
574 // none found
575 uint32_t IndexOfFirstFailure() {
576 for (uint32_t i = 0; i < mQueue.Length(); i++) {
577 if (mQueue[i]->mFailed) return i;
578 }
579 return mQueue.Length();
580 }
581
582 // SessionCount might be decremented from the main or the socket
583 // thread, so manage it with atomic counters
584 Atomic<int32_t> mSessionCount;
585
586 // Queue for websockets that have not completed connecting yet.
587 // The first nsOpenConn with a given address will be either be
588 // CONNECTING_IN_PROGRESS or CONNECTING_DELAYED. Later ones with the same
589 // hostname must be CONNECTING_QUEUED.
590 //
591 // We could hash hostnames instead of using a single big vector here, but the
592 // dataset is expected to be small.
593 nsTArray<UniquePtr<nsOpenConn>> mQueue;
594
595 FailDelayManager mFailures;
596
597 static nsWSAdmissionManager* sManager MOZ_GUARDED_BY(sLock)__attribute__((guarded_by(sLock)));
598 static StaticMutex sLock;
599};
600
601nsWSAdmissionManager* nsWSAdmissionManager::sManager;
602StaticMutex nsWSAdmissionManager::sLock;
603
604//-----------------------------------------------------------------------------
605// CallOnMessageAvailable
606//-----------------------------------------------------------------------------
607
608class CallOnMessageAvailable final : public Runnable {
609 public:
610 CallOnMessageAvailable(
611 WebSocketChannel* aChannel,
612 RefPtr<BaseWebSocketChannel::ListenerAndContextContainer>&& aListenerMT,
613 nsACString& aData, int32_t aLen)
614 : Runnable("net::CallOnMessageAvailable"),
615 mChannel(aChannel),
616 mListenerMT(std::move(aListenerMT)),
617 mData(aData),
618 mLen(aLen) {}
619
620 NS_IMETHODvirtual nsresult Run() override {
621 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"
, 621); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mChannel->IsOnTargetThread()"
")"); do { MOZ_CrashSequence(__null, 621); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
622
623 if (mListenerMT) {
624 nsresult rv;
625 if (mLen < 0) {
626 rv = mListenerMT->mListener->OnMessageAvailable(mListenerMT->mContext,
627 mData);
628 } else {
629 rv = mListenerMT->mListener->OnBinaryMessageAvailable(
630 mListenerMT->mContext, mData);
631 }
632 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
633 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)
634 ("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)
635 "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)
636 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)
;
637 }
638 }
639
640 return NS_OK;
641 }
642
643 private:
644 ~CallOnMessageAvailable() = default;
645
646 RefPtr<WebSocketChannel> mChannel;
647 RefPtr<BaseWebSocketChannel::ListenerAndContextContainer> mListenerMT;
648 nsCString mData;
649 int32_t mLen;
650};
651
652//-----------------------------------------------------------------------------
653// CallOnStop
654//-----------------------------------------------------------------------------
655
656class CallOnStop final : public Runnable {
657 public:
658 CallOnStop(
659 WebSocketChannel* aChannel,
660 RefPtr<BaseWebSocketChannel::ListenerAndContextContainer>&& aListenerMT,
661 nsresult aReason)
662 : Runnable("net::CallOnStop"),
663 mChannel(aChannel),
664 mListenerMT(std::move(aListenerMT)),
665 mReason(aReason) {}
666
667 NS_IMETHODvirtual nsresult Run() override {
668 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"
, 668); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mChannel->IsOnTargetThread()"
")"); do { MOZ_CrashSequence(__null, 668); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
669
670 if (mListenerMT) {
671 nsresult rv =
672 mListenerMT->mListener->OnStop(mListenerMT->mContext, mReason);
673 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
674 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)
675 ("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)
676 "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)
677 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)
;
678 }
679 }
680
681 return NS_OK;
682 }
683
684 private:
685 ~CallOnStop() = default;
686
687 RefPtr<WebSocketChannel> mChannel;
688 RefPtr<BaseWebSocketChannel::ListenerAndContextContainer> mListenerMT;
689 nsresult mReason;
690};
691
692//-----------------------------------------------------------------------------
693// CallOnServerClose
694//-----------------------------------------------------------------------------
695
696class CallOnServerClose final : public Runnable {
697 public:
698 CallOnServerClose(
699 WebSocketChannel* aChannel,
700 RefPtr<BaseWebSocketChannel::ListenerAndContextContainer>&& aListenerMT,
701 uint16_t aCode, nsACString& aReason)
702 : Runnable("net::CallOnServerClose"),
703 mChannel(aChannel),
704 mListenerMT(std::move(aListenerMT)),
705 mCode(aCode),
706 mReason(aReason) {}
707
708 NS_IMETHODvirtual nsresult Run() override {
709 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"
, 709); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mChannel->IsOnTargetThread()"
")"); do { MOZ_CrashSequence(__null, 709); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
710
711 if (mListenerMT) {
712 nsresult rv = mListenerMT->mListener->OnServerClose(mListenerMT->mContext,
713 mCode, mReason);
714 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
715 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)
716 ("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)
717 "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)
718 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)
;
719 }
720 }
721 return NS_OK;
722 }
723
724 private:
725 ~CallOnServerClose() = default;
726
727 RefPtr<WebSocketChannel> mChannel;
728 RefPtr<BaseWebSocketChannel::ListenerAndContextContainer> mListenerMT;
729 uint16_t mCode;
730 nsCString mReason;
731};
732
733//-----------------------------------------------------------------------------
734// CallAcknowledge
735//-----------------------------------------------------------------------------
736
737class CallAcknowledge final : public Runnable {
738 public:
739 CallAcknowledge(
740 WebSocketChannel* aChannel,
741 RefPtr<BaseWebSocketChannel::ListenerAndContextContainer>&& aListenerMT,
742 uint32_t aSize)
743 : Runnable("net::CallAcknowledge"),
744 mChannel(aChannel),
745 mListenerMT(std::move(aListenerMT)),
746 mSize(aSize) {}
747
748 NS_IMETHODvirtual nsresult Run() override {
749 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"
, 749); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mChannel->IsOnTargetThread()"
")"); do { MOZ_CrashSequence(__null, 749); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
750
751 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)
;
752 if (mListenerMT) {
753 nsresult rv =
754 mListenerMT->mListener->OnAcknowledge(mListenerMT->mContext, mSize);
755 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
756 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)
757 ")\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)
758 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)
;
759 }
760 }
761 return NS_OK;
762 }
763
764 private:
765 ~CallAcknowledge() = default;
766
767 RefPtr<WebSocketChannel> mChannel;
768 RefPtr<BaseWebSocketChannel::ListenerAndContextContainer> mListenerMT;
769 uint32_t mSize;
770};
771
772//-----------------------------------------------------------------------------
773// CallOnTransportAvailable
774//-----------------------------------------------------------------------------
775
776class CallOnTransportAvailable final : public Runnable {
777 public:
778 CallOnTransportAvailable(WebSocketChannel* aChannel,
779 nsISocketTransport* aTransport,
780 nsIAsyncInputStream* aSocketIn,
781 nsIAsyncOutputStream* aSocketOut)
782 : Runnable("net::CallOnTransportAvailble"),
783 mChannel(aChannel),
784 mTransport(aTransport),
785 mSocketIn(aSocketIn),
786 mSocketOut(aSocketOut) {}
787
788 NS_IMETHODvirtual nsresult Run() override {
789 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)
;
790 return mChannel->OnTransportAvailable(mTransport, mSocketIn, mSocketOut);
791 }
792
793 private:
794 ~CallOnTransportAvailable() = default;
795
796 RefPtr<WebSocketChannel> mChannel;
797 nsCOMPtr<nsISocketTransport> mTransport;
798 nsCOMPtr<nsIAsyncInputStream> mSocketIn;
799 nsCOMPtr<nsIAsyncOutputStream> mSocketOut;
800};
801
802//-----------------------------------------------------------------------------
803// PMCECompression
804//-----------------------------------------------------------------------------
805
806class PMCECompression {
807 public:
808 PMCECompression(bool aNoContextTakeover, int32_t aLocalMaxWindowBits,
809 int32_t aRemoteMaxWindowBits)
810 : mActive(false),
811 mNoContextTakeover(aNoContextTakeover),
812 mResetDeflater(false),
813 mMessageDeflated(false) {
814 this->mDeflater.next_in = nullptr;
815 this->mDeflater.avail_in = 0;
816 this->mDeflater.total_in = 0;
817 this->mDeflater.next_out = nullptr;
818 this->mDeflater.avail_out = 0;
819 this->mDeflater.total_out = 0;
820 this->mDeflater.msg = nullptr;
821 this->mDeflater.state = nullptr;
822 this->mDeflater.data_type = 0;
823 this->mDeflater.adler = 0;
824 this->mDeflater.reserved = 0;
825 this->mInflater.next_in = nullptr;
826 this->mInflater.avail_in = 0;
827 this->mInflater.total_in = 0;
828 this->mInflater.next_out = nullptr;
829 this->mInflater.avail_out = 0;
830 this->mInflater.total_out = 0;
831 this->mInflater.msg = nullptr;
832 this->mInflater.state = nullptr;
833 this->mInflater.data_type = 0;
834 this->mInflater.adler = 0;
835 this->mInflater.reserved = 0;
836 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)
;
837
838 mDeflater.zalloc = mInflater.zalloc = Z_NULL0;
839 mDeflater.zfree = mInflater.zfree = Z_NULL0;
840 mDeflater.opaque = mInflater.opaque = Z_NULL0;
841
842 if (deflateInit2(&mDeflater, Z_DEFAULT_COMPRESSION, Z_DEFLATED,MOZ_Z_deflateInit2_((&mDeflater),((-1)),(8),(-aLocalMaxWindowBits
),(8), (0), "1.4", (int)sizeof(z_stream))
843 -aLocalMaxWindowBits, 8, Z_DEFAULT_STRATEGY)MOZ_Z_deflateInit2_((&mDeflater),((-1)),(8),(-aLocalMaxWindowBits
),(8), (0), "1.4", (int)sizeof(z_stream))
== Z_OK0) {
844 if (inflateInit2(&mInflater, -aRemoteMaxWindowBits)MOZ_Z_inflateInit2_((&mInflater), (-aRemoteMaxWindowBits)
, "1.4", (int)sizeof(z_stream))
== Z_OK0) {
845 mActive = true;
846 } else {
847 deflateEndMOZ_Z_deflateEnd(&mDeflater);
848 }
849 }
850 }
851
852 ~PMCECompression() {
853 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)
;
854
855 if (mActive) {
856 inflateEndMOZ_Z_inflateEnd(&mInflater);
857 deflateEndMOZ_Z_deflateEnd(&mDeflater);
858 }
859 }
860
861 bool Active() { return mActive; }
862
863 void SetMessageDeflated() {
864 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"
, 864); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mMessageDeflated"
")"); do { MOZ_CrashSequence(__null, 864); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
865 mMessageDeflated = true;
866 }
867 bool IsMessageDeflated() { return mMessageDeflated; }
868
869 bool UsingContextTakeover() { return !mNoContextTakeover; }
870
871 nsresult Deflate(uint8_t* data, uint32_t dataLen, nsACString& _retval) {
872 if (mResetDeflater || mNoContextTakeover) {
873 if (deflateResetMOZ_Z_deflateReset(&mDeflater) != Z_OK0) {
874 return NS_ERROR_UNEXPECTED;
875 }
876 mResetDeflater = false;
877 }
878
879 mDeflater.avail_out = kBufferLen;
880 mDeflater.next_out = mBuffer;
881 mDeflater.avail_in = dataLen;
882 mDeflater.next_in = data;
883
884 while (true) {
885 int zerr = deflateMOZ_Z_deflate(&mDeflater, Z_SYNC_FLUSH2);
886
887 if (zerr != Z_OK0) {
888 mResetDeflater = true;
889 return NS_ERROR_UNEXPECTED;
890 }
891
892 uint32_t deflated = kBufferLen - mDeflater.avail_out;
893 if (deflated > 0) {
894 _retval.Append(reinterpret_cast<char*>(mBuffer), deflated);
895 }
896
897 mDeflater.avail_out = kBufferLen;
898 mDeflater.next_out = mBuffer;
899
900 if (mDeflater.avail_in > 0) {
901 continue; // There is still some data to deflate
902 }
903
904 if (deflated == kBufferLen) {
905 continue; // There was not enough space in the buffer
906 }
907
908 break;
909 }
910
911 if (_retval.Length() < 4) {
912 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"
, 912); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"Expected trailing not found in deflated data!" ")"); do { MOZ_CrashSequence
(__null, 912); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
913 mResetDeflater = true;
914 return NS_ERROR_UNEXPECTED;
915 }
916
917 _retval.Truncate(_retval.Length() - 4);
918
919 return NS_OK;
920 }
921
922 nsresult Inflate(uint8_t* data, uint32_t dataLen, nsACString& _retval) {
923 mMessageDeflated = false;
924
925 Bytef trailingData[] = {0x00, 0x00, 0xFF, 0xFF};
926 bool trailingDataUsed = false;
927
928 mInflater.avail_out = kBufferLen;
929 mInflater.next_out = mBuffer;
930 mInflater.avail_in = dataLen;
931 mInflater.next_in = data;
932
933 while (true) {
934 int zerr = inflateMOZ_Z_inflate(&mInflater, Z_NO_FLUSH0);
935
936 if (zerr == Z_STREAM_END1) {
937 Bytef* saveNextIn = mInflater.next_in;
938 uint32_t saveAvailIn = mInflater.avail_in;
939 Bytef* saveNextOut = mInflater.next_out;
940 uint32_t saveAvailOut = mInflater.avail_out;
941
942 inflateResetMOZ_Z_inflateReset(&mInflater);
943
944 mInflater.next_in = saveNextIn;
945 mInflater.avail_in = saveAvailIn;
946 mInflater.next_out = saveNextOut;
947 mInflater.avail_out = saveAvailOut;
948 } else if (zerr != Z_OK0 && zerr != Z_BUF_ERROR(-5)) {
949 return NS_ERROR_INVALID_CONTENT_ENCODING;
950 }
951
952 uint32_t inflated = kBufferLen - mInflater.avail_out;
953 if (inflated > 0) {
954 if (!_retval.Append(reinterpret_cast<char*>(mBuffer), inflated,
955 fallible)) {
956 return NS_ERROR_OUT_OF_MEMORY;
957 }
958 }
959
960 mInflater.avail_out = kBufferLen;
961 mInflater.next_out = mBuffer;
962
963 if (mInflater.avail_in > 0) {
964 continue; // There is still some data to inflate
965 }
966
967 if (inflated == kBufferLen) {
968 continue; // There was not enough space in the buffer
969 }
970
971 if (!trailingDataUsed) {
972 trailingDataUsed = true;
973 mInflater.avail_in = sizeof(trailingData);
974 mInflater.next_in = trailingData;
975 continue;
976 }
977
978 return NS_OK;
979 }
980 }
981
982 private:
983 bool mActive;
984 bool mNoContextTakeover;
985 bool mResetDeflater;
986 bool mMessageDeflated;
987 z_stream mDeflater{};
988 z_stream mInflater{};
989 const static uint32_t kBufferLen = 4096;
990 uint8_t mBuffer[kBufferLen]{0};
991};
992
993//-----------------------------------------------------------------------------
994// OutboundMessage
995//-----------------------------------------------------------------------------
996
997enum WsMsgType {
998 kMsgTypeString = 0,
999 kMsgTypeBinaryString,
1000 kMsgTypeStream,
1001 kMsgTypePing,
1002 kMsgTypePong,
1003 kMsgTypeFin
1004};
1005
1006static const char* msgNames[] = {"text", "binaryString", "binaryStream",
1007 "ping", "pong", "close"};
1008
1009class OutboundMessage {
1010 public:
1011 OutboundMessage(WsMsgType type, const nsACString& str)
1012 : mMsg(mozilla::AsVariant(pString(str))),
1013 mMsgType(type),
1014 mDeflated(false) {
1015 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)
;
1016 }
1017
1018 OutboundMessage(nsIInputStream* stream, uint32_t length)
1019 : mMsg(mozilla::AsVariant(StreamWithLength(stream, length))),
1020 mMsgType(kMsgTypeStream),
1021 mDeflated(false) {
1022 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)
;
1023 }
1024
1025 ~OutboundMessage() {
1026 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)
;
1027 switch (mMsgType) {
1028 case kMsgTypeString:
1029 case kMsgTypeBinaryString:
1030 case kMsgTypePing:
1031 case kMsgTypePong:
1032 break;
1033 case kMsgTypeStream:
1034 // for now this only gets hit if msg deleted w/o being sent
1035 if (mMsg.as<StreamWithLength>().mStream) {
1036 mMsg.as<StreamWithLength>().mStream->Close();
1037 }
1038 break;
1039 case kMsgTypeFin:
1040 break; // do-nothing: avoid compiler warning
1041 }
1042 }
1043
1044 WsMsgType GetMsgType() const { return mMsgType; }
1045 int32_t Length() {
1046 if (mMsg.is<pString>()) {
1047 return mMsg.as<pString>().mValue.Length();
1048 }
1049
1050 return mMsg.as<StreamWithLength>().mLength;
1051 }
1052 int32_t OrigLength() {
1053 if (mMsg.is<pString>()) {
1054 pString& ref = mMsg.as<pString>();
1055 return mDeflated ? ref.mOrigValue.Length() : ref.mValue.Length();
1056 }
1057
1058 return mMsg.as<StreamWithLength>().mLength;
1059 }
1060
1061 uint8_t* BeginWriting() {
1062 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"
, 1063); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mMsgType != kMsgTypeStream"
") (" "Stream should have been converted to string by now" ")"
); do { MOZ_CrashSequence(__null, 1063); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1063 "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"
, 1063); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mMsgType != kMsgTypeStream"
") (" "Stream should have been converted to string by now" ")"
); do { MOZ_CrashSequence(__null, 1063); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1064 if (!mMsg.as<pString>().mValue.IsVoid()) {
1065 return (uint8_t*)mMsg.as<pString>().mValue.BeginWriting();
1066 }
1067 return nullptr;
1068 }
1069
1070 uint8_t* BeginReading() {
1071 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"
, 1072); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mMsgType != kMsgTypeStream"
") (" "Stream should have been converted to string by now" ")"
); do { MOZ_CrashSequence(__null, 1072); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1072 "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"
, 1072); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mMsgType != kMsgTypeStream"
") (" "Stream should have been converted to string by now" ")"
); do { MOZ_CrashSequence(__null, 1072); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1073 if (!mMsg.as<pString>().mValue.IsVoid()) {
1074 return (uint8_t*)mMsg.as<pString>().mValue.BeginReading();
1075 }
1076 return nullptr;
1077 }
1078
1079 uint8_t* BeginOrigReading() {
1080 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"
, 1081); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mMsgType != kMsgTypeStream"
") (" "Stream should have been converted to string by now" ")"
); do { MOZ_CrashSequence(__null, 1081); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1081 "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"
, 1081); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mMsgType != kMsgTypeStream"
") (" "Stream should have been converted to string by now" ")"
); do { MOZ_CrashSequence(__null, 1081); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1082 if (!mDeflated) return BeginReading();
1083 if (!mMsg.as<pString>().mOrigValue.IsVoid()) {
1084 return (uint8_t*)mMsg.as<pString>().mOrigValue.BeginReading();
1085 }
1086 return nullptr;
1087 }
1088
1089 nsresult ConvertStreamToString() {
1090 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"
, 1090); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mMsgType == kMsgTypeStream"
") (" "Not a stream!" ")"); do { MOZ_CrashSequence(__null, 1090
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
;
1091 nsAutoCString temp;
1092 {
1093 StreamWithLength& ref = mMsg.as<StreamWithLength>();
1094 nsresult rv = NS_ReadInputStreamToString(ref.mStream, temp, ref.mLength);
1095
1096 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"
, 1096); return rv; } } while (false)
;
1097 if (temp.Length() != ref.mLength) {
1098 return NS_ERROR_UNEXPECTED;
1099 }
1100 ref.mStream->Close();
1101 }
1102
1103 mMsg = mozilla::AsVariant(pString(temp));
1104 mMsgType = kMsgTypeBinaryString;
1105
1106 return NS_OK;
1107 }
1108
1109 bool DeflatePayload(PMCECompression* aCompressor) {
1110 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"
, 1111); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mMsgType != kMsgTypeStream"
") (" "Stream should have been converted to string by now" ")"
); do { MOZ_CrashSequence(__null, 1111); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1111 "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"
, 1111); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mMsgType != kMsgTypeStream"
") (" "Stream should have been converted to string by now" ")"
); do { MOZ_CrashSequence(__null, 1111); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1112 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"
, 1112); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mDeflated"
")"); do { MOZ_CrashSequence(__null, 1112); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1113
1114 nsresult rv;
1115 pString& ref = mMsg.as<pString>();
1116 if (ref.mValue.Length() == 0) {
1117 // Empty message
1118 return false;
1119 }
1120
1121 nsAutoCString temp;
1122 rv = aCompressor->Deflate(BeginReading(), ref.mValue.Length(), temp);
1123 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
1124 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)
1125 ("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)
1126 "[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)
1127 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)
;
1128 return false;
1129 }
1130
1131 if (!aCompressor->UsingContextTakeover() &&
1132 temp.Length() > ref.mValue.Length()) {
1133 // When "<local>_no_context_takeover" was negotiated, do not send deflated
1134 // payload if it's larger that the original one. OTOH, it makes sense
1135 // to send the larger deflated payload when the sliding window is not
1136 // reset between messages because if we would skip some deflated block
1137 // we would need to empty the sliding window which could affect the
1138 // compression of the subsequent messages.
1139 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)
1140 ("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)
1141 "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)
1142 "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)
1143 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)
;
1144 return false;
1145 }
1146
1147 mDeflated = true;
1148 mMsg.as<pString>().mOrigValue = std::move(mMsg.as<pString>().mValue);
1149 mMsg.as<pString>().mValue = std::move(temp);
1150 return true;
1151 }
1152
1153 private:
1154 struct pString {
1155 nsCString mValue;
1156 nsCString mOrigValue;
1157 explicit pString(const nsACString& value)
1158 : mValue(value), mOrigValue(VoidCString()) {}
1159 };
1160 struct StreamWithLength {
1161 nsCOMPtr<nsIInputStream> mStream;
1162 uint32_t mLength;
1163 explicit StreamWithLength(nsIInputStream* stream, uint32_t Length)
1164 : mStream(stream), mLength(Length) {}
1165 };
1166 mozilla::Variant<pString, StreamWithLength> mMsg;
1167 WsMsgType mMsgType;
1168 bool mDeflated;
1169};
1170
1171//-----------------------------------------------------------------------------
1172// OutboundEnqueuer
1173//-----------------------------------------------------------------------------
1174
1175class OutboundEnqueuer final : public Runnable {
1176 public:
1177 OutboundEnqueuer(WebSocketChannel* aChannel, OutboundMessage* aMsg)
1178 : Runnable("OutboundEnquerer"), mChannel(aChannel), mMessage(aMsg) {}
1179
1180 NS_IMETHODvirtual nsresult Run() override {
1181 mChannel->EnqueueOutgoingMessage(mChannel->mOutgoingMessages, mMessage);
1182 return NS_OK;
1183 }
1184
1185 private:
1186 ~OutboundEnqueuer() = default;
1187
1188 RefPtr<WebSocketChannel> mChannel;
1189 OutboundMessage* mMessage;
1190};
1191
1192//-----------------------------------------------------------------------------
1193// WebSocketChannel
1194//-----------------------------------------------------------------------------
1195
1196WebSocketChannel::WebSocketChannel()
1197 : mPort(0),
1198 mCloseTimeout(20000),
1199 mOpenTimeout(20000),
1200 mConnecting(NOT_CONNECTING),
1201 mMaxConcurrentConnections(200),
1202 mInnerWindowID(0),
1203 mGotUpgradeOK(0),
1204 mRecvdHttpUpgradeTransport(0),
1205 mPingOutstanding(0),
1206 mReleaseOnTransmit(0),
1207 mDataStarted(false),
1208 mRequestedClose(false),
1209 mClientClosed(false),
1210 mServerClosed(false),
1211 mStopped(false),
1212 mCalledOnStop(false),
1213 mTCPClosed(false),
1214 mOpenedHttpChannel(false),
1215 mIncrementedSessionCount(false),
1216 mDecrementedSessionCount(false),
1217 mMaxMessageSize(INT32_MAX(2147483647)),
1218 mStopOnClose(NS_OK),
1219 mServerCloseCode(CLOSE_ABNORMAL),
1220 mScriptCloseCode(0),
1221 mFragmentOpcode(nsIWebSocketFrame::OPCODE_CONTINUATION),
1222 mFragmentAccumulator(0),
1223 mBuffered(0),
1224 mBufferSize(kIncomingBufferInitialSize),
1225 mCurrentOut(nullptr),
1226 mCurrentOutSent(0),
1227 mHdrOutToSend(0),
1228 mHdrOut(nullptr),
1229 mCompressorMutex("WebSocketChannel::mCompressorMutex"),
1230 mDynamicOutputSize(0),
1231 mDynamicOutput(nullptr),
1232 mPrivateBrowsing(false),
1233 mConnectionLogService(nullptr),
1234 mMutex("WebSocketChannel::mMutex") {
1235 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"
, 1235); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
") (" "not main thread" ")"); do { MOZ_CrashSequence(__null,
1235); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false)
;
1236
1237 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)
;
1238
1239 nsWSAdmissionManager::Init();
1240
1241 mFramePtr = mBuffer = static_cast<uint8_t*>(moz_xmalloc(mBufferSize));
1242
1243 nsresult rv;
1244 mConnectionLogService = mozilla::components::Dashboard::Service(&rv);
1245 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)
;
1246
1247 mService = WebSocketEventService::GetOrCreate();
1248}
1249
1250WebSocketChannel::~WebSocketChannel() {
1251 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)
;
1252
1253 if (mWasOpened) {
1254 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"
, 1254); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mCalledOnStop"
") (" "WebSocket was opened but OnStop was not called" ")");
do { MOZ_CrashSequence(__null, 1254); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1255 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"
, 1255); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mStopped" ") ("
"WebSocket was opened but never stopped" ")"); do { MOZ_CrashSequence
(__null, 1255); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
1256 }
1257 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"
, 1257); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mCancelable"
") (" "DNS/Proxy Request still alive at destruction" ")"); do
{ MOZ_CrashSequence(__null, 1257); __attribute__((nomerge)) ::
abort(); } while (false); } } while (false)
;
1258 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"
, 1258); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mConnecting"
") (" "Should not be connecting in destructor" ")"); do { MOZ_CrashSequence
(__null, 1258); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
1259
1260 free(mBuffer);
1261 free(mDynamicOutput);
1262 delete mCurrentOut;
1263
1264 while ((mCurrentOut = mOutgoingPingMessages.PopFront())) {
1265 delete mCurrentOut;
1266 }
1267 while ((mCurrentOut = mOutgoingPongMessages.PopFront())) {
1268 delete mCurrentOut;
1269 }
1270 while ((mCurrentOut = mOutgoingMessages.PopFront())) {
1271 delete mCurrentOut;
1272 }
1273
1274 mListenerMT = nullptr;
1275
1276 NS_ReleaseOnMainThread("WebSocketChannel::mService", mService.forget());
1277}
1278
1279NS_IMETHODIMPnsresult
1280WebSocketChannel::Observe(nsISupports* subject, const char* topic,
1281 const char16_t* data) {
1282 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)
;
1283
1284 if (strcmp(topic, NS_NETWORK_LINK_TOPIC"network:link-status-changed") == 0) {
1285 nsCString converted = NS_ConvertUTF16toUTF8(data);
1286 const char* state = converted.get();
1287
1288 if (strcmp(state, NS_NETWORK_LINK_DATA_CHANGED"changed") == 0) {
1289 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)
;
1290
1291 if (!mIOThread) {
1292 // there has not been an asyncopen yet on the object and then we need
1293 // no ping.
1294 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)
;
1295 } else {
1296 mIOThread->Dispatch(
1297 NewRunnableMethod("net::WebSocketChannel::OnNetworkChanged", this,
1298 &WebSocketChannel::OnNetworkChanged),
1299 NS_DISPATCH_NORMALnsIEventTarget::DISPATCH_NORMAL);
1300 }
1301 }
1302 }
1303
1304 return NS_OK;
1305}
1306
1307nsresult WebSocketChannel::OnNetworkChanged() {
1308 if (!mDataStarted) {
1309 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)
;
1310 return NS_OK;
1311 }
1312
1313 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"
, 1313); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mIOThread->IsOnCurrentThread()"
") (" "not on right thread" ")"); do { MOZ_CrashSequence(__null
, 1313); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
1314
1315 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)
;
1316
1317 if (mPingOutstanding) {
1318 // If there's an outstanding ping that's expected to get a pong back
1319 // we let that do its thing.
1320 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)
;
1321 return NS_OK;
1322 }
1323
1324 if (mPingForced) {
1325 // avoid more than one
1326 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)
;
1327 return NS_OK;
1328 }
1329
1330 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)
;
1331
1332 if (!mPingTimer) {
1333 // The ping timer is only conditionally running already. If it wasn't
1334 // already created do it here.
1335 mPingTimer = NS_NewTimer();
1336 if (!mPingTimer) {
1337 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)
;
1338 NS_WARNING("unable to create ping timer!")NS_DebugBreak(NS_DEBUG_WARNING, "unable to create ping timer!"
, nullptr, "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 1338)
;
1339 return NS_ERROR_OUT_OF_MEMORY;
1340 }
1341 }
1342 // Trigger the ping timeout asap to fire off a new ping. Wait just
1343 // a little bit to better avoid multi-triggers.
1344 mPingForced = true;
1345 mPingTimer->InitWithCallback(this, 200, nsITimer::TYPE_ONE_SHOT);
1346
1347 return NS_OK;
1348}
1349
1350void WebSocketChannel::Shutdown() { nsWSAdmissionManager::Shutdown(); }
1351
1352void WebSocketChannel::GetEffectiveURL(nsAString& aEffectiveURL) const {
1353 aEffectiveURL = mEffectiveURL;
1354}
1355
1356bool WebSocketChannel::IsEncrypted() const { return mEncrypted; }
1357
1358void WebSocketChannel::BeginOpen(bool aCalledFromAdmissionManager) {
1359 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"
, 1359); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
") (" "not main thread" ")"); do { MOZ_CrashSequence(__null,
1359); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false)
;
1360
1361 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)
;
1362
1363 // Important that we set CONNECTING_IN_PROGRESS before any call to
1364 // AbortSession here: ensures that any remaining queued connection(s) are
1365 // scheduled in OnStopSession
1366 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)
;
1367 mConnecting = CONNECTING_IN_PROGRESS;
1368
1369 if (aCalledFromAdmissionManager) {
1370 // When called from nsWSAdmissionManager post an event to avoid potential
1371 // re-entering of nsWSAdmissionManager and its lock.
1372 NS_DispatchToMainThread(
1373 NewRunnableMethod("net::WebSocketChannel::BeginOpenInternal", this,
1374 &WebSocketChannel::BeginOpenInternal),
1375 NS_DISPATCH_NORMALnsIEventTarget::DISPATCH_NORMAL);
1376 } else {
1377 BeginOpenInternal();
1378 }
1379}
1380
1381// MainThread
1382void WebSocketChannel::BeginOpenInternal() {
1383 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)
;
1384 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"
, 1384); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
") (" "not main thread" ")"); do { MOZ_CrashSequence(__null,
1384); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false)
;
1385
1386 nsresult rv;
1387
1388 if (mRedirectCallback) {
1389 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)
;
1390 rv = mRedirectCallback->OnRedirectVerifyCallback(NS_OK);
1391 mRedirectCallback = nullptr;
1392 return;
1393 }
1394
1395 nsCOMPtr<nsIChannel> localChannel = do_QueryInterface(mChannel, &rv);
1396 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
1397 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)
;
1398 AbortSession(NS_ERROR_UNEXPECTED);
1399 return;
1400 }
1401
1402 rv = localChannel->AsyncOpen(this);
1403
1404 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
1405 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)
;
1406 AbortSession(NS_ERROR_WEBSOCKET_CONNECTION_REFUSED);
1407 return;
1408 }
1409 mOpenedHttpChannel = true;
1410
1411 rv = NS_NewTimerWithCallback(getter_AddRefs(mOpenTimer), this, mOpenTimeout,
1412 nsITimer::TYPE_ONE_SHOT);
1413 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
1414 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)
1415 ("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)
1416 "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)
;
1417 AbortSession(NS_ERROR_UNEXPECTED);
1418 return;
1419 }
1420}
1421
1422bool WebSocketChannel::IsPersistentFramePtr() {
1423 return (mFramePtr >= mBuffer && mFramePtr <= mBuffer + mBufferSize);
1424}
1425
1426// Extends the internal buffer by count and returns the total
1427// amount of data available for read
1428//
1429// Accumulated fragment size is passed in instead of using the member
1430// variable beacuse when transitioning from the stack to the persistent
1431// read buffer we want to explicitly include them in the buffer instead
1432// of as already existing data.
1433bool WebSocketChannel::UpdateReadBuffer(uint8_t* buffer, uint32_t count,
1434 uint32_t accumulatedFragments,
1435 uint32_t* available) {
1436 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)
1437 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)
;
1438
1439 if (!mBuffered) mFramePtr = mBuffer;
1440
1441 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"
, 1441); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsPersistentFramePtr()"
") (" "update read buffer bad mFramePtr" ")"); do { MOZ_CrashSequence
(__null, 1441); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
1442 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"
, 1443); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mFramePtr - accumulatedFragments >= mBuffer"
") (" "reserved FramePtr bad" ")"); do { MOZ_CrashSequence(__null
, 1443); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
1443 "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"
, 1443); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mFramePtr - accumulatedFragments >= mBuffer"
") (" "reserved FramePtr bad" ")"); do { MOZ_CrashSequence(__null
, 1443); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
1444
1445 if (mBuffered + count <= mBufferSize) {
1446 // append to existing buffer
1447 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)
;
1448 } else if (mBuffered + count - (mFramePtr - accumulatedFragments - mBuffer) <=
1449 mBufferSize) {
1450 // make room in existing buffer by shifting unused data to start
1451 mBuffered -= (mFramePtr - mBuffer - accumulatedFragments);
1452 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)
;
1453 ::memmove(mBuffer, mFramePtr - accumulatedFragments, mBuffered);
1454 mFramePtr = mBuffer + accumulatedFragments;
1455 } else {
1456 // existing buffer is not sufficient, extend it
1457 uint32_t newBufferSize = mBufferSize;
1458 newBufferSize += count + 8192 + mBufferSize / 3;
1459 ptrdiff_t frameIndex = mFramePtr - mBuffer;
1460 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)
1461 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)
;
1462 uint8_t* newBuffer = (uint8_t*)realloc(mBuffer, newBufferSize);
1463 if (!newBuffer) {
1464 // Reallocation failed.
1465 return false;
1466 }
1467 mBuffer = newBuffer;
1468 mBufferSize = newBufferSize;
1469
1470 // mBuffer was reallocated, so we need to update mFramePtr
1471 mFramePtr = mBuffer + frameIndex;
1472 }
1473
1474 ::memmove(mBuffer + mBuffered, buffer, count);
1475 mBuffered += count;
1476
1477 if (available) *available = mBuffered - (mFramePtr - mBuffer);
1478
1479 return true;
1480}
1481
1482already_AddRefed<BaseWebSocketChannel::ListenerAndContextContainer>
1483WebSocketChannel::GetListenerMT() {
1484 MutexAutoLock lock(mMutex);
1485 return do_AddRef(mStopped ? nullptr : mListenerMT.get());
1486}
1487
1488already_AddRefed<BaseWebSocketChannel::ListenerAndContextContainer>
1489WebSocketChannel::TakeListenerMT() {
1490 MutexAutoLock lock(mMutex);
1491 return mListenerMT.forget();
1492}
1493
1494nsresult WebSocketChannel::ProcessInput(uint8_t* buffer, uint32_t count) {
1495 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)
;
1496 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"
, 1496); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mIOThread->IsOnCurrentThread()"
") (" "not on right thread" ")"); do { MOZ_CrashSequence(__null
, 1496); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
1497
1498 nsresult rv;
1499
1500 // The purpose of ping/pong is to actively probe the peer so that an
1501 // unreachable peer is not mistaken for a period of idleness. This
1502 // implementation accepts any application level read activity as a sign of
1503 // life, it does not necessarily have to be a pong.
1504 ResetPingTimer();
1505
1506 uint32_t avail;
1507
1508 if (!mBuffered) {
1509 // Most of the time we can process right off the stack buffer without
1510 // having to accumulate anything
1511 mFramePtr = buffer;
1512 avail = count;
1513 } else {
1514 if (!UpdateReadBuffer(buffer, count, mFragmentAccumulator, &avail)) {
1515 return NS_ERROR_FILE_TOO_BIG;
1516 }
1517 }
1518
1519 uint8_t* payload;
1520 uint32_t totalAvail = avail;
1521
1522 while (avail >= 2) {
1523 int64_t payloadLength64 = mFramePtr[1] & kPayloadLengthBitsMask;
1524 uint8_t finBit = mFramePtr[0] & kFinalFragBit;
1525 uint8_t rsvBits = mFramePtr[0] & kRsvBitsMask;
1526 uint8_t rsvBit1 = mFramePtr[0] & kRsv1Bit;
1527 uint8_t rsvBit2 = mFramePtr[0] & kRsv2Bit;
1528 uint8_t rsvBit3 = mFramePtr[0] & kRsv3Bit;
1529 uint8_t opcode = mFramePtr[0] & kOpcodeBitsMask;
1530 uint8_t maskBit = mFramePtr[1] & kMaskBit;
1531 uint32_t mask = 0;
1532
1533 uint32_t framingLength = 2;
1534 if (maskBit) framingLength += 4;
1535
1536 if (payloadLength64 < 126) {
1537 if (avail < framingLength) break;
1538 } else if (payloadLength64 == 126) {
1539 // 16 bit length field
1540 framingLength += 2;
1541 if (avail < framingLength) break;
1542
1543 payloadLength64 = mFramePtr[2] << 8 | mFramePtr[3];
1544
1545 if (payloadLength64 < 126) {
1546 // Section 5.2 says that the minimal number of bytes MUST
1547 // be used to encode the length in all cases
1548 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)
;
1549 return NS_ERROR_ILLEGAL_VALUE;
1550 }
1551
1552 } else {
1553 // 64 bit length
1554 framingLength += 8;
1555 if (avail < framingLength) break;
1556
1557 if (mFramePtr[2] & 0x80) {
1558 // Section 4.2 says that the most significant bit MUST be
1559 // 0. (i.e. this is really a 63 bit value)
1560 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)
;
1561 return NS_ERROR_ILLEGAL_VALUE;
1562 }
1563
1564 // copy this in case it is unaligned
1565 payloadLength64 = NetworkEndian::readInt64(mFramePtr + 2);
1566
1567 if (payloadLength64 <= 0xffff) {
1568 // Section 5.2 says that the minimal number of bytes MUST
1569 // be used to encode the length in all cases
1570 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)
;
1571 return NS_ERROR_ILLEGAL_VALUE;
1572 }
1573 }
1574
1575 payload = mFramePtr + framingLength;
1576 avail -= framingLength;
1577
1578 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)
1579 "\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)
1580 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)
;
1581
1582 CheckedInt<int64_t> payloadLengthChecked(payloadLength64);
1583 payloadLengthChecked += mFragmentAccumulator;
1584 if (!payloadLengthChecked.isValid() ||
1585 payloadLengthChecked.value() > mMaxMessageSize) {
1586 return NS_ERROR_FILE_TOO_BIG;
1587 }
1588
1589 uint32_t payloadLength = static_cast<uint32_t>(payloadLength64);
1590
1591 if (avail < payloadLength) break;
1592
1593 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)
1594 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)
;
1595
1596 if (!maskBit && mIsServerSide) {
1597 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)
1598 ("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)
1599 "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)
;
1600 return NS_ERROR_ILLEGAL_VALUE;
1601 }
1602
1603 if (maskBit) {
1604 if (!mIsServerSide) {
1605 // The server should not be allowed to send masked frames to clients.
1606 // But we've been allowing it for some time, so this should be
1607 // deprecated with care.
1608 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)
;
1609 }
1610
1611 mask = NetworkEndian::readUint32(payload - 4);
1612 }
1613
1614 if (mask) {
1615 ApplyMask(mask, payload, payloadLength);
1616 } else if (mIsServerSide) {
1617 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)
1618 ("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)
1619 "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)
;
1620 return NS_ERROR_ILLEGAL_VALUE;
1621 }
1622
1623 // Control codes are required to have the fin bit set
1624 if (!finBit && (opcode & kControlFrameMask)) {
1625 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)
;
1626 return NS_ERROR_ILLEGAL_VALUE;
1627 }
1628
1629 if (rsvBits) {
1630 // PMCE sets RSV1 bit in the first fragment when the non-control frame
1631 // is deflated
1632 MutexAutoLock lock(mCompressorMutex);
1633 if (mPMCECompressor && rsvBits == kRsv1Bit && mFragmentAccumulator == 0 &&
1634 !(opcode & kControlFrameMask)) {
1635 mPMCECompressor->SetMessageDeflated();
1636 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)
;
1637 } else {
1638 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)
1639 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)
;
1640 return NS_ERROR_ILLEGAL_VALUE;
1641 }
1642 }
1643
1644 if (!finBit || opcode == nsIWebSocketFrame::OPCODE_CONTINUATION) {
1645 // This is part of a fragment response
1646
1647 // Only the first frame has a non zero op code: Make sure we don't see a
1648 // first frame while some old fragments are open
1649 if ((mFragmentAccumulator != 0) &&
1650 (opcode != nsIWebSocketFrame::OPCODE_CONTINUATION)) {
1651 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)
;
1652 return NS_ERROR_ILLEGAL_VALUE;
1653 }
1654
1655 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)
1656 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)
;
1657
1658 if (opcode == nsIWebSocketFrame::OPCODE_CONTINUATION) {
1659 // Make sure this continuation fragment isn't the first fragment
1660 if (mFragmentOpcode == nsIWebSocketFrame::OPCODE_CONTINUATION) {
1661 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)
;
1662 return NS_ERROR_ILLEGAL_VALUE;
1663 }
1664
1665 // For frag > 1 move the data body back on top of the headers
1666 // so we have contiguous stream of data
1667 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"
, 1668); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mFramePtr + framingLength == payload"
") (" "payload offset from frameptr wrong" ")"); do { MOZ_CrashSequence
(__null, 1668); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
1668 "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"
, 1668); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mFramePtr + framingLength == payload"
") (" "payload offset from frameptr wrong" ")"); do { MOZ_CrashSequence
(__null, 1668); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
1669 ::memmove(mFramePtr, payload, avail);
1670 payload = mFramePtr;
1671 if (mBuffered) mBuffered -= framingLength;
1672 } else {
1673 mFragmentOpcode = opcode;
1674 }
1675
1676 if (finBit) {
1677 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)
;
1678 payload -= mFragmentAccumulator;
1679 payloadLength += mFragmentAccumulator;
1680 avail += mFragmentAccumulator;
1681 mFragmentAccumulator = 0;
1682 opcode = mFragmentOpcode;
1683 // reset to detect if next message illegally starts with continuation
1684 mFragmentOpcode = nsIWebSocketFrame::OPCODE_CONTINUATION;
1685 } else {
1686 opcode = nsIWebSocketFrame::OPCODE_CONTINUATION;
1687 mFragmentAccumulator += payloadLength;
1688 }
1689 } else if (mFragmentAccumulator != 0 && !(opcode & kControlFrameMask)) {
1690 // This frame is not part of a fragment sequence but we
1691 // have an open fragment.. it must be a control code or else
1692 // we have a problem
1693 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)
;
1694 return NS_ERROR_ILLEGAL_VALUE;
1695 }
1696
1697 if (mServerClosed) {
1698 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)
1699 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)
;
1700 // nop
1701 } else if (mStopped) {
1702 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)
1703 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)
;
1704 } else if (opcode == nsIWebSocketFrame::OPCODE_TEXT) {
1705 if (RefPtr<BaseWebSocketChannel::ListenerAndContextContainer> listener =
1706 GetListenerMT()) {
1707 nsCString utf8Data;
1708 {
1709 MutexAutoLock lock(mCompressorMutex);
1710 bool isDeflated =
1711 mPMCECompressor && mPMCECompressor->IsMessageDeflated();
1712 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)
1713 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)
;
1714
1715 if (isDeflated) {
1716 rv = mPMCECompressor->Inflate(payload, payloadLength, utf8Data);
1717 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
1718 return rv;
1719 }
1720 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)
1721 ("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)
1722 "[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)
1723 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)
;
1724 } else {
1725 if (!utf8Data.Assign((const char*)payload, payloadLength,
1726 mozilla::fallible)) {
1727 return NS_ERROR_OUT_OF_MEMORY;
1728 }
1729 }
1730 }
1731
1732 // Section 8.1 says to fail connection if invalid utf-8 in text message
1733 if (!IsUtf8(utf8Data)) {
1734 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)
;
1735 return NS_ERROR_CANNOT_CONVERT_DATA;
1736 }
1737
1738 RefPtr<WebSocketFrame> frame = mService->CreateFrameIfNeeded(
1739 finBit, rsvBit1, rsvBit2, rsvBit3, opcode, maskBit, mask, utf8Data);
1740
1741 if (frame) {
1742 mService->FrameReceived(mSerial, mInnerWindowID, mHttpChannelId,
1743 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, mHttpChannelId,
1807 frame.forget());
1808 frame = nullptr;
1809 }
1810
1811 if (RefPtr<BaseWebSocketChannel::ListenerAndContextContainer> listener =
1812 GetListenerMT()) {
1813 if (nsCOMPtr<nsIEventTarget> target = GetTargetThread()) {
1814 target->Dispatch(
1815 new CallOnServerClose(this, std::move(listener),
1816 mServerCloseCode, mServerCloseReason),
1817 NS_DISPATCH_NORMALnsIEventTarget::DISPATCH_NORMAL);
1818 } else {
1819 return NS_ERROR_UNEXPECTED;
1820 }
1821 }
1822
1823 if (mClientClosed) ReleaseSession();
1824 } else if (opcode == nsIWebSocketFrame::OPCODE_PING) {
1825 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)
;
1826 GeneratePong(payload, payloadLength);
1827 } else if (opcode == nsIWebSocketFrame::OPCODE_PONG) {
1828 // opcode OPCODE_PONG: the mere act of receiving the packet is all we
1829 // need to do for the pong to trigger the activity timers
1830 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)
;
1831 } else {
1832 /* unknown control frame opcode */
1833 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)
;
1834 return NS_ERROR_ILLEGAL_VALUE;
1835 }
1836
1837 if (mFragmentAccumulator) {
1838 // Remove the control frame from the stream so we have a contiguous
1839 // data buffer of reassembled fragments
1840 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)
;
1841 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"
, 1842); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mFramePtr + framingLength == payload"
") (" "payload offset from frameptr wrong" ")"); do { MOZ_CrashSequence
(__null, 1842); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
1842 "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"
, 1842); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mFramePtr + framingLength == payload"
") (" "payload offset from frameptr wrong" ")"); do { MOZ_CrashSequence
(__null, 1842); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
1843 ::memmove(mFramePtr, payload + payloadLength, avail - payloadLength);
1844 payload = mFramePtr;
1845 avail -= payloadLength;
1846 if (mBuffered) mBuffered -= framingLength + payloadLength;
1847 payloadLength = 0;
1848 }
1849
1850 if (frame) {
1851 mService->FrameReceived(mSerial, mInnerWindowID, mHttpChannelId,
1852 frame.forget());
1853 }
1854 } else if (opcode == nsIWebSocketFrame::OPCODE_BINARY) {
1855 if (RefPtr<BaseWebSocketChannel::ListenerAndContextContainer> listener =
1856 GetListenerMT()) {
1857 nsCString binaryData;
1858 {
1859 MutexAutoLock lock(mCompressorMutex);
1860 bool isDeflated =
1861 mPMCECompressor && mPMCECompressor->IsMessageDeflated();
1862 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)
1863 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)
;
1864
1865 if (isDeflated) {
1866 rv = mPMCECompressor->Inflate(payload, payloadLength, binaryData);
1867 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
1868 return rv;
1869 }
1870 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)
1871 ("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)
1872 "[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)
1873 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)
;
1874 } else {
1875 if (!binaryData.Assign((const char*)payload, payloadLength,
1876 mozilla::fallible)) {
1877 return NS_ERROR_OUT_OF_MEMORY;
1878 }
1879 }
1880 }
1881
1882 RefPtr<WebSocketFrame> frame =
1883 mService->CreateFrameIfNeeded(finBit, rsvBit1, rsvBit2, rsvBit3,
1884 opcode, maskBit, mask, binaryData);
1885 if (frame) {
1886 mService->FrameReceived(mSerial, mInnerWindowID, mHttpChannelId,
1887 frame.forget());
1888 }
1889
1890 if (nsCOMPtr<nsIEventTarget> target = GetTargetThread()) {
1891 target->Dispatch(
1892 new CallOnMessageAvailable(this, std::move(listener), binaryData,
1893 binaryData.Length()),
1894 NS_DISPATCH_NORMALnsIEventTarget::DISPATCH_NORMAL);
1895 } else {
1896 return NS_ERROR_UNEXPECTED;
1897 }
1898 // To add the header to 'Networking Dashboard' log
1899 if (mConnectionLogService && !mPrivateBrowsing) {
1900 mConnectionLogService->NewMsgReceived(mHost, mSerial, count);
1901 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)
;
1902 }
1903 }
1904 } else if (opcode != nsIWebSocketFrame::OPCODE_CONTINUATION) {
1905 /* unknown opcode */
1906 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)
;
1907 return NS_ERROR_ILLEGAL_VALUE;
1908 }
1909
1910 mFramePtr = payload + payloadLength;
1911 avail -= payloadLength;
1912 totalAvail = avail;
1913 }
1914
1915 // Adjust the stateful buffer. If we were operating off the stack and
1916 // now have a partial message then transition to the buffer, or if
1917 // we were working off the buffer but no longer have any active state
1918 // then transition to the stack
1919 if (!IsPersistentFramePtr()) {
1920 mBuffered = 0;
1921
1922 if (mFragmentAccumulator) {
1923 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)
;
1924
1925 if (!UpdateReadBuffer(mFramePtr - mFragmentAccumulator,
1926 totalAvail + mFragmentAccumulator, 0, nullptr)) {
1927 return NS_ERROR_FILE_TOO_BIG;
1928 }
1929
1930 // UpdateReadBuffer will reset the frameptr to the beginning
1931 // of new saved state, so we need to skip past processed framgents
1932 mFramePtr += mFragmentAccumulator;
1933 } else if (totalAvail) {
1934 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)
;
1935 if (!UpdateReadBuffer(mFramePtr, totalAvail, 0, nullptr)) {
1936 return NS_ERROR_FILE_TOO_BIG;
1937 }
1938 }
1939 } else if (!mFragmentAccumulator && !totalAvail) {
1940 // If we were working off a saved buffer state and there is no partial
1941 // frame or fragment in process, then revert to stack behavior
1942 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)
;
1943 mBuffered = 0;
1944
1945 // release memory if we've been processing a large message
1946 if (mBufferSize > kIncomingBufferStableSize) {
1947 mBufferSize = kIncomingBufferStableSize;
1948 free(mBuffer);
1949 mBuffer = (uint8_t*)moz_xmalloc(mBufferSize);
1950 }
1951 }
1952 return NS_OK;
1953}
1954
1955/* static */
1956void WebSocketChannel::ApplyMask(uint32_t mask, uint8_t* data, uint64_t len) {
1957 if (!data || len == 0) return;
1958
1959 // Optimally we want to apply the mask 32 bits at a time,
1960 // but the buffer might not be alligned. So we first deal with
1961 // 0 to 3 bytes of preamble individually
1962
1963 while (len && (reinterpret_cast<uintptr_t>(data) & 3)) {
1964 *data ^= mask >> 24;
1965 mask = RotateLeft(mask, 8);
1966 data++;
1967 len--;
1968 }
1969
1970 // perform mask on full words of data
1971
1972 uint32_t* iData = (uint32_t*)data;
1973 uint32_t* end = iData + (len / 4);
1974 NetworkEndian::writeUint32(&mask, mask);
1975 for (; iData < end; iData++) *iData ^= mask;
1976 mask = NetworkEndian::readUint32(&mask);
1977 data = (uint8_t*)iData;
1978 len = len % 4;
1979
1980 // There maybe up to 3 trailing bytes that need to be dealt with
1981 // individually
1982
1983 while (len) {
1984 *data ^= mask >> 24;
1985 mask = RotateLeft(mask, 8);
1986 data++;
1987 len--;
1988 }
1989}
1990
1991void WebSocketChannel::GeneratePing() {
1992 nsAutoCString buf;
1993 buf.AssignLiteral("PING");
1994 EnqueueOutgoingMessage(mOutgoingPingMessages,
1995 new OutboundMessage(kMsgTypePing, buf));
1996}
1997
1998void WebSocketChannel::GeneratePong(uint8_t* payload, uint32_t len) {
1999 nsAutoCString buf;
2000 buf.SetLength(len);
2001 if (buf.Length() < len) {
2002 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)
;
2003 return;
2004 }
2005
2006 memcpy(buf.BeginWriting(), payload, len);
2007 EnqueueOutgoingMessage(mOutgoingPongMessages,
2008 new OutboundMessage(kMsgTypePong, buf));
2009}
2010
2011void WebSocketChannel::EnqueueOutgoingMessage(nsDeque<OutboundMessage>& aQueue,
2012 OutboundMessage* aMsg) {
2013 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"
, 2013); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mIOThread->IsOnCurrentThread()"
") (" "not on right thread" ")"); do { MOZ_CrashSequence(__null
, 2013); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
2014
2015 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)
2016 ("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)
2017 "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)
2018 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)
;
2019
2020 aQueue.Push(aMsg);
2021 OnOutputStreamReady(mSocketOut);
2022}
2023
2024uint16_t WebSocketChannel::ResultToCloseCode(nsresult resultCode) {
2025 if (NS_SUCCEEDED(resultCode)((bool)(__builtin_expect(!!(!NS_FAILED_impl(resultCode)), 1))
)
) return CLOSE_NORMAL;
2026
2027 switch (resultCode) {
2028 case NS_ERROR_FILE_TOO_BIG:
2029 case NS_ERROR_OUT_OF_MEMORY:
2030 return CLOSE_TOO_LARGE;
2031 case NS_ERROR_CANNOT_CONVERT_DATA:
2032 return CLOSE_INVALID_PAYLOAD;
2033 case NS_ERROR_UNEXPECTED:
2034 return CLOSE_INTERNAL_ERROR;
2035 default:
2036 return CLOSE_PROTOCOL_ERROR;
2037 }
2038}
2039
2040void WebSocketChannel::PrimeNewOutgoingMessage() {
2041 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)
;
2042 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"
, 2042); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mIOThread->IsOnCurrentThread()"
") (" "not on right thread" ")"); do { MOZ_CrashSequence(__null
, 2042); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
2043 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"
, 2043); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mCurrentOut"
") (" "Current message in progress" ")"); do { MOZ_CrashSequence
(__null, 2043); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2044
2045 nsresult rv = NS_OK;
2046
2047 mCurrentOut = mOutgoingPongMessages.PopFront();
2048 if (mCurrentOut) {
2049 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"
, 2049); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mCurrentOut->GetMsgType() == kMsgTypePong"
") (" "Not pong message!" ")"); do { MOZ_CrashSequence(__null
, 2049); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
2050 } else {
2051 mCurrentOut = mOutgoingPingMessages.PopFront();
2052 if (mCurrentOut) {
2053 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"
, 2054); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mCurrentOut->GetMsgType() == kMsgTypePing"
") (" "Not ping message!" ")"); do { MOZ_CrashSequence(__null
, 2054); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
2054 "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"
, 2054); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mCurrentOut->GetMsgType() == kMsgTypePing"
") (" "Not ping message!" ")"); do { MOZ_CrashSequence(__null
, 2054); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
2055 } else {
2056 mCurrentOut = mOutgoingMessages.PopFront();
2057 }
2058 }
2059
2060 if (!mCurrentOut) return;
2061
2062 auto cleanupAfterFailure =
2063 MakeScopeExit([&] { DeleteCurrentOutGoingMessage(); });
2064
2065 WsMsgType msgType = mCurrentOut->GetMsgType();
2066
2067 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)
2068 ("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)
2069 "%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)
2070 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)
;
2071
2072 mCurrentOutSent = 0;
2073 mHdrOut = mOutHeader;
2074
2075 uint8_t maskBit = mIsServerSide ? 0 : kMaskBit;
2076 uint8_t maskSize = mIsServerSide ? 0 : 4;
2077
2078 uint8_t* payload = nullptr;
2079
2080 if (msgType == kMsgTypeFin) {
2081 // This is a demand to create a close message
2082 if (mClientClosed) {
2083 DeleteCurrentOutGoingMessage();
2084 PrimeNewOutgoingMessage();
2085 cleanupAfterFailure.release();
2086 return;
2087 }
2088
2089 mClientClosed = true;
2090 mOutHeader[0] = kFinalFragBit | nsIWebSocketFrame::OPCODE_CLOSE;
2091 mOutHeader[1] = maskBit;
2092
2093 // payload is offset 2 plus size of the mask
2094 payload = mOutHeader + 2 + maskSize;
2095
2096 // The close reason code sits in the first 2 bytes of payload
2097 // If the channel user provided a code and reason during Close()
2098 // and there isn't an internal error, use that.
2099 if (NS_SUCCEEDED(mStopOnClose)((bool)(__builtin_expect(!!(!NS_FAILED_impl(mStopOnClose)), 1
)))
) {
2100 MutexAutoLock lock(mMutex);
2101 if (mScriptCloseCode) {
2102 NetworkEndian::writeUint16(payload, mScriptCloseCode);
2103 mOutHeader[1] += 2;
2104 mHdrOutToSend = 4 + maskSize;
2105 if (!mScriptCloseReason.IsEmpty()) {
2106 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"
, 2107); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mScriptCloseReason.Length() <= 123"
") (" "Close Reason Too Long" ")"); do { MOZ_CrashSequence(__null
, 2107); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
2107 "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"
, 2107); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mScriptCloseReason.Length() <= 123"
") (" "Close Reason Too Long" ")"); do { MOZ_CrashSequence(__null
, 2107); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
2108 mOutHeader[1] += mScriptCloseReason.Length();
2109 mHdrOutToSend += mScriptCloseReason.Length();
2110 memcpy(payload + 2, mScriptCloseReason.BeginReading(),
2111 mScriptCloseReason.Length());
2112 }
2113 } else {
2114 // No close code/reason, so payload length = 0. We must still send mask
2115 // even though it's not used. Keep payload offset so we write mask
2116 // below.
2117 mHdrOutToSend = 2 + maskSize;
2118 }
2119 } else {
2120 NetworkEndian::writeUint16(payload, ResultToCloseCode(mStopOnClose));
2121 mOutHeader[1] += 2;
2122 mHdrOutToSend = 4 + maskSize;
2123 }
2124
2125 if (mServerClosed) {
2126 /* bidi close complete */
2127 mReleaseOnTransmit = 1;
2128 } else if (NS_FAILED(mStopOnClose)((bool)(__builtin_expect(!!(NS_FAILED_impl(mStopOnClose)), 0)
))
) {
2129 /* result of abort session - give up */
2130 StopSession(mStopOnClose);
2131 } else {
2132 /* wait for reciprocal close from server */
2133 rv = NS_NewTimerWithCallback(getter_AddRefs(mCloseTimer), this,
2134 mCloseTimeout, nsITimer::TYPE_ONE_SHOT);
2135 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
2136 StopSession(rv);
2137 }
2138 }
2139 } else {
2140 switch (msgType) {
2141 case kMsgTypePong:
2142 mOutHeader[0] = kFinalFragBit | nsIWebSocketFrame::OPCODE_PONG;
2143 break;
2144 case kMsgTypePing:
2145 mOutHeader[0] = kFinalFragBit | nsIWebSocketFrame::OPCODE_PING;
2146 break;
2147 case kMsgTypeString:
2148 mOutHeader[0] = kFinalFragBit | nsIWebSocketFrame::OPCODE_TEXT;
2149 break;
2150 case kMsgTypeStream:
2151 // HACK ALERT: read in entire stream into string.
2152 // Will block socket transport thread if file is blocking.
2153 // TODO: bug 704447: don't block socket thread!
2154 rv = mCurrentOut->ConvertStreamToString();
2155 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
2156 AbortSession(NS_ERROR_FILE_TOO_BIG);
2157 return;
2158 }
2159 // Now we're a binary string
2160 msgType = kMsgTypeBinaryString;
2161
2162 // no break: fall down into binary string case
2163 [[fallthrough]];
2164
2165 case kMsgTypeBinaryString:
2166 mOutHeader[0] = kFinalFragBit | nsIWebSocketFrame::OPCODE_BINARY;
2167 break;
2168 case kMsgTypeFin:
2169 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"
, 2169); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"unreachable" ")"); do { MOZ_CrashSequence(__null, 2169); __attribute__
((nomerge)) ::abort(); } while (false); } } while (false)
; // avoid compiler warning
2170 break;
2171 }
2172
2173 // deflate the payload if PMCE is negotiated
2174 MutexAutoLock lock(mCompressorMutex);
2175 if (mPMCECompressor &&
2176 (msgType == kMsgTypeString || msgType == kMsgTypeBinaryString)) {
2177 if (mCurrentOut->DeflatePayload(mPMCECompressor.get())) {
2178 // The payload was deflated successfully, set RSV1 bit
2179 mOutHeader[0] |= kRsv1Bit;
2180
2181 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)
2182 ("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)
2183 "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)
2184 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)
2185 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)
;
2186 }
2187 }
2188
2189 if (mCurrentOut->Length() < 126) {
2190 mOutHeader[1] = mCurrentOut->Length() | maskBit;
2191 mHdrOutToSend = 2 + maskSize;
2192 } else if (mCurrentOut->Length() <= 0xffff) {
2193 mOutHeader[1] = 126 | maskBit;
2194 NetworkEndian::writeUint16(mOutHeader + sizeof(uint16_t),
2195 mCurrentOut->Length());
2196 mHdrOutToSend = 4 + maskSize;
2197 } else {
2198 mOutHeader[1] = 127 | maskBit;
2199 NetworkEndian::writeUint64(mOutHeader + 2, mCurrentOut->Length());
2200 mHdrOutToSend = 10 + maskSize;
2201 }
2202 payload = mOutHeader + mHdrOutToSend;
2203 }
2204
2205 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"
, 2205); AnnotateMozCrashReason("MOZ_ASSERT" "(" "payload" ") ("
"payload offset not found" ")"); do { MOZ_CrashSequence(__null
, 2205); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
2206
2207 uint32_t mask = 0;
2208 if (!mIsServerSide) {
2209 // Perform the sending mask. Never use a zero mask
2210 do {
2211 static_assert(4 == sizeof(mask), "Size of the mask should be equal to 4");
2212 nsresult rv = mRandomGenerator->GenerateRandomBytesInto(mask);
2213 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
2214 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)
2215 ("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)
2216 "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)
2217 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)
;
2218 AbortSession(rv);
2219 return;
2220 }
2221 } while (!mask);
2222 NetworkEndian::writeUint32(payload - sizeof(uint32_t), mask);
2223 }
2224
2225 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)
;
2226
2227 // We don't mask the framing, but occasionally we stick a little payload
2228 // data in the buffer used for the framing. Close frames are the current
2229 // example. This data needs to be masked, but it is never more than a
2230 // handful of bytes and might rotate the mask, so we can just do it locally.
2231 // For real data frames we ship the bulk of the payload off to ApplyMask()
2232
2233 RefPtr<WebSocketFrame> frame = mService->CreateFrameIfNeeded(
2234 mOutHeader[0] & WebSocketChannel::kFinalFragBit,
2235 mOutHeader[0] & WebSocketChannel::kRsv1Bit,
2236 mOutHeader[0] & WebSocketChannel::kRsv2Bit,
2237 mOutHeader[0] & WebSocketChannel::kRsv3Bit,
2238 mOutHeader[0] & WebSocketChannel::kOpcodeBitsMask,
2239 mOutHeader[1] & WebSocketChannel::kMaskBit, mask, payload,
2240 mHdrOutToSend - (payload - mOutHeader), mCurrentOut->BeginOrigReading(),
2241 mCurrentOut->OrigLength());
2242
2243 if (frame) {
2244 mService->FrameSent(mSerial, mInnerWindowID, mHttpChannelId,
2245 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 (mConnectionLogService && !mPrivateBrowsing) {
2356 mConnectionLogService->RemoveHost(mHost, mSerial);
2357 }
2358
2359 // The observer has to be removed on the main-thread.
2360 NS_DispatchToMainThread(new RemoveObserverRunnable(this));
2361
2362 DecrementSessionCount();
2363}
2364
2365void WebSocketChannel::StopSession(nsresult reason) {
2366 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)
2367 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)
;
2368
2369 {
2370 MutexAutoLock lock(mMutex);
2371 if (mStopped) {
2372 return;
2373 }
2374 mStopped = true;
2375 }
2376
2377 DoStopSession(reason);
2378}
2379
2380void WebSocketChannel::DoStopSession(nsresult reason) {
2381 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)
2382 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)
;
2383
2384 // normally this should be called on socket thread, but it is ok to call it
2385 // from OnStartRequest before the socket thread machine has gotten underway.
2386 // If mDataStarted is false, this is called on MainThread for Close().
2387 // Otherwise it should be called on the IO thread
2388
2389 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"
, 2389); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mStopped" ")"
); do { MOZ_CrashSequence(__null, 2389); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2390 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"
, 2390); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mIOThread->IsOnCurrentThread() || mTCPClosed || !mDataStarted"
")"); do { MOZ_CrashSequence(__null, 2390); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2391
2392 if (!mOpenedHttpChannel) {
2393 // The HTTP channel information will never be used in this case
2394 NS_ReleaseOnMainThread("WebSocketChannel::mChannel", mChannel.forget());
2395 NS_ReleaseOnMainThread("WebSocketChannel::mHttpChannel",
2396 mHttpChannel.forget());
2397 NS_ReleaseOnMainThread("WebSocketChannel::mLoadGroup", mLoadGroup.forget());
2398 NS_ReleaseOnMainThread("WebSocketChannel::mCallbacks", mCallbacks.forget());
2399 }
2400
2401 if (mCloseTimer) {
2402 mCloseTimer->Cancel();
2403 mCloseTimer = nullptr;
2404 }
2405
2406 // mOpenTimer must be null if mDataStarted is true and we're not on MainThread
2407 if (mOpenTimer) {
2408 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"
, 2408); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
") (" "not main thread" ")"); do { MOZ_CrashSequence(__null,
2408); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false)
;
2409 mOpenTimer->Cancel();
2410 mOpenTimer = nullptr;
2411 }
2412
2413 {
2414 MutexAutoLock lock(mMutex);
2415 if (mReconnectDelayTimer) {
2416 mReconnectDelayTimer->Cancel();
2417 NS_ReleaseOnMainThread("WebSocketChannel::mMutex",
2418 mReconnectDelayTimer.forget());
2419 }
2420 }
2421
2422 if (mPingTimer) {
2423 mPingTimer->Cancel();
2424 mPingTimer = nullptr;
2425 }
2426
2427 if (!mTCPClosed && mDataStarted) {
2428 if (mSocketIn) {
2429 // Drain, within reason, this socket. if we leave any data
2430 // unconsumed (including the tcp fin) a RST will be generated
2431 // The right thing to do here is shutdown(SHUT_WR) and then wait
2432 // a little while to see if any data comes in.. but there is no
2433 // reason to delay things for that when the websocket handshake
2434 // is supposed to guarantee a quiet connection except for that fin.
2435
2436 char buffer[512];
2437 uint32_t count = 0;
2438 uint32_t total = 0;
2439 nsresult rv;
2440 do {
2441 total += count;
2442 rv = mSocketIn->Read(buffer, 512, &count);
2443 if (rv != NS_BASE_STREAM_WOULD_BLOCK && (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) || count == 0)) {
2444 mTCPClosed = true;
2445 }
2446 } while (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) && count > 0 && total < 32000);
2447 }
2448 }
2449
2450 int32_t sessionCount = kLingeringCloseThreshold;
2451 nsWSAdmissionManager::GetSessionCount(sessionCount);
2452
2453 if (!mTCPClosed && mTransport && sessionCount < kLingeringCloseThreshold) {
2454 // 7.1.1 says that the client SHOULD wait for the server to close the TCP
2455 // connection. This is so we can reuse port numbers before 2 MSL expires,
2456 // which is not really as much of a concern for us as the amount of state
2457 // that might be accrued by keeping this channel object around waiting for
2458 // the server. We handle the SHOULD by waiting a short time in the common
2459 // case, but not waiting in the case of high concurrency.
2460 //
2461 // Normally this will be taken care of in AbortSession() after mTCPClosed
2462 // is set when the server close arrives without waiting for the timeout to
2463 // expire.
2464
2465 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)
;
2466
2467 nsresult rv;
2468 rv = NS_NewTimerWithCallback(getter_AddRefs(mLingeringCloseTimer), this,
2469 kLingeringCloseTimeout,
2470 nsITimer::TYPE_ONE_SHOT);
2471 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) CleanupConnection();
2472 } else {
2473 CleanupConnection();
2474 }
2475
2476 {
2477 MutexAutoLock lock(mMutex);
2478 if (mCancelable) {
2479 mCancelable->Cancel(NS_ERROR_UNEXPECTED);
2480 mCancelable = nullptr;
2481 }
2482 }
2483
2484 {
2485 MutexAutoLock lock(mCompressorMutex);
2486 mPMCECompressor = nullptr;
2487 }
2488 if (!mCalledOnStop) {
2489 mCalledOnStop = true;
2490
2491 nsWSAdmissionManager::OnStopSession(this, reason);
2492
2493 RefPtr<CallOnStop> runnable =
2494 new CallOnStop(this, TakeListenerMT(), reason);
2495 if (nsCOMPtr<nsIEventTarget> target = GetTargetThread()) {
2496 target->Dispatch(runnable, NS_DISPATCH_NORMALnsIEventTarget::DISPATCH_NORMAL);
2497 }
2498 }
2499}
2500
2501// Called from MainThread, and called from IOThread in
2502// PrimeNewOutgoingMessage
2503void WebSocketChannel::AbortSession(nsresult reason) {
2504 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)
2505 "] 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)
2506 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)
;
2507
2508 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"
, 2508); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(NS_FAILED_impl(reason)), 0)))"
") (" "reason must be a failure!" ")"); do { MOZ_CrashSequence
(__null, 2508); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2509
2510 // normally this should be called on socket thread, but it is ok to call it
2511 // from the main thread before StartWebsocketData() has completed
2512 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"
, 2512); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mIOThread->IsOnCurrentThread() || !mDataStarted"
")"); do { MOZ_CrashSequence(__null, 2512); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2513
2514 // When we are failing we need to close the TCP connection immediately
2515 // as per 7.1.1
2516 mTCPClosed = true;
2517
2518 if (mLingeringCloseTimer) {
2519 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"
, 2519); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mStopped" ") ("
"Lingering without Stop" ")"); do { MOZ_CrashSequence(__null
, 2519); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
2520 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)
;
2521 CleanupConnection();
2522 return;
2523 }
2524
2525 {
2526 MutexAutoLock lock(mMutex);
2527 if (mStopped) {
2528 return;
2529 }
2530
2531 if (mTransport && reason != NS_BASE_STREAM_CLOSED && !mRequestedClose &&
2532 !mClientClosed && !mServerClosed && mDataStarted) {
2533 mRequestedClose = true;
2534 mStopOnClose = reason;
2535 mIOThread->Dispatch(
2536 new OutboundEnqueuer(this,
2537 new OutboundMessage(kMsgTypeFin, VoidCString())),
2538 nsIEventTarget::DISPATCH_NORMAL);
2539 return;
2540 }
2541
2542 mStopped = true;
2543 }
2544
2545 DoStopSession(reason);
2546}
2547
2548// ReleaseSession is called on orderly shutdown
2549void WebSocketChannel::ReleaseSession() {
2550 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)
2551 !!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)
;
2552 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"
, 2552); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mIOThread->IsOnCurrentThread()"
") (" "not on right thread" ")"); do { MOZ_CrashSequence(__null
, 2552); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
2553
2554 StopSession(NS_OK);
2555}
2556
2557void WebSocketChannel::IncrementSessionCount() {
2558 if (!mIncrementedSessionCount) {
2559 nsWSAdmissionManager::IncrementSessionCount();
2560 mIncrementedSessionCount = true;
2561 }
2562}
2563
2564void WebSocketChannel::DecrementSessionCount() {
2565 // Make sure we decrement session count only once, and only if we incremented
2566 // it. This code is thread-safe: sWebSocketAdmissions->DecrementSessionCount
2567 // is atomic, and mIncrementedSessionCount/mDecrementedSessionCount are set at
2568 // times when they'll never be a race condition for checking/setting them.
2569 if (mIncrementedSessionCount && !mDecrementedSessionCount) {
2570 nsWSAdmissionManager::DecrementSessionCount();
2571 mDecrementedSessionCount = true;
2572 }
2573}
2574
2575namespace {
2576enum ExtensionParseMode { eParseServerSide, eParseClientSide };
2577}
2578
2579static nsresult ParseWebSocketExtension(const nsACString& aExtension,
2580 ExtensionParseMode aMode,
2581 bool& aClientNoContextTakeover,
2582 bool& aServerNoContextTakeover,
2583 int32_t& aClientMaxWindowBits,
2584 int32_t& aServerMaxWindowBits) {
2585 nsCCharSeparatedTokenizer tokens(aExtension, ';');
2586
2587 if (!tokens.hasMoreTokens() ||
2588 !tokens.nextToken().EqualsLiteral("permessage-deflate")) {
2589 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)
2590 ("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)
2591 "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)
2592 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)
;
2593 return NS_ERROR_ILLEGAL_VALUE;
2594 }
2595
2596 aClientNoContextTakeover = aServerNoContextTakeover = false;
2597 aClientMaxWindowBits = aServerMaxWindowBits = -1;
2598
2599 while (tokens.hasMoreTokens()) {
2600 auto token = tokens.nextToken();
2601
2602 int32_t nameEnd, valueStart;
2603 int32_t delimPos = token.FindChar('=');
2604 if (delimPos == kNotFound) {
2605 nameEnd = token.Length();
2606 valueStart = token.Length();
2607 } else {
2608 nameEnd = delimPos;
2609 valueStart = delimPos + 1;
2610 }
2611
2612 auto paramName = Substring(token, 0, nameEnd);
2613 auto paramValue = Substring(token, valueStart);
2614
2615 if (paramName.EqualsLiteral("client_no_context_takeover")) {
2616 if (!paramValue.IsEmpty()) {
2617 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)
2618 ("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)
2619 "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)
2620 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)
;
2621 return NS_ERROR_ILLEGAL_VALUE;
2622 }
2623 if (aClientNoContextTakeover) {
2624 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)
2625 ("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)
2626 "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)
;
2627 return NS_ERROR_ILLEGAL_VALUE;
2628 }
2629 aClientNoContextTakeover = true;
2630 } else if (paramName.EqualsLiteral("server_no_context_takeover")) {
2631 if (!paramValue.IsEmpty()) {
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: parameter "
"server_no_context_takeover must not have value, found %s\n"
, TPromiseFlatString<char>(paramValue).get()); } } while
(0)
2633 ("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)
2634 "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)
2635 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)
;
2636 return NS_ERROR_ILLEGAL_VALUE;
2637 }
2638 if (aServerNoContextTakeover) {
2639 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)
2640 ("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)
2641 "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)
;
2642 return NS_ERROR_ILLEGAL_VALUE;
2643 }
2644 aServerNoContextTakeover = true;
2645 } else if (paramName.EqualsLiteral("client_max_window_bits")) {
2646 if (aClientMaxWindowBits != -1) {
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 client_max_window_bits\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 client_max_window_bits\n"); } } while (0)
2649 "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)
;
2650 return NS_ERROR_ILLEGAL_VALUE;
2651 }
2652
2653 if (aMode == eParseServerSide && paramValue.IsEmpty()) {
2654 // Use -2 to indicate that "client_max_window_bits" has been parsed,
2655 // but had no value.
2656 aClientMaxWindowBits = -2;
2657 } else {
2658 nsresult errcode;
2659 aClientMaxWindowBits =
2660 PromiseFlatCStringTPromiseFlatString<char>(paramValue).ToInteger(&errcode);
2661 if (NS_FAILED(errcode)((bool)(__builtin_expect(!!(NS_FAILED_impl(errcode)), 0))) || aClientMaxWindowBits < 8 ||
2662 aClientMaxWindowBits > 15) {
2663 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)
2664 ("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)
2665 "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)
2666 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)
;
2667 return NS_ERROR_ILLEGAL_VALUE;
2668 }
2669 }
2670 } else if (paramName.EqualsLiteral("server_max_window_bits")) {
2671 if (aServerMaxWindowBits != -1) {
2672 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)
2673 ("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)
2674 "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)
;
2675 return NS_ERROR_ILLEGAL_VALUE;
2676 }
2677
2678 nsresult errcode;
2679 aServerMaxWindowBits = PromiseFlatCStringTPromiseFlatString<char>(paramValue).ToInteger(&errcode);
2680 if (NS_FAILED(errcode)((bool)(__builtin_expect(!!(NS_FAILED_impl(errcode)), 0))) || aServerMaxWindowBits < 8 ||
2681 aServerMaxWindowBits > 15) {
2682 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)
2683 ("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)
2684 "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)
2685 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)
;
2686 return NS_ERROR_ILLEGAL_VALUE;
2687 }
2688 } else {
2689 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)
2690 ("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)
2691 "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)
2692 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)
;
2693 return NS_ERROR_ILLEGAL_VALUE;
2694 }
2695 }
2696
2697 if (aClientMaxWindowBits == -2) {
2698 aClientMaxWindowBits = -1;
2699 }
2700
2701 return NS_OK;
2702}
2703
2704nsresult WebSocketChannel::HandleExtensions() {
2705 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)
;
2706
2707 nsresult rv;
2708 nsAutoCString extensions;
2709
2710 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"
, 2710); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
") (" "not main thread" ")"); do { MOZ_CrashSequence(__null,
2710); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false)
;
2711
2712 rv = mHttpChannel->GetResponseHeader("Sec-WebSocket-Extensions"_ns,
Value stored to 'rv' is never read
2713 extensions);
2714 extensions.CompressWhitespace();
2715 if (extensions.IsEmpty()) {
2716 return NS_OK;
2717 }
2718
2719 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)
2720 ("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)
2721 "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)
2722 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)
;
2723
2724 bool clientNoContextTakeover;
2725 bool serverNoContextTakeover;
2726 int32_t clientMaxWindowBits;
2727 int32_t serverMaxWindowBits;
2728
2729 rv = ParseWebSocketExtension(extensions, eParseClientSide,
2730 clientNoContextTakeover, serverNoContextTakeover,
2731 clientMaxWindowBits, serverMaxWindowBits);
2732 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
2733 AbortSession(rv);
2734 return rv;
2735 }
2736
2737 if (clientMaxWindowBits == -1) {
2738 clientMaxWindowBits = 15;
2739 }
2740 if (serverMaxWindowBits == -1) {
2741 serverMaxWindowBits = 15;
2742 }
2743
2744 MutexAutoLock lock(mCompressorMutex);
2745 mPMCECompressor = std::make_unique<PMCECompression>(
2746 clientNoContextTakeover, clientMaxWindowBits, serverMaxWindowBits);
2747 if (mPMCECompressor->Active()) {
2748 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)
2749 ("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)
2750 "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)
2751 "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)
2752 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)
2753 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)
;
2754
2755 mNegotiatedExtensions = "permessage-deflate";
2756 } else {
2757 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)
2758 ("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)
2759 "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)
;
2760 mPMCECompressor = nullptr;
2761 AbortSession(NS_ERROR_UNEXPECTED);
2762 return NS_ERROR_UNEXPECTED;
2763 }
2764
2765 return NS_OK;
2766}
2767
2768void ProcessServerWebSocketExtensions(const nsACString& aExtensions,
2769 nsACString& aNegotiatedExtensions) {
2770 aNegotiatedExtensions.Truncate();
2771
2772 for (const auto& ext :
2773 nsCCharSeparatedTokenizer(aExtensions, ',').ToRange()) {
2774 bool clientNoContextTakeover;
2775 bool serverNoContextTakeover;
2776 int32_t clientMaxWindowBits;
2777 int32_t serverMaxWindowBits;
2778
2779 nsresult rv = ParseWebSocketExtension(
2780 ext, eParseServerSide, clientNoContextTakeover, serverNoContextTakeover,
2781 clientMaxWindowBits, serverMaxWindowBits);
2782 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
2783 // Ignore extensions that we can't parse
2784 continue;
2785 }
2786
2787 aNegotiatedExtensions.AssignLiteral("permessage-deflate");
2788 if (clientNoContextTakeover) {
2789 aNegotiatedExtensions.AppendLiteral(";client_no_context_takeover");
2790 }
2791 if (serverNoContextTakeover) {
2792 aNegotiatedExtensions.AppendLiteral(";server_no_context_takeover");
2793 }
2794 if (clientMaxWindowBits != -1) {
2795 aNegotiatedExtensions.AppendLiteral(";client_max_window_bits=");
2796 aNegotiatedExtensions.AppendInt(clientMaxWindowBits);
2797 }
2798 if (serverMaxWindowBits != -1) {
2799 aNegotiatedExtensions.AppendLiteral(";server_max_window_bits=");
2800 aNegotiatedExtensions.AppendInt(serverMaxWindowBits);
2801 }
2802
2803 return;
2804 }
2805}
2806
2807nsresult CalculateWebSocketHashedSecret(const nsACString& aKey,
2808 nsACString& aHash) {
2809 nsresult rv;
2810 nsCString key = aKey + "258EAFA5-E914-47DA-95CA-C5AB0DC85B11"_ns;
2811 nsCOMPtr<nsICryptoHash> hasher =
2812 do_CreateInstance(NS_CRYPTO_HASH_CONTRACTID"@mozilla.org/security/hash;1", &rv);
2813 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"
, 2813); return rv; } } while (false)
;
2814 rv = hasher->Init(nsICryptoHash::SHA1);
2815 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"
, 2815); return rv; } } while (false)
;
2816 rv = hasher->Update((const uint8_t*)key.BeginWriting(), key.Length());
2817 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"
, 2817); return rv; } } while (false)
;
2818 return hasher->Finish(true, aHash);
2819}
2820
2821nsresult WebSocketChannel::SetupRequest() {
2822 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)
;
2823
2824 nsresult rv;
2825
2826 if (mLoadGroup) {
2827 rv = mHttpChannel->SetLoadGroup(mLoadGroup);
2828 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"
, 2828); return rv; } } while (false)
;
2829 }
2830
2831 rv = mHttpChannel->SetLoadFlags(
2832 nsIRequest::LOAD_BACKGROUND | nsIRequest::INHIBIT_CACHING |
2833 nsIRequest::LOAD_BYPASS_CACHE | nsIChannel::LOAD_BYPASS_SERVICE_WORKER);
2834 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"
, 2834); return rv; } } while (false)
;
2835
2836 // we never let websockets be blocked by head CSS/JS loads to avoid
2837 // potential deadlock where server generation of CSS/JS requires
2838 // an XHR signal.
2839 nsCOMPtr<nsIClassOfService> cos(do_QueryInterface(mChannel));
2840 if (cos) {
2841 cos->AddClassFlags(nsIClassOfService::Unblocked);
2842 }
2843
2844 // draft-ietf-hybi-thewebsocketprotocol-07 illustrates Upgrade: websocket
2845 // in lower case, so go with that. It is technically case insensitive.
2846 rv = mChannel->HTTPUpgrade("websocket"_ns, this);
2847 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"
, 2847); return rv; } } while (false)
;
2848
2849 rv = mHttpChannel->SetRequestHeader("Sec-WebSocket-Version"_ns,
2850 nsLiteralCString(SEC_WEBSOCKET_VERSION"13"),
2851 false);
2852 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"
, 2852); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))"
")"); do { MOZ_CrashSequence(__null, 2852); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2853
2854 if (!mOrigin.IsEmpty()) {
2855 rv = mHttpChannel->SetRequestHeader("Origin"_ns, mOrigin, false);
2856 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"
, 2856); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))"
")"); do { MOZ_CrashSequence(__null, 2856); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2857 }
2858
2859 if (!mProtocol.IsEmpty()) {
2860 rv = mHttpChannel->SetRequestHeader("Sec-WebSocket-Protocol"_ns, mProtocol,
2861 true);
2862 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"
, 2862); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))"
")"); do { MOZ_CrashSequence(__null, 2862); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2863 }
2864
2865 rv = mHttpChannel->SetRequestHeader("Sec-WebSocket-Extensions"_ns,
2866 "permessage-deflate"_ns, false);
2867 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"
, 2867); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))"
")"); do { MOZ_CrashSequence(__null, 2867); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2868
2869 uint8_t* secKey;
2870 nsAutoCString secKeyString;
2871
2872 rv = mRandomGenerator->GenerateRandomBytes(16, &secKey);
2873 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"
, 2873); return rv; } } while (false)
;
2874 rv = Base64Encode(reinterpret_cast<const char*>(secKey), 16, secKeyString);
2875 free(secKey);
2876 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
2877 return rv;
2878 }
2879
2880 rv = mHttpChannel->SetRequestHeader("Sec-WebSocket-Key"_ns, secKeyString,
2881 false);
2882 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"
, 2882); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))"
")"); do { MOZ_CrashSequence(__null, 2882); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2883 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)
;
2884
2885 // prepare the value we expect to see in
2886 // the sec-websocket-accept response header
2887 rv = CalculateWebSocketHashedSecret(secKeyString, mHashedSecret);
2888 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"
, 2888); return rv; } } while (false)
;
2889 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)
2890 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)
;
2891
2892 mHttpChannelId = mHttpChannel->ChannelId();
2893
2894 return NS_OK;
2895}
2896
2897nsresult WebSocketChannel::DoAdmissionDNS() {
2898 nsresult rv;
2899
2900 nsCString hostName;
2901 rv = mURI->GetHost(hostName);
2902 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"
, 2902); return rv; } } while (false)
;
2903 mAddress = hostName;
2904 nsCString path;
2905 rv = mURI->GetFilePath(path);
2906 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"
, 2906); return rv; } } while (false)
;
2907 mPath = std::move(path);
2908 rv = mURI->GetPort(&mPort);
2909 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"
, 2909); return rv; } } while (false)
;
2910 if (mPort == -1) mPort = (mEncrypted ? kDefaultWSSPort : kDefaultWSPort);
2911 nsCOMPtr<nsIDNSService> dns;
2912 dns = mozilla::components::DNS::Service(&rv);
2913 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"
, 2913); return rv; } } while (false)
;
2914 nsCOMPtr<nsIEventTarget> main = GetMainThreadSerialEventTarget();
2915 nsCOMPtr<nsICancelable> cancelable;
2916 rv = dns->AsyncResolveNative(hostName, nsIDNSService::RESOLVE_TYPE_DEFAULT,
2917 nsIDNSService::RESOLVE_DEFAULT_FLAGS, nullptr,
2918 this, main, mLoadInfo->GetOriginAttributes(),
2919 getter_AddRefs(cancelable));
2920 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
2921 return rv;
2922 }
2923
2924 MutexAutoLock lock(mMutex);
2925 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"
, 2925); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mCancelable"
")"); do { MOZ_CrashSequence(__null, 2925); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2926 mCancelable = std::move(cancelable);
2927 return rv;
2928}
2929
2930nsresult WebSocketChannel::ApplyForAdmission() {
2931 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)
;
2932
2933 // Websockets has a policy of 1 session at a time being allowed in the
2934 // CONNECTING state per server IP address (not hostname)
2935
2936 // Check to see if a proxy is being used before making DNS call
2937 nsCOMPtr<nsIProtocolProxyService> pps;
2938 pps = mozilla::components::ProtocolProxy::Service();
2939
2940 if (!pps) {
2941 // go straight to DNS
2942 // expect the callback in ::OnLookupComplete
2943 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)
2944 "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)
;
2945 return DoAdmissionDNS();
2946 }
2947
2948 nsresult rv;
2949 nsCOMPtr<nsICancelable> cancelable;
2950 rv = pps->AsyncResolve(
2951 mHttpChannel,
2952 nsIProtocolProxyService::RESOLVE_PREFER_SOCKS_PROXY |
2953 nsIProtocolProxyService::RESOLVE_PREFER_HTTPS_PROXY |
2954 nsIProtocolProxyService::RESOLVE_ALWAYS_TUNNEL,
2955 this, nullptr, getter_AddRefs(cancelable));
2956
2957 MutexAutoLock lock(mMutex);
2958 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"
, 2958); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mCancelable"
")"); do { MOZ_CrashSequence(__null, 2958); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2959 mCancelable = std::move(cancelable);
2960 return rv;
2961}
2962
2963// Called after both OnStartRequest and OnTransportAvailable have
2964// executed. This essentially ends the handshake and starts the websockets
2965// protocol state machine.
2966nsresult WebSocketChannel::CallStartWebsocketData() {
2967 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)
;
2968 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"
, 2968); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
") (" "not main thread" ")"); do { MOZ_CrashSequence(__null,
2968); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false)
;
2969
2970 if (mOpenTimer) {
2971 mOpenTimer->Cancel();
2972 mOpenTimer = nullptr;
2973 }
2974
2975 nsCOMPtr<nsIEventTarget> target = GetTargetThread();
2976 if (target && !target->IsOnCurrentThread()) {
2977 return target->Dispatch(
2978 NewRunnableMethod("net::WebSocketChannel::StartWebsocketData", this,
2979 &WebSocketChannel::StartWebsocketData),
2980 NS_DISPATCH_NORMALnsIEventTarget::DISPATCH_NORMAL);
2981 }
2982
2983 return StartWebsocketData();
2984}
2985
2986nsresult WebSocketChannel::StartWebsocketData() {
2987 {
2988 MutexAutoLock lock(mMutex);
2989 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)
;
2990 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"
, 2990); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mDataStarted"
") (" "StartWebsocketData twice" ")"); do { MOZ_CrashSequence
(__null, 2990); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2991
2992 if (mStopped) {
2993 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)
2994 ("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)
2995 "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)
;
2996 return NS_ERROR_NOT_AVAILABLE;
2997 }
2998 }
2999
3000 RefPtr<WebSocketChannel> self = this;
3001 mIOThread->Dispatch(NS_NewRunnableFunction(
3002 "WebSocketChannel::StartWebsocketData", [self{std::move(self)}] {
3003 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)
;
3004 {
3005 MutexAutoLock lock(self->mMutex);
3006 if (self->mStopped) {
3007 return;
3008 }
3009 self->mDataStarted = true;
3010 }
3011
3012 NS_DispatchToMainThread(
3013 NewRunnableMethod("net::WebSocketChannel::NotifyOnStart", self,
3014 &WebSocketChannel::NotifyOnStart),
3015 NS_DISPATCH_NORMALnsIEventTarget::DISPATCH_NORMAL);
3016
3017 nsresult rv = self->mSocketIn->AsyncWait(self, 0, 0, self->mIOThread);
3018 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
3019 self->AbortSession(rv);
3020 }
3021
3022 if (self->mPingInterval) {
3023 rv = self->StartPinging();
3024 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
3025 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)
3026 "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)
3027 "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)
3028 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)
;
3029 self->AbortSession(rv);
3030 }
3031 }
3032 }));
3033
3034 return NS_OK;
3035}
3036
3037void WebSocketChannel::NotifyOnStart() {
3038 RefPtr<BaseWebSocketChannel::ListenerAndContextContainer> listener =
3039 GetListenerMT();
3040 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)
3041 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)
;
3042 if (listener) {
3043 nsresult rv = listener->mListener->OnStart(listener->mContext);
3044 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
3045 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)
3046 ("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)
3047 "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)
3048 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)
;
3049 }
3050 }
3051}
3052
3053nsresult WebSocketChannel::StartPinging() {
3054 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)
;
3055 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"
, 3055); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mIOThread->IsOnCurrentThread()"
") (" "not on right thread" ")"); do { MOZ_CrashSequence(__null
, 3055); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
3056 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"
, 3056); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mPingInterval"
")"); do { MOZ_CrashSequence(__null, 3056); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3057 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"
, 3057); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mPingTimer"
")"); do { MOZ_CrashSequence(__null, 3057); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3058
3059 nsresult rv;
3060 rv = NS_NewTimerWithCallback(getter_AddRefs(mPingTimer), this, mPingInterval,
3061 nsITimer::TYPE_ONE_SHOT);
3062 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
3063 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)
3064 (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)
;
3065 } else {
3066 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"
, 3066)
;
3067 }
3068
3069 return NS_OK;
3070}
3071
3072void WebSocketChannel::ReportConnectionTelemetry(nsresult aStatusCode) {
3073 // 3 bits are used. high bit is for wss, middle bit for failed,
3074 // and low bit for proxy..
3075 // 0 - 7 : ws-ok-plain, ws-ok-proxy, ws-failed-plain, ws-failed-proxy,
3076 // wss-ok-plain, wss-ok-proxy, wss-failed-plain, wss-failed-proxy
3077
3078 bool didProxy = false;
3079
3080 nsCOMPtr<nsIProxyInfo> pi;
3081 nsCOMPtr<nsIProxiedChannel> pc = do_QueryInterface(mChannel);
3082 if (pc) pc->GetProxyInfo(getter_AddRefs(pi));
3083 if (pi) {
3084 nsAutoCString proxyType;
3085 pi->GetType(proxyType);
3086 if (!proxyType.IsEmpty() && !proxyType.EqualsLiteral("direct")) {
3087 didProxy = true;
3088 }
3089 }
3090
3091 uint8_t value =
3092 (mEncrypted ? (1 << 2) : 0) |
3093 (!(mGotUpgradeOK && NS_SUCCEEDED(aStatusCode)((bool)(__builtin_expect(!!(!NS_FAILED_impl(aStatusCode)), 1)
))
) ? (1 << 1) : 0) |
3094 (didProxy ? (1 << 0) : 0);
3095
3096 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)
;
3097 glean::websockets::handshake_type.AccumulateSingleSample(value);
3098}
3099
3100// nsIDNSListener
3101
3102NS_IMETHODIMPnsresult
3103WebSocketChannel::OnLookupComplete(nsICancelable* aRequest,
3104 nsIDNSRecord* aRecord, nsresult aStatus) {
3105 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)
3106 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)
;
3107
3108 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"
, 3108); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
") (" "not main thread" ")"); do { MOZ_CrashSequence(__null,
3108); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false)
;
3109
3110 {
3111 MutexAutoLock lock(mMutex);
3112 mCancelable = nullptr;
3113 }
3114
3115 if (mStopped) {
3116 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)
;
3117 return NS_OK;
3118 }
3119
3120 // These failures are not fatal - we just use the hostname as the key
3121 if (NS_FAILED(aStatus)((bool)(__builtin_expect(!!(NS_FAILED_impl(aStatus)), 0)))) {
3122 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)
;
3123
3124 // set host in case we got here without calling DoAdmissionDNS()
3125 mURI->GetHost(mAddress);
3126 } else {
3127 nsCOMPtr<nsIDNSAddrRecord> record = do_QueryInterface(aRecord);
3128 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"
, 3128); AnnotateMozCrashReason("MOZ_ASSERT" "(" "record" ")"
); do { MOZ_CrashSequence(__null, 3128); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3129 nsresult rv = record->GetNextAddrAsString(mAddress);
3130 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
3131 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)
;
3132 }
3133 }
3134
3135 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)
;
3136 nsWSAdmissionManager::ConditionallyConnect(this);
3137
3138 return NS_OK;
3139}
3140
3141// nsIProtocolProxyCallback
3142NS_IMETHODIMPnsresult
3143WebSocketChannel::OnProxyAvailable(nsICancelable* aRequest,
3144 nsIChannel* aChannel, nsIProxyInfo* pi,
3145 nsresult status) {
3146 {
3147 MutexAutoLock lock(mMutex);
3148 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"
, 3148); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mCancelable || (aRequest == mCancelable)"
")"); do { MOZ_CrashSequence(__null, 3148); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3149 mCancelable = nullptr;
3150 }
3151
3152 if (mStopped) {
3153 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)
3154 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)
;
3155 return NS_OK;
3156 }
3157
3158 nsAutoCString type;
3159 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)))
&&
3160 !type.EqualsLiteral("direct")) {
3161 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)
3162 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)
;
3163 // call DNS callback directly without DNS resolver
3164 OnLookupComplete(nullptr, nullptr, NS_ERROR_FAILURE);
3165 } else {
3166 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)
3167 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)
;
3168 nsresult rv = DoAdmissionDNS();
3169 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
3170 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)
;
3171 // call DNS callback directly without DNS resolver
3172 OnLookupComplete(nullptr, nullptr, NS_ERROR_FAILURE);
3173 }
3174 }
3175
3176 // notify listener of OnProxyAvailable
3177 RefPtr<BaseWebSocketChannel::ListenerAndContextContainer> listener =
3178 GetListenerMT();
3179 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)
3180 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)
;
3181 if (!listener) {
3182 return NS_OK;
3183 }
3184 nsresult rv;
3185 nsCOMPtr<nsIProtocolProxyCallback> ppc(
3186 do_QueryInterface(listener->mListener, &rv));
3187 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
3188 rv = ppc->OnProxyAvailable(aRequest, aChannel, pi, status);
3189 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
3190 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)
3191 ("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)
3192 " 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)
3193 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)
;
3194 }
3195 }
3196
3197 return NS_OK;
3198}
3199
3200// nsIInterfaceRequestor
3201
3202NS_IMETHODIMPnsresult
3203WebSocketChannel::GetInterface(const nsIID& iid, void** result) {
3204 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)
;
3205
3206 if (iid.Equals(NS_GET_IID(nsIChannelEventSink)(nsIChannelEventSink::kIID))) {
3207 return QueryInterface(iid, result);
3208 }
3209
3210 if (mCallbacks) return mCallbacks->GetInterface(iid, result);
3211
3212 return NS_ERROR_NO_INTERFACE;
3213}
3214
3215// nsIChannelEventSink
3216
3217NS_IMETHODIMPnsresult
3218WebSocketChannel::AsyncOnChannelRedirect(
3219 nsIChannel* oldChannel, nsIChannel* newChannel, uint32_t flags,
3220 nsIAsyncVerifyRedirectCallback* callback) {
3221 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)
;
3222
3223 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"
, 3223); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
") (" "not main thread" ")"); do { MOZ_CrashSequence(__null,
3223); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false)
;
3224
3225 nsresult rv;
3226
3227 nsCOMPtr<nsIURI> newuri;
3228 rv = newChannel->GetURI(getter_AddRefs(newuri));
3229 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"
, 3229); return rv; } } while (false)
;
3230
3231 // newuri is expected to be http or https
3232 bool newuriIsHttps = newuri->SchemeIs("https");
3233
3234 // allow insecure->secure redirects for HTTP Strict Transport Security (from
3235 // ws://FOO to https://FOO (mapped to wss://FOO)
3236 if (!(flags & (nsIChannelEventSink::REDIRECT_INTERNAL |
3237 nsIChannelEventSink::REDIRECT_STS_UPGRADE))) {
3238 nsAutoCString newSpec;
3239 rv = newuri->GetSpec(newSpec);
3240 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"
, 3240); return rv; } } while (false)
;
3241
3242 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)
3243 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)
;
3244 return NS_ERROR_FAILURE;
3245 }
3246
3247 if (mEncrypted && !newuriIsHttps) {
3248 nsAutoCString spec;
3249 if (NS_SUCCEEDED(newuri->GetSpec(spec))((bool)(__builtin_expect(!!(!NS_FAILED_impl(newuri->GetSpec
(spec))), 1)))
) {
3250 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)
3251 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)
;
3252 }
3253 return NS_ERROR_FAILURE;
3254 }
3255
3256 nsCOMPtr<nsIHttpChannel> newHttpChannel = do_QueryInterface(newChannel, &rv);
3257 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
3258 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)
;
3259 return rv;
3260 }
3261
3262 nsCOMPtr<nsIHttpChannelInternal> newUpgradeChannel =
3263 do_QueryInterface(newChannel, &rv);
3264
3265 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
3266 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)
;
3267 return rv;
3268 }
3269
3270 // The redirect is likely OK
3271
3272 newChannel->SetNotificationCallbacks(this);
3273
3274 mEncrypted = newuriIsHttps;
3275 rv = NS_MutateURI(newuri)
3276 .SetScheme(mEncrypted ? "wss"_ns : "ws"_ns)
3277 .Finalize(mURI);
3278
3279 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
3280 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)
;
3281 return rv;
3282 }
3283
3284 mHttpChannel = newHttpChannel;
3285 mChannel = newUpgradeChannel;
3286 rv = SetupRequest();
3287 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
3288 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)
;
3289 return rv;
3290 }
3291
3292 // Redirected-to URI may need to be delayed by 1-connecting-per-host and
3293 // delay-after-fail algorithms. So hold off calling OnRedirectVerifyCallback
3294 // until BeginOpen, when we know it's OK to proceed with new channel.
3295 mRedirectCallback = callback;
3296
3297 // Mark old channel as successfully connected so we'll clear any FailDelay
3298 // associated with the old URI. Note: no need to also call OnStopSession:
3299 // it's a no-op for successful, already-connected channels.
3300 nsWSAdmissionManager::OnConnected(this);
3301
3302 // ApplyForAdmission as if we were starting from fresh...
3303 mAddress.Truncate();
3304 mOpenedHttpChannel = false;
3305 rv = ApplyForAdmission();
3306 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
3307 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)
;
3308 mRedirectCallback = nullptr;
3309 return rv;
3310 }
3311
3312 return NS_OK;
3313}
3314
3315// nsITimerCallback
3316
3317NS_IMETHODIMPnsresult
3318WebSocketChannel::Notify(nsITimer* timer) {
3319 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)
;
3320
3321 if (timer == mCloseTimer) {
3322 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"
, 3322); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mClientClosed"
") (" "Close Timeout without local close" ")"); do { MOZ_CrashSequence
(__null, 3322); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
3323 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"
, 3323); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mIOThread->IsOnCurrentThread()"
") (" "not on right thread" ")"); do { MOZ_CrashSequence(__null
, 3323); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
3324
3325 mCloseTimer = nullptr;
3326 if (mStopped || mServerClosed) { /* no longer relevant */
3327 return NS_OK;
3328 }
3329
3330 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)
;
3331 AbortSession(NS_ERROR_NET_TIMEOUT_EXTERNAL);
3332 } else if (timer == mOpenTimer) {
3333 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"
, 3333); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
") (" "not main thread" ")"); do { MOZ_CrashSequence(__null,
3333); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false)
;
3334
3335 mOpenTimer = nullptr;
3336 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)
;
3337 if (mStopped || mServerClosed) { /* no longer relevant */
3338 return NS_OK;
3339 }
3340
3341 AbortSession(NS_ERROR_NET_TIMEOUT_EXTERNAL);
3342 MOZ_PUSH_IGNORE_THREAD_SAFETYGCC diagnostic push GCC diagnostic ignored "-Wthread-safety"
3343 // mReconnectDelayTimer is only modified on MainThread, we can read it
3344 // without a lock, but ONLY if we're on MainThread! And if we're not
3345 // on MainThread, it can't be mReconnectDelayTimer
3346 } else if (NS_IsMainThread() && timer == mReconnectDelayTimer) {
3347 MOZ_POP_THREAD_SAFETYGCC diagnostic pop
3348 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"
, 3349); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mConnecting == CONNECTING_DELAYED"
") (" "woke up from delay w/o being delayed?" ")"); do { MOZ_CrashSequence
(__null, 3349); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
3349 "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"
, 3349); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mConnecting == CONNECTING_DELAYED"
") (" "woke up from delay w/o being delayed?" ")"); do { MOZ_CrashSequence
(__null, 3349); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
3350
3351 {
3352 MutexAutoLock lock(mMutex);
3353 mReconnectDelayTimer = nullptr;
3354 }
3355 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)
;
3356 BeginOpen(false);
3357 } else if (timer == mPingTimer) {
3358 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"
, 3358); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mIOThread->IsOnCurrentThread()"
") (" "not on right thread" ")"); do { MOZ_CrashSequence(__null
, 3358); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
3359
3360 if (mClientClosed || mServerClosed || mRequestedClose) {
3361 // no point in worrying about ping now
3362 mPingTimer = nullptr;
3363 return NS_OK;
3364 }
3365
3366 if (!mPingOutstanding) {
3367 // Ping interval must be non-null or PING was forced by OnNetworkChanged()
3368 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"
, 3368); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mPingInterval || mPingForced"
")"); do { MOZ_CrashSequence(__null, 3368); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3369 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)
;
3370 mPingOutstanding = 1;
3371 mPingForced = false;
3372 mPingTimer->InitWithCallback(this, mPingResponseTimeout,
3373 nsITimer::TYPE_ONE_SHOT);
3374 GeneratePing();
3375 } else {
3376 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)
;
3377 mPingTimer = nullptr;
3378 AbortSession(NS_ERROR_NET_TIMEOUT_EXTERNAL);
3379 }
3380 } else if (timer == mLingeringCloseTimer) {
3381 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)
;
3382 CleanupConnection();
3383 } else {
3384 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"
, 3384); AnnotateMozCrashReason("MOZ_ASSERT" "(" "0" ") (" "Unknown Timer"
")"); do { MOZ_CrashSequence(__null, 3384); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3385 }
3386
3387 return NS_OK;
3388}
3389
3390// nsINamed
3391
3392NS_IMETHODIMPnsresult
3393WebSocketChannel::GetName(nsACString& aName) {
3394 aName.AssignLiteral("WebSocketChannel");
3395 return NS_OK;
3396}
3397
3398// nsIWebSocketChannel
3399
3400NS_IMETHODIMPnsresult
3401WebSocketChannel::GetSecurityInfo(nsITransportSecurityInfo** aSecurityInfo) {
3402 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)
;
3403 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"
, 3403); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
") (" "not main thread" ")"); do { MOZ_CrashSequence(__null,
3403); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false)
;
3404
3405 *aSecurityInfo = nullptr;
3406
3407 if (mTransport) {
3408 nsCOMPtr<nsITLSSocketControl> tlsSocketControl;
3409 nsresult rv =
3410 mTransport->GetTlsSocketControl(getter_AddRefs(tlsSocketControl));
3411 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
3412 return rv;
3413 }
3414 nsCOMPtr<nsITransportSecurityInfo> securityInfo(
3415 do_QueryInterface(tlsSocketControl));
3416 if (securityInfo) {
3417 securityInfo.forget(aSecurityInfo);
3418 }
3419 }
3420 return NS_OK;
3421}
3422
3423NS_IMETHODIMPnsresult
3424WebSocketChannel::AsyncOpen(nsIURI* aURI, const nsACString& aOrigin,
3425 JS::Handle<JS::Value> aOriginAttributes,
3426 uint64_t aInnerWindowID,
3427 nsIWebSocketListener* aListener,
3428 nsISupports* aContext, JSContext* aCx) {
3429 OriginAttributes attrs;
3430 if (!aOriginAttributes.isObject() || !attrs.Init(aCx, aOriginAttributes)) {
3431 return NS_ERROR_INVALID_ARG;
3432 }
3433 return AsyncOpenNative(aURI, aOrigin, attrs, aInnerWindowID, aListener,
3434 aContext);
3435}
3436
3437NS_IMETHODIMPnsresult
3438WebSocketChannel::AsyncOpenNative(nsIURI* aURI, const nsACString& aOrigin,
3439 const OriginAttributes& aOriginAttributes,
3440 uint64_t aInnerWindowID,
3441 nsIWebSocketListener* aListener,
3442 nsISupports* aContext) {
3443 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)
;
3444
3445 aOriginAttributes.CreateSuffix(mOriginSuffix);
3446
3447 if (!NS_IsMainThread()) {
3448 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"
, 3448); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"not main thread" ")"); do { MOZ_CrashSequence(__null, 3448)
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
;
3449 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)
;
3450 return NS_ERROR_UNEXPECTED;
3451 }
3452
3453 if ((!aURI && !mIsServerSide) || !aListener) {
3454 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)
;
3455 return NS_ERROR_UNEXPECTED;
3456 }
3457
3458 {
3459 MutexAutoLock lock(mMutex);
3460 if (mWasOpened || mListenerMT) return NS_ERROR_ALREADY_OPENED;
3461 }
3462
3463 nsresult rv;
3464
3465 // Ensure target thread is set if RetargetDeliveryTo isn't called
3466 {
3467 auto lock = mTargetThread.Lock();
3468 if (!lock.ref()) {
3469 lock.ref() = GetMainThreadSerialEventTarget();
3470 }
3471 }
3472
3473 mIOThread = mozilla::components::SocketTransport::Service(&rv);
3474 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
3475 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"
, 3475)
;
3476 return rv;
3477 }
3478
3479 nsCOMPtr<nsIPrefBranch> prefService;
3480 prefService = mozilla::components::Preferences::Service();
3481
3482 if (prefService) {
3483 int32_t intpref;
3484 rv =
3485 prefService->GetIntPref("network.websocket.max-message-size", &intpref);
3486 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
3487 mMaxMessageSize = std::clamp(intpref, 1024, INT32_MAX(2147483647));
3488 }
3489 rv = prefService->GetIntPref("network.websocket.timeout.close", &intpref);
3490 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
3491 mCloseTimeout = std::clamp(intpref, 1, 1800) * 1000;
3492 }
3493 rv = prefService->GetIntPref("network.websocket.timeout.open", &intpref);
3494 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
3495 mOpenTimeout = std::clamp(intpref, 1, 1800) * 1000;
3496 }
3497 rv = prefService->GetIntPref("network.websocket.timeout.ping.request",
3498 &intpref);
3499 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) && !mClientSetPingInterval) {
3500 mPingInterval = std::clamp(intpref, 0, 86400) * 1000;
3501 }
3502 rv = prefService->GetIntPref("network.websocket.timeout.ping.response",
3503 &intpref);
3504 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) && !mClientSetPingTimeout) {
3505 mPingResponseTimeout = std::clamp(intpref, 1, 3600) * 1000;
3506 }
3507 rv = prefService->GetIntPref("network.websocket.max-connections", &intpref);
3508 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
3509 mMaxConcurrentConnections = std::clamp(intpref, 1, 0xffff);
3510 }
3511 }
3512
3513 int32_t sessionCount = -1;
3514 nsWSAdmissionManager::GetSessionCount(sessionCount);
3515 if (sessionCount >= 0) {
3516 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)
3517 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)
;
3518 }
3519
3520 if (sessionCount >= mMaxConcurrentConnections) {
3521 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)
3522 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)
;
3523
3524 // WebSocket connections are expected to be long lived, so return
3525 // an error here instead of queueing
3526 return NS_ERROR_SOCKET_CREATE_FAILED;
3527 }
3528
3529 mInnerWindowID = aInnerWindowID;
3530 mOriginalURI = aURI;
3531 mURI = mOriginalURI;
3532 mOrigin = aOrigin;
3533
3534 if (mIsServerSide) {
3535 // IncrementSessionCount();
3536 mWasOpened = 1;
3537 {
3538 MutexAutoLock lock(mMutex);
3539 mListenerMT =
3540 MakeRefPtr<ListenerAndContextContainer>(aListener, aContext);
3541 }
3542 rv = mServerTransportProvider->SetListener(this);
3543 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"
, 3543); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))"
")"); do { MOZ_CrashSequence(__null, 3543); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3544 mServerTransportProvider = nullptr;
3545
3546 return NS_OK;
3547 }
3548
3549 mURI->GetHostPort(mHost);
3550
3551 mRandomGenerator = mozilla::components::RandomGenerator::Service(&rv);
3552 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
3553 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"
, 3553)
;
3554 return rv;
3555 }
3556
3557 nsCOMPtr<nsIURI> localURI;
3558 nsCOMPtr<nsIChannel> localChannel;
3559
3560 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)
;
3561
3562 rv = NS_MutateURI(mURI)
3563 .SetScheme(mEncrypted ? "https"_ns : "http"_ns)
3564 .Finalize(localURI);
3565 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"
, 3565); return rv; } } while (false)
;
3566
3567 nsCOMPtr<nsIIOService> ioService;
3568 ioService = mozilla::components::IO::Service(&rv);
3569 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
3570 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"
, 3570)
;
3571 return rv;
3572 }
3573
3574 rv = ioService->NewChannelFromURIWithProxyFlagsAndLoadInfo(
3575 localURI, mURI,
3576 nsIProtocolProxyService::RESOLVE_PREFER_SOCKS_PROXY |
3577 nsIProtocolProxyService::RESOLVE_PREFER_HTTPS_PROXY |
3578 nsIProtocolProxyService::RESOLVE_ALWAYS_TUNNEL,
3579 mLoadInfo, getter_AddRefs(localChannel));
3580 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"
, 3580); return rv; } } while (false)
;
3581
3582 // Pass most GetInterface() requests through to our instantiator, but handle
3583 // nsIChannelEventSink in this object in order to deal with redirects
3584 localChannel->SetNotificationCallbacks(this);
3585
3586 class MOZ_STACK_CLASS CleanUpOnFailure {
3587 public:
3588 explicit CleanUpOnFailure(WebSocketChannel* aWebSocketChannel)
3589 : mWebSocketChannel(aWebSocketChannel) {}
3590
3591 ~CleanUpOnFailure() {
3592 if (!mWebSocketChannel->mWasOpened) {
3593 mWebSocketChannel->mChannel = nullptr;
3594 mWebSocketChannel->mHttpChannel = nullptr;
3595 }
3596 }
3597
3598 WebSocketChannel* mWebSocketChannel;
3599 };
3600
3601 CleanUpOnFailure cuof(this);
3602
3603 mChannel = do_QueryInterface(localChannel, &rv);
3604 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"
, 3604); return rv; } } while (false)
;
3605
3606 mHttpChannel = do_QueryInterface(localChannel, &rv);
3607 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"
, 3607); return rv; } } while (false)
;
3608
3609 rv = SetupRequest();
3610 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) return rv;
3611
3612 mPrivateBrowsing = NS_UsePrivateBrowsing(localChannel);
3613
3614 if (mConnectionLogService && !mPrivateBrowsing) {
3615 mConnectionLogService->AddHost(mHost, mSerial,
3616 BaseWebSocketChannel::mEncrypted);
3617 }
3618
3619 rv = ApplyForAdmission();
3620 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) return rv;
3621
3622 // Register for prefs change notifications
3623 nsCOMPtr<nsIObserverService> observerService =
3624 mozilla::services::GetObserverService();
3625 if (!observerService) {
3626 NS_WARNING("failed to get observer service")NS_DebugBreak(NS_DEBUG_WARNING, "failed to get observer service"
, nullptr, "./../../../../netwerk/protocol/websocket/WebSocketChannel.cpp"
, 3626)
;
3627 return NS_ERROR_FAILURE;
3628 }
3629
3630 rv = observerService->AddObserver(this, NS_NETWORK_LINK_TOPIC"network:link-status-changed", false);
3631 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"
, 3631)
) {
3632 return rv;
3633 }
3634
3635 // Only set these if the open was successful:
3636 //
3637 mWasOpened = 1;
3638 {
3639 MutexAutoLock lock(mMutex);
3640 mListenerMT = MakeRefPtr<ListenerAndContextContainer>(aListener, aContext);
3641 }
3642 IncrementSessionCount();
3643
3644 return rv;
3645}
3646
3647NS_IMETHODIMPnsresult
3648WebSocketChannel::Close(uint16_t code, const nsACString& reason) {
3649 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)
;
3650 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"
, 3650); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
") (" "not main thread" ")"); do { MOZ_CrashSequence(__null,
3650); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false)
;
3651
3652 {
3653 MutexAutoLock lock(mMutex);
3654
3655 if (mRequestedClose) {
3656 return NS_OK;
3657 }
3658
3659 if (mStopped) {
3660 return NS_ERROR_NOT_AVAILABLE;
3661 }
3662
3663 // The API requires the UTF-8 string to be 123 or less bytes
3664 if (reason.Length() > 123) return NS_ERROR_ILLEGAL_VALUE;
3665
3666 mRequestedClose = true;
3667 mScriptCloseReason = reason;
3668 mScriptCloseCode = code;
3669
3670 if (mDataStarted) {
3671 return mIOThread->Dispatch(
3672 new OutboundEnqueuer(this,
3673 new OutboundMessage(kMsgTypeFin, VoidCString())),
3674 nsIEventTarget::DISPATCH_NORMAL);
3675 }
3676
3677 mStopped = true;
3678 }
3679
3680 nsresult rv;
3681 if (code == CLOSE_GOING_AWAY) {
3682 // Not an error: for example, tab has closed or navigated away
3683 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)
;
3684 rv = NS_OK;
3685 } else {
3686 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)
;
3687 rv = NS_ERROR_NOT_CONNECTED;
3688 }
3689
3690 DoStopSession(rv);
3691 return rv;
3692}
3693
3694NS_IMETHODIMPnsresult
3695WebSocketChannel::SendMsg(const nsACString& aMsg) {
3696 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)
;
3697
3698 return SendMsgCommon(aMsg, false, aMsg.Length());
3699}
3700
3701NS_IMETHODIMPnsresult
3702WebSocketChannel::SendBinaryMsg(const nsACString& aMsg) {
3703 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)
;
3704 return SendMsgCommon(aMsg, true, aMsg.Length());
3705}
3706
3707NS_IMETHODIMPnsresult
3708WebSocketChannel::SendBinaryStream(nsIInputStream* aStream, uint32_t aLength) {
3709 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)
;
3710
3711 return SendMsgCommon(VoidCString(), true, aLength, aStream);
3712}
3713
3714nsresult WebSocketChannel::SendMsgCommon(const nsACString& aMsg, bool aIsBinary,
3715 uint32_t aLength,
3716 nsIInputStream* aStream) {
3717 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"
, 3717); AnnotateMozCrashReason("MOZ_ASSERT" "(" "IsOnTargetThread()"
") (" "not target thread" ")"); do { MOZ_CrashSequence(__null
, 3717); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
3718
3719 if (!mDataStarted) {
3720 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)
;
3721 return NS_ERROR_UNEXPECTED;
3722 }
3723
3724 if (mRequestedClose) {
3725 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)
;
3726 return NS_ERROR_UNEXPECTED;
3727 }
3728
3729 if (mStopped) {
3730 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)
;
3731 return NS_ERROR_NOT_CONNECTED;
3732 }
3733
3734 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"
, 3734); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mMaxMessageSize >= 0"
") (" "max message size negative" ")"); do { MOZ_CrashSequence
(__null, 3734); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
3735 if (aLength > static_cast<uint32_t>(mMaxMessageSize)) {
3736 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)
;
3737 return NS_ERROR_FILE_TOO_BIG;
3738 }
3739
3740 if (mConnectionLogService && !mPrivateBrowsing) {
3741 mConnectionLogService->NewMsgSent(mHost, mSerial, aLength);
3742 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)
;
3743 }
3744
3745 return mIOThread->Dispatch(
3746 aStream
3747 ? new OutboundEnqueuer(this, new OutboundMessage(aStream, aLength))
3748 : new OutboundEnqueuer(
3749 this,
3750 new OutboundMessage(
3751 aIsBinary ? kMsgTypeBinaryString : kMsgTypeString, aMsg)),
3752 nsIEventTarget::DISPATCH_NORMAL);
3753}
3754
3755// nsIHttpUpgradeListener
3756
3757NS_IMETHODIMPnsresult
3758WebSocketChannel::OnTransportAvailable(nsISocketTransport* aTransport,
3759 nsIAsyncInputStream* aSocketIn,
3760 nsIAsyncOutputStream* aSocketOut) {
3761 if (!NS_IsMainThread()) {
3762 return NS_DispatchToMainThread(
3763 new CallOnTransportAvailable(this, aTransport, aSocketIn, aSocketOut));
3764 }
3765
3766 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)
3767 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)
;
3768
3769 if (mStopped) {
3770 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)
;
3771 return NS_OK;
3772 }
3773
3774 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"
, 3774); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
") (" "not main thread" ")"); do { MOZ_CrashSequence(__null,
3774); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false)
;
3775 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"
, 3775); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mRecvdHttpUpgradeTransport"
") (" "OTA duplicated" ")"); do { MOZ_CrashSequence(__null, 3775
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
;
3776 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"
, 3776); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aSocketIn" ") ("
"OTA with invalid socketIn" ")"); do { MOZ_CrashSequence(__null
, 3776); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
3777
3778 mTransport = aTransport;
3779 mSocketIn = aSocketIn;
3780 mSocketOut = aSocketOut;
3781
3782 nsresult rv;
3783 rv = mTransport->SetEventSink(nullptr, nullptr);
3784 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"
, 3784)
) return rv;
3785 rv = mTransport->SetSecurityCallbacks(this);
3786 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"
, 3786)
) return rv;
3787
3788 mRecvdHttpUpgradeTransport = 1;
3789 if (mGotUpgradeOK) {
3790 // We're now done CONNECTING, which means we can now open another,
3791 // perhaps parallel, connection to the same host if one
3792 // is pending
3793 nsWSAdmissionManager::OnConnected(this);
3794
3795 return CallStartWebsocketData();
3796 }
3797
3798 if (mIsServerSide) {
3799 if (!mNegotiatedExtensions.IsEmpty()) {
3800 bool clientNoContextTakeover;
3801 bool serverNoContextTakeover;
3802 int32_t clientMaxWindowBits;
3803 int32_t serverMaxWindowBits;
3804
3805 rv = ParseWebSocketExtension(
3806 mNegotiatedExtensions, eParseServerSide, clientNoContextTakeover,
3807 serverNoContextTakeover, clientMaxWindowBits, serverMaxWindowBits);
3808 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"
, 3808); AnnotateMozCrashReason("MOZ_RELEASE_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))"
") (" "illegal value provided by server" ")"); do { MOZ_CrashSequence
(__null, 3808); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
3809
3810 if (clientMaxWindowBits == -1) {
3811 clientMaxWindowBits = 15;
3812 }
3813 if (serverMaxWindowBits == -1) {
3814 serverMaxWindowBits = 15;
3815 }
3816
3817 MutexAutoLock lock(mCompressorMutex);
3818 mPMCECompressor = std::make_unique<PMCECompression>(
3819 serverNoContextTakeover, serverMaxWindowBits, clientMaxWindowBits);
3820 if (mPMCECompressor->Active()) {
3821 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)
3822 ("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)
3823 "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)
3824 "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)
3825 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)
3826 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)
;
3827
3828 mNegotiatedExtensions = "permessage-deflate";
3829 } else {
3830 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)
3831 ("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)
3832 "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)
;
3833 mPMCECompressor = nullptr;
3834 AbortSession(NS_ERROR_UNEXPECTED);
3835 return NS_ERROR_UNEXPECTED;
3836 }
3837 }
3838
3839 return CallStartWebsocketData();
3840 }
3841
3842 return NS_OK;
3843}
3844
3845NS_IMETHODIMPnsresult
3846WebSocketChannel::OnUpgradeFailed(nsresult aErrorCode) {
3847 if (!NS_IsMainThread()) {
3848 return NS_DispatchToMainThread(NewRunnableMethod<nsresult>(
3849 "net::WebSocketChannel::OnUpgradeFailed", this,
3850 &WebSocketChannel::OnUpgradeFailed, aErrorCode));
3851 }
3852
3853 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)
3854 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)
;
3855
3856 if (mStopped) {
3857 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)
;
3858 return NS_OK;
3859 }
3860
3861 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"
, 3861); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mRecvdHttpUpgradeTransport"
") (" "OTA already called" ")"); do { MOZ_CrashSequence(__null
, 3861); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
3862
3863 AbortSession(aErrorCode);
3864 return NS_OK;
3865}
3866
3867// nsIRequestObserver (from nsIStreamListener)
3868
3869NS_IMETHODIMPnsresult
3870WebSocketChannel::OnStartRequest(nsIRequest* aRequest) {
3871 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)
3872 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)
;
3873 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"
, 3873); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
") (" "not main thread" ")"); do { MOZ_CrashSequence(__null,
3873); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false)
;
3874 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"
, 3874); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mGotUpgradeOK"
") (" "OTA duplicated" ")"); do { MOZ_CrashSequence(__null, 3874
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
;
3875
3876 if (mStopped) {
3877 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)
;
3878 AbortSession(NS_ERROR_WEBSOCKET_CONNECTION_REFUSED);
3879 return NS_ERROR_WEBSOCKET_CONNECTION_REFUSED;
3880 }
3881
3882 nsresult rv;
3883 uint32_t status;
3884 char *val, *token;
3885
3886 rv = mHttpChannel->GetResponseStatus(&status);
3887 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
3888 nsresult httpStatus;
3889 rv = NS_ERROR_WEBSOCKET_CONNECTION_REFUSED;
3890
3891 // If we failed to connect due to unsuccessful TLS handshake, we must
3892 // propagate a specific error to mozilla::dom::WebSocketImpl so it can set
3893 // status code to 1015. Otherwise return
3894 // NS_ERROR_WEBSOCKET_CONNECTION_REFUSED.
3895 if (NS_SUCCEEDED(mHttpChannel->GetStatus(&httpStatus))((bool)(__builtin_expect(!!(!NS_FAILED_impl(mHttpChannel->
GetStatus(&httpStatus))), 1)))
) {
3896 uint32_t errorClass;
3897 nsCOMPtr<nsINSSErrorsService> errSvc;
3898 errSvc = mozilla::components::NSSErrors::Service();
3899 // If GetErrorClass succeeds httpStatus is TLS related failure.
3900 if (errSvc &&
3901 NS_SUCCEEDED(errSvc->GetErrorClass(httpStatus, &errorClass))((bool)(__builtin_expect(!!(!NS_FAILED_impl(errSvc->GetErrorClass
(httpStatus, &errorClass))), 1)))
) {
3902 rv = NS_ERROR_NET_INADEQUATE_SECURITY;
3903 }
3904 }
3905
3906 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)
;
3907 AbortSession(rv);
3908 return rv;
3909 }
3910
3911 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)
;
3912 nsCOMPtr<nsIHttpChannelInternal> internalChannel =
3913 do_QueryInterface(mHttpChannel);
3914 uint32_t versionMajor, versionMinor;
3915 rv = internalChannel->GetResponseVersion(&versionMajor, &versionMinor);
3916 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) ||
3917 !((versionMajor == 1 && versionMinor != 0) || versionMajor == 2) ||
3918 (versionMajor == 1 && status != 101) ||
3919 (versionMajor == 2 && status != 200)) {
3920 AbortSession(NS_ERROR_WEBSOCKET_CONNECTION_REFUSED);
3921 return NS_ERROR_WEBSOCKET_CONNECTION_REFUSED;
3922 }
3923
3924 if (versionMajor == 1) {
3925 // These are only present on http/1.x websocket upgrades
3926 nsAutoCString respUpgrade;
3927 rv = mHttpChannel->GetResponseHeader("Upgrade"_ns, respUpgrade);
3928
3929 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
3930 rv = NS_ERROR_ILLEGAL_VALUE;
3931 if (!respUpgrade.IsEmpty()) {
3932 val = respUpgrade.BeginWriting();
3933 while ((token = nsCRT::strtok(val, ", \t", &val))) {
3934 if (nsCRT::strcasecmp(token, "Websocket") == 0) {
3935 rv = NS_OK;
3936 break;
3937 }
3938 }
3939 }
3940 }
3941
3942 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
3943 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)
3944 ("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)
3945 "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)
;
3946 AbortSession(NS_ERROR_ILLEGAL_VALUE);
3947 return rv;
3948 }
3949
3950 nsAutoCString respConnection;
3951 rv = mHttpChannel->GetResponseHeader("Connection"_ns, respConnection);
3952
3953 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
3954 rv = NS_ERROR_ILLEGAL_VALUE;
3955 if (!respConnection.IsEmpty()) {
3956 val = respConnection.BeginWriting();
3957 while ((token = nsCRT::strtok(val, ", \t", &val))) {
3958 if (nsCRT::strcasecmp(token, "Upgrade") == 0) {
3959 rv = NS_OK;
3960 break;
3961 }
3962 }
3963 }
3964 }
3965
3966 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
3967 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)
3968 ("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)
3969 "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)
;
3970 AbortSession(NS_ERROR_ILLEGAL_VALUE);
3971 return rv;
3972 }
3973
3974 nsAutoCString respAccept;
3975 rv = mHttpChannel->GetResponseHeader("Sec-WebSocket-Accept"_ns, respAccept);
3976
3977 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) || respAccept.IsEmpty() ||
3978 !respAccept.Equals(mHashedSecret)) {
3979 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)
3980 ("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)
3981 "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)
;
3982 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)
3983 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)
;
3984#ifdef FUZZING
3985 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) || respAccept.IsEmpty()) {
3986#endif
3987 AbortSession(NS_ERROR_ILLEGAL_VALUE);
3988 return NS_ERROR_ILLEGAL_VALUE;
3989#ifdef FUZZING
3990 }
3991#endif
3992 }
3993 }
3994
3995 // If we sent a sub protocol header, verify the response matches.
3996 // If response contains protocol that was not in request, fail.
3997 // If response contained no protocol header, set to "" so the protocol
3998 // attribute of the WebSocket JS object reflects that
3999 if (!mProtocol.IsEmpty()) {
4000 nsAutoCString respProtocol;
4001 rv = mHttpChannel->GetResponseHeader("Sec-WebSocket-Protocol"_ns,
4002 respProtocol);
4003 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
4004 rv = NS_ERROR_ILLEGAL_VALUE;
4005 val = mProtocol.BeginWriting();
4006 while ((token = nsCRT::strtok(val, ", \t", &val))) {
4007 if (strcmp(token, respProtocol.get()) == 0) {
4008 rv = NS_OK;
4009 break;
4010 }
4011 }
4012
4013 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
4014 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)
4015 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)
;
4016 mProtocol = std::move(respProtocol);
4017 } else {
4018 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)
4019 ("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)
4020 "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)
4021 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)
;
4022 mProtocol.Truncate();
4023 AbortSession(NS_ERROR_ILLEGAL_VALUE);
4024 return NS_ERROR_ILLEGAL_VALUE;
4025 }
4026 } else {
4027 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)
4028 ("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)
4029 "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)
4030 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)
;
4031 mProtocol.Truncate();
4032 }
4033 }
4034
4035 rv = HandleExtensions();
4036 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) return rv;
4037
4038 // Update mEffectiveURL for off main thread URI access.
4039 nsCOMPtr<nsIURI> uri = mURI ? mURI : mOriginalURI;
4040 nsAutoCString spec;
4041 rv = uri->GetSpec(spec);
4042 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"
, 4042); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))"
")"); do { MOZ_CrashSequence(__null, 4042); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
4043 CopyUTF8toUTF16(spec, mEffectiveURL);
4044
4045 mGotUpgradeOK = 1;
4046 if (mRecvdHttpUpgradeTransport) {
4047 // We're now done CONNECTING, which means we can now open another,
4048 // perhaps parallel, connection to the same host if one
4049 // is pending
4050 nsWSAdmissionManager::OnConnected(this);
4051
4052 return CallStartWebsocketData();
4053 }
4054
4055 return NS_OK;
4056}
4057
4058NS_IMETHODIMPnsresult
4059WebSocketChannel::OnStopRequest(nsIRequest* aRequest, nsresult aStatusCode) {
4060 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)
4061 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)
;
4062 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"
, 4062); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
") (" "not main thread" ")"); do { MOZ_CrashSequence(__null,
4062); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false)
;
4063
4064 // OnTransportAvailable won't be called if the request is stopped with
4065 // an error. Abort the session now instead of waiting for timeout.
4066 if (NS_FAILED(aStatusCode)((bool)(__builtin_expect(!!(NS_FAILED_impl(aStatusCode)), 0))
)
&& !mRecvdHttpUpgradeTransport) {
4067 AbortSession(aStatusCode);
4068 }
4069
4070 ReportConnectionTelemetry(aStatusCode);
4071
4072 // This is the end of the HTTP upgrade transaction, the
4073 // upgraded streams live on
4074
4075 mChannel = nullptr;
4076 mHttpChannel = nullptr;
4077 mLoadGroup = nullptr;
4078 mCallbacks = nullptr;
4079
4080 return NS_OK;
4081}
4082
4083// nsIInputStreamCallback
4084
4085NS_IMETHODIMPnsresult
4086WebSocketChannel::OnInputStreamReady(nsIAsyncInputStream* aStream) {
4087 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)
;
4088 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"
, 4088); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "mIOThread->IsOnCurrentThread()"
") (" "not on right thread" ")"); do { MOZ_CrashSequence(__null
, 4088); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
4089
4090 if (!mSocketIn) { // did we we clean up the socket after scheduling
4091 // InputReady?
4092 return NS_OK;
4093 }
4094
4095 // this is after the http upgrade - so we are speaking websockets
4096 char buffer[2048];
4097 uint32_t count;
4098 nsresult rv;
4099
4100 do {
4101 rv = mSocketIn->Read((char*)buffer, sizeof(buffer), &count);
4102 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)
4103 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)
;
4104
4105 if (rv == NS_BASE_STREAM_WOULD_BLOCK) {
4106 mSocketIn->AsyncWait(this, 0, 0, mIOThread);
4107 return NS_OK;
4108 }
4109
4110 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
4111 AbortSession(rv);
4112 return rv;
4113 }
4114
4115 if (count == 0) {
4116 AbortSession(NS_BASE_STREAM_CLOSED);
4117 return NS_OK;
4118 }
4119
4120 if (mStopped) {
4121 continue;
4122 }
4123
4124 rv = ProcessInput((uint8_t*)buffer, count);
4125 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
4126 AbortSession(rv);
4127 return rv;
4128 }
4129 } while (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) && mSocketIn);
4130
4131 return NS_OK;
4132}
4133
4134// nsIOutputStreamCallback
4135
4136NS_IMETHODIMPnsresult
4137WebSocketChannel::OnOutputStreamReady(nsIAsyncOutputStream* aStream) {
4138 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)
;
4139 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"
, 4139); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "mIOThread->IsOnCurrentThread()"
") (" "not on right thread" ")"); do { MOZ_CrashSequence(__null
, 4139); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
4140 nsresult rv;
4141
4142 if (!mCurrentOut) PrimeNewOutgoingMessage();
4143
4144 while (mCurrentOut && mSocketOut) {
4145 const char* sndBuf;
4146 uint32_t toSend;
4147 uint32_t amtSent;
4148
4149 if (mHdrOut) {
4150 sndBuf = (const char*)mHdrOut;
4151 toSend = mHdrOutToSend;
4152 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)
4153 ("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)
4154 "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)
4155 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)
;
4156 } else {
4157 sndBuf = (char*)mCurrentOut->BeginReading() + mCurrentOutSent;
4158 toSend = mCurrentOut->Length() - mCurrentOutSent;
4159 if (toSend > 0) {
4160 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)
4161 ("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)
4162 "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)
4163 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)
;
4164 }
4165 }
4166
4167 if (toSend == 0) {
4168 amtSent = 0;
4169 } else {
4170 rv = mSocketOut->Write(sndBuf, toSend, &amtSent);
4171 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)
4172 "\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)
4173 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)
;
4174
4175 if (rv == NS_BASE_STREAM_WOULD_BLOCK) {
4176 mSocketOut->AsyncWait(this, 0, 0, mIOThread);
4177 return NS_OK;
4178 }
4179
4180 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
4181 AbortSession(rv);
4182 return NS_OK;
4183 }
4184 }
4185
4186 if (mHdrOut) {
4187 if (amtSent == toSend) {
4188 mHdrOut = nullptr;
4189 mHdrOutToSend = 0;
4190 } else {
4191 mHdrOut += amtSent;
4192 mHdrOutToSend -= amtSent;
4193 mSocketOut->AsyncWait(this, 0, 0, mIOThread);
4194 }
4195 } else {
4196 if (amtSent == toSend) {
4197 if (RefPtr<BaseWebSocketChannel::ListenerAndContextContainer> listener =
4198 GetListenerMT()) {
4199 if (nsCOMPtr<nsIEventTarget> target = GetTargetThread()) {
4200 target->Dispatch(new CallAcknowledge(this, std::move(listener),
4201 mCurrentOut->OrigLength()),
4202 NS_DISPATCH_NORMALnsIEventTarget::DISPATCH_NORMAL);
4203 } else {
4204 return NS_ERROR_UNEXPECTED;
4205 }
4206 }
4207 DeleteCurrentOutGoingMessage();
4208 PrimeNewOutgoingMessage();
4209 } else {
4210 mCurrentOutSent += amtSent;
4211 mSocketOut->AsyncWait(this, 0, 0, mIOThread);
4212 }
4213 }
4214 }
4215
4216 if (mReleaseOnTransmit) ReleaseSession();
4217 return NS_OK;
4218}
4219
4220// nsIStreamListener
4221
4222NS_IMETHODIMPnsresult
4223WebSocketChannel::OnDataAvailable(nsIRequest* aRequest,
4224 nsIInputStream* aInputStream,
4225 uint64_t aOffset, uint32_t aCount) {
4226 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)
4227 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)
;
4228
4229 // This is the HTTP OnDataAvailable Method, which means this is http data in
4230 // response to the upgrade request and there should be no http response body
4231 // if the upgrade succeeded. This generally should be caught by a non 101
4232 // response code in OnStartRequest().. so we can ignore the data here
4233
4234 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)
4235 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)
;
4236
4237 return NS_OK;
4238}
4239
4240} // namespace mozilla::net
4241
4242#undef CLOSE_GOING_AWAY