Bug Summary

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