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 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/bin/../lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13 -internal-isystem /usr/bin/../lib/gcc/x86_64-linux-gnu/13/../../../../include/x86_64-linux-gnu/c++/13 -internal-isystem /usr/bin/../lib/gcc/x86_64-linux-gnu/13/../../../../include/c++/13/backward -internal-isystem /usr/lib/llvm-18/lib/clang/18/include -internal-isystem /usr/local/include -internal-isystem /usr/bin/../lib/gcc/x86_64-linux-gnu/13/../../../../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-05-16-034744-15991-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/EndianUtils.h"
18#include "mozilla/MathAlgorithms.h"
19#include "mozilla/ScopeExit.h"
20#include "mozilla/StaticMutex.h"
21#include "mozilla/StaticPrefs_privacy.h"
22#include "mozilla/Telemetry.h"
23#include "mozilla/TimeStamp.h"
24#include "mozilla/Utf8.h"
25#include "mozilla/net/WebSocketEventService.h"
26#include "nsAlgorithm.h"
27#include "nsCRT.h"
28#include "nsCharSeparatedTokenizer.h"
29#include "nsComponentManagerUtils.h"
30#include "nsError.h"
31#include "nsIAsyncVerifyRedirectCallback.h"
32#include "nsICancelable.h"
33#include "nsIChannel.h"
34#include "nsIClassOfService.h"
35#include "nsICryptoHash.h"
36#include "nsIDNSRecord.h"
37#include "nsIDNSService.h"
38#include "nsIDashboardEventNotifier.h"
39#include "nsIEventTarget.h"
40#include "nsIHttpChannel.h"
41#include "nsIIOService.h"
42#include "nsINSSErrorsService.h"
43#include "nsINetworkLinkService.h"
44#include "nsINode.h"
45#include "nsIObserverService.h"
46#include "nsIPrefBranch.h"
47#include "nsIProtocolHandler.h"
48#include "nsIProtocolProxyService.h"
49#include "nsIProxiedChannel.h"
50#include "nsIProxyInfo.h"
51#include "nsIRandomGenerator.h"
52#include "nsIRunnable.h"
53#include "nsISocketTransport.h"
54#include "nsITLSSocketControl.h"
55#include "nsITransportProvider.h"
56#include "nsITransportSecurityInfo.h"
57#include "nsIURI.h"
58#include "nsIURIMutator.h"
59#include "nsNetCID.h"
60#include "nsNetUtil.h"
61#include "nsProxyRelease.h"
62#include "nsServiceManagerUtils.h"
63#include "nsSocketTransportService2.h"
64#include "nsStringStream.h"
65#include "nsThreadUtils.h"
66#include "plbase64.h"
67#include "prmem.h"
68#include "prnetdb.h"
69#include "zlib.h"
70
71// rather than slurp up all of nsIWebSocket.idl, which lives outside necko, just
72// dupe one constant we need from it
73#define CLOSE_GOING_AWAY 1001
74
75using namespace mozilla;
76using namespace mozilla::net;
77
78namespace mozilla::net {
79
80NS_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"
, 85); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { *((volatile int*)__null) =
85; __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"
, 85); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"WebSocketChannel\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 85; __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"
, 85); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { *((volatile int*)__null) = 85
; __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"
, 85); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"WebSocketChannel\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 85; __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"
, 85); 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; }
81 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"
, 85); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { *((volatile int*)__null) =
85; __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"
, 85); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"WebSocketChannel\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 85; __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"
, 85); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { *((volatile int*)__null) = 85
; __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"
, 85); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"WebSocketChannel\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 85; __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"
, 85); 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 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"
, 85); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { *((volatile int*)__null) =
85; __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"
, 85); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"WebSocketChannel\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 85; __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"
, 85); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { *((volatile int*)__null) = 85
; __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"
, 85); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"WebSocketChannel\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 85; __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"
, 85); 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 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"
, 85); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { *((volatile int*)__null) =
85; __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"
, 85); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"WebSocketChannel\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 85; __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"
, 85); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { *((volatile int*)__null) = 85
; __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"
, 85); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"WebSocketChannel\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 85; __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"
, 85); 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 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"
, 85); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { *((volatile int*)__null) =
85; __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"
, 85); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"WebSocketChannel\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 85; __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"
, 85); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { *((volatile int*)__null) = 85
; __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"
, 85); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"WebSocketChannel\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 85; __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"
, 85); 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 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"
, 85); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { *((volatile int*)__null) =
85; __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"
, 85); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"WebSocketChannel\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 85; __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"
, 85); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { *((volatile int*)__null) = 85
; __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"
, 85); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"WebSocketChannel\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 85; __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"
, 85); 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
87// We implement RFC 6455, which uses Sec-WebSocket-Version: 13 on the wire.
88#define SEC_WEBSOCKET_VERSION"13" "13"
89
90/*
91 * About SSL unsigned certificates
92 *
93 * wss will not work to a host using an unsigned certificate unless there
94 * is already an exception (i.e. it cannot popup a dialog asking for
95 * a security exception). This is similar to how an inlined img will
96 * fail without a dialog if fails for the same reason. This should not
97 * be a problem in practice as it is expected the websocket javascript
98 * is served from the same host as the websocket server (or of course,
99 * a valid cert could just be provided).
100 *
101 */
102
103// some helper classes
104
105//-----------------------------------------------------------------------------
106// FailDelayManager
107//
108// Stores entries (searchable by {host, port}) of connections that have recently
109// failed, so we can do delay of reconnects per RFC 6455 Section 7.2.3
110//-----------------------------------------------------------------------------
111
112// Initial reconnect delay is randomly chosen between 200-400 ms.
113// This is a gentler backoff than the 0-5 seconds the spec offhandedly suggests.
114const uint32_t kWSReconnectInitialBaseDelay = 200;
115const uint32_t kWSReconnectInitialRandomDelay = 200;
116
117// Base lifetime (in ms) of a FailDelay: kept longer if more failures occur
118const uint32_t kWSReconnectBaseLifeTime = 60 * 1000;
119// Maximum reconnect delay (in ms)
120const uint32_t kWSReconnectMaxDelay = 60 * 1000;
121
122// hold record of failed connections, and calculates needed delay for reconnects
123// to same host/path/port.
124class FailDelay {
125 public:
126 FailDelay(nsCString address, nsCString path, int32_t port)
127 : mAddress(std::move(address)), mPath(std::move(path)), mPort(port) {
128 mLastFailure = TimeStamp::Now();
129 mNextDelay = kWSReconnectInitialBaseDelay +
130 (rand() % kWSReconnectInitialRandomDelay);
131 }
132
133 // Called to update settings when connection fails again.
134 void FailedAgain() {
135 mLastFailure = TimeStamp::Now();
136 // We use a truncated exponential backoff as suggested by RFC 6455,
137 // but multiply by 1.5 instead of 2 to be more gradual.
138 mNextDelay = static_cast<uint32_t>(
139 std::min<double>(kWSReconnectMaxDelay, mNextDelay * 1.5));
140 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocket: FailedAgain: host=%s, path=%s, port=%d: incremented delay "
"to " "%" "u", mAddress.get(), mPath.get(), mPort, mNextDelay
); } } while (0)
141 ("WebSocket: FailedAgain: host=%s, path=%s, port=%d: incremented delay "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocket: FailedAgain: host=%s, path=%s, port=%d: incremented delay "
"to " "%" "u", mAddress.get(), mPath.get(), mPort, mNextDelay
); } } while (0)
142 "to "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocket: FailedAgain: host=%s, path=%s, port=%d: incremented delay "
"to " "%" "u", mAddress.get(), mPath.get(), mPort, mNextDelay
); } } while (0)
143 "%" PRIu32,do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocket: FailedAgain: host=%s, path=%s, port=%d: incremented delay "
"to " "%" "u", mAddress.get(), mPath.get(), mPort, mNextDelay
); } } while (0)
144 mAddress.get(), mPath.get(), mPort, mNextDelay))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocket: FailedAgain: host=%s, path=%s, port=%d: incremented delay "
"to " "%" "u", mAddress.get(), mPath.get(), mPort, mNextDelay
); } } while (0)
;
145 }
146
147 // returns 0 if there is no need to delay (i.e. delay interval is over)
148 uint32_t RemainingDelay(TimeStamp rightNow) {
149 TimeDuration dur = rightNow - mLastFailure;
150 uint32_t sinceFail = (uint32_t)dur.ToMilliseconds();
151 if (sinceFail > mNextDelay) return 0;
152
153 return mNextDelay - sinceFail;
154 }
155
156 bool IsExpired(TimeStamp rightNow) {
157 return (mLastFailure + TimeDuration::FromMilliseconds(
158 kWSReconnectBaseLifeTime + mNextDelay)) <=
159 rightNow;
160 }
161
162 nsCString mAddress; // IP address (or hostname if using proxy)
163 nsCString mPath;
164 int32_t mPort;
165
166 private:
167 TimeStamp mLastFailure; // Time of last failed attempt
168 // mLastFailure + mNextDelay is the soonest we'll allow a reconnect
169 uint32_t mNextDelay; // milliseconds
170};
171
172class FailDelayManager {
173 public:
174 FailDelayManager() {
175 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)
;
176
177 mDelaysDisabled = false;
178
179 nsCOMPtr<nsIPrefBranch> prefService =
180 do_GetService(NS_PREFSERVICE_CONTRACTID"@mozilla.org/preferences-service;1");
181 if (!prefService) {
182 return;
183 }
184 bool boolpref = true;
185 nsresult rv;
186 rv = prefService->GetBoolPref("network.websocket.delay-failed-reconnects",
187 &boolpref);
188 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) && !boolpref) {
189 mDelaysDisabled = true;
190 }
191 }
192
193 ~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)
; }
194
195 void Add(nsCString& address, nsCString& path, int32_t port) {
196 if (mDelaysDisabled) return;
197
198 UniquePtr<FailDelay> record(new FailDelay(address, path, port));
199 mEntries.AppendElement(std::move(record));
200 }
201
202 // Element returned may not be valid after next main thread event: don't keep
203 // pointer to it around
204 FailDelay* Lookup(nsCString& address, nsCString& path, int32_t port,
205 uint32_t* outIndex = nullptr) {
206 if (mDelaysDisabled) return nullptr;
207
208 FailDelay* result = nullptr;
209 TimeStamp rightNow = TimeStamp::Now();
210
211 // We also remove expired entries during search: iterate from end to make
212 // indexing simpler
213 for (int32_t i = mEntries.Length() - 1; i >= 0; --i) {
214 FailDelay* fail = mEntries[i].get();
215 if (fail->mAddress.Equals(address) && fail->mPath.Equals(path) &&
216 fail->mPort == port) {
217 if (outIndex) *outIndex = i;
218 result = fail;
219 // break here: removing more entries would mess up *outIndex.
220 // Any remaining expired entries will be deleted next time Lookup
221 // finds nothing, which is the most common case anyway.
222 break;
223 }
224 if (fail->IsExpired(rightNow)) {
225 mEntries.RemoveElementAt(i);
226 }
227 }
228 return result;
229 }
230
231 // returns true if channel connects immediately, or false if it's delayed
232 void DelayOrBegin(WebSocketChannel* ws) {
233 if (!mDelaysDisabled) {
234 uint32_t failIndex = 0;
235 FailDelay* fail = Lookup(ws->mAddress, ws->mPath, ws->mPort, &failIndex);
236
237 if (fail) {
238 TimeStamp rightNow = TimeStamp::Now();
239
240 uint32_t remainingDelay = fail->RemainingDelay(rightNow);
241 if (remainingDelay) {
242 // reconnecting within delay interval: delay by remaining time
243 nsresult rv;
244 MutexAutoLock lock(ws->mMutex);
245 rv = NS_NewTimerWithCallback(getter_AddRefs(ws->mReconnectDelayTimer),
246 ws, remainingDelay,
247 nsITimer::TYPE_ONE_SHOT);
248 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
249 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)
250 ("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)
251 " 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)
252 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)
;
253 ws->mConnecting = CONNECTING_DELAYED;
254 return;
255 }
256 // if timer fails (which is very unlikely), drop down to BeginOpen
257 // call
258 } else if (fail->IsExpired(rightNow)) {
259 mEntries.RemoveElementAt(failIndex);
260 }
261 }
262 }
263
264 // Delays disabled, or no previous failure, or we're reconnecting after
265 // scheduled delay interval has passed: connect.
266 ws->BeginOpen(true);
267 }
268
269 // Remove() also deletes all expired entries as it iterates: better for
270 // battery life than using a periodic timer.
271 void Remove(nsCString& address, nsCString& path, int32_t port) {
272 TimeStamp rightNow = TimeStamp::Now();
273
274 // iterate from end, to make deletion indexing easier
275 for (int32_t i = mEntries.Length() - 1; i >= 0; --i) {
276 FailDelay* entry = mEntries[i].get();
277 if ((entry->mAddress.Equals(address) && entry->mPath.Equals(path) &&
278 entry->mPort == port) ||
279 entry->IsExpired(rightNow)) {
280 mEntries.RemoveElementAt(i);
281 }
282 }
283 }
284
285 private:
286 nsTArray<UniquePtr<FailDelay>> mEntries;
287 bool mDelaysDisabled;
288};
289
290//-----------------------------------------------------------------------------
291// nsWSAdmissionManager
292//
293// 1) Ensures that only one websocket at a time is CONNECTING to a given IP
294// address (or hostname, if using proxy), per RFC 6455 Section 4.1.
295// 2) Delays reconnects to IP/host after connection failure, per Section 7.2.3
296//-----------------------------------------------------------------------------
297
298class nsWSAdmissionManager {
299 public:
300 static void Init() {
301 StaticMutexAutoLock lock(sLock);
302 if (!sManager) {
303 sManager = new nsWSAdmissionManager();
304 }
305 }
306
307 static void Shutdown() {
308 StaticMutexAutoLock lock(sLock);
309 delete sManager;
310 sManager = nullptr;
311 }
312
313 // Determine if we will open connection immediately (returns true), or
314 // delay/queue the connection (returns false)
315 static void ConditionallyConnect(WebSocketChannel* ws) {
316 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)
;
317 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"
, 317); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
") (" "not main thread" ")"); do { *((volatile int*)__null) =
317; __attribute__((nomerge)) ::abort(); } while (false); } }
while (false)
;
318 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"
, 318); AnnotateMozCrashReason("MOZ_ASSERT" "(" "ws->mConnecting == NOT_CONNECTING"
") (" "opening state" ")"); do { *((volatile int*)__null) = 318
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
;
319
320 StaticMutexAutoLock lock(sLock);
321 if (!sManager) {
322 return;
323 }
324
325 // If there is already another WS channel connecting to this IP address,
326 // defer BeginOpen and mark as waiting in queue.
327 bool hostFound = (sManager->IndexOf(ws->mAddress, ws->mOriginSuffix) >= 0);
328
329 uint32_t failIndex = 0;
330 FailDelay* fail = sManager->mFailures.Lookup(ws->mAddress, ws->mPath,
331 ws->mPort, &failIndex);
332 bool existingFail = fail != nullptr;
333
334 // Always add ourselves to queue, even if we'll connect immediately
335 UniquePtr<nsOpenConn> newdata(
336 new nsOpenConn(ws->mAddress, ws->mOriginSuffix, existingFail, ws));
337
338 // If a connection has not previously failed then prioritize it over
339 // connections that have
340 if (existingFail) {
341 sManager->mQueue.AppendElement(std::move(newdata));
342 } else {
343 uint32_t insertionIndex = sManager->IndexOfFirstFailure();
344 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"
, 345); AnnotateMozCrashReason("MOZ_ASSERT" "(" "insertionIndex <= sManager->mQueue.Length()"
") (" "Insertion index outside bounds" ")"); do { *((volatile
int*)__null) = 345; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
345 "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"
, 345); AnnotateMozCrashReason("MOZ_ASSERT" "(" "insertionIndex <= sManager->mQueue.Length()"
") (" "Insertion index outside bounds" ")"); do { *((volatile
int*)__null) = 345; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
346 sManager->mQueue.InsertElementAt(insertionIndex, std::move(newdata));
347 }
348
349 if (hostFound) {
350 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)
351 ("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)
352 "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)
;
353 ws->mConnecting = CONNECTING_QUEUED;
354 } else {
355 sManager->mFailures.DelayOrBegin(ws);
356 }
357 }
358
359 static void OnConnected(WebSocketChannel* aChannel) {
360 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)
;
361
362 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"
, 362); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
") (" "not main thread" ")"); do { *((volatile int*)__null) =
362; __attribute__((nomerge)) ::abort(); } while (false); } }
while (false)
;
363 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"
, 364); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChannel->mConnecting == CONNECTING_IN_PROGRESS"
") (" "Channel completed connect, but not connecting?" ")");
do { *((volatile int*)__null) = 364; __attribute__((nomerge)
) ::abort(); } while (false); } } while (false)
364 "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"
, 364); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aChannel->mConnecting == CONNECTING_IN_PROGRESS"
") (" "Channel completed connect, but not connecting?" ")");
do { *((volatile int*)__null) = 364; __attribute__((nomerge)
) ::abort(); } while (false); } } while (false)
;
365
366 StaticMutexAutoLock lock(sLock);
367 if (!sManager) {
368 return;
369 }
370
371 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)
;
372 aChannel->mConnecting = NOT_CONNECTING;
373
374 // Remove from queue
375 sManager->RemoveFromQueue(aChannel);
376
377 // Connection succeeded, so stop keeping track of any previous failures
378 sManager->mFailures.Remove(aChannel->mAddress, aChannel->mPath,
379 aChannel->mPort);
380
381 // Check for queued connections to same host.
382 // Note: still need to check for failures, since next websocket with same
383 // host may have different port
384 sManager->ConnectNext(aChannel->mAddress, aChannel->mOriginSuffix);
385 }
386
387 // Called every time a websocket channel ends its session (including going
388 // away w/o ever successfully creating a connection)
389 static void OnStopSession(WebSocketChannel* aChannel, nsresult aReason) {
390 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)
391 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)
;
392
393 StaticMutexAutoLock lock(sLock);
394 if (!sManager) {
395 return;
396 }
397
398 if (NS_FAILED(aReason)((bool)(__builtin_expect(!!(NS_FAILED_impl(aReason)), 0)))) {
399 // Have we seen this failure before?
400 FailDelay* knownFailure = sManager->mFailures.Lookup(
401 aChannel->mAddress, aChannel->mPath, aChannel->mPort);
402 if (knownFailure) {
403 if (aReason == NS_ERROR_NOT_CONNECTED) {
404 // Don't count close() before connection as a network error
405 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)
406 ("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)
407 " [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)
408 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)
409 (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)
;
410 } else {
411 // repeated failure to connect: increase delay for next connection
412 knownFailure->FailedAgain();
413 }
414 } else {
415 // new connection failure: record it.
416 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)
417 aChannel->mAddress.get(), aChannel->mPath.get(),do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocket: connection to %s, %s, %d failed: [this=%p]"
, aChannel->mAddress.get(), aChannel->mPath.get(), (int
)aChannel->mPort, aChannel); } } while (0)
418 (int)aChannel->mPort, aChannel))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocket: connection to %s, %s, %d failed: [this=%p]"
, aChannel->mAddress.get(), aChannel->mPath.get(), (int
)aChannel->mPort, aChannel); } } while (0)
;
419 sManager->mFailures.Add(aChannel->mAddress, aChannel->mPath,
420 aChannel->mPort);
421 }
422 }
423
424 if (NS_IsMainThread()) {
425 ContinueOnStopSession(aChannel, aReason);
426 } else {
427 NS_DispatchToMainThread(NS_NewRunnableFunction(
428 "nsWSAdmissionManager::ContinueOnStopSession",
429 [channel = RefPtr{aChannel}, reason = aReason]() {
430 StaticMutexAutoLock lock(sLock);
431 if (!sManager) {
432 return;
433 }
434
435 nsWSAdmissionManager::ContinueOnStopSession(channel, reason);
436 }));
437 }
438 }
439
440 static void ContinueOnStopSession(WebSocketChannel* aChannel,
441 nsresult aReason) {
442 sLock.AssertCurrentThreadOwns();
443 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"
, 443); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
") (" "not main thread" ")"); do { *((volatile int*)__null) =
443; __attribute__((nomerge)) ::abort(); } while (false); } }
while (false)
;
444
445 if (!aChannel->mConnecting) {
446 return;
447 }
448
449 // Only way a connecting channel may get here w/o failing is if it
450 // was closed with GOING_AWAY (1001) because of navigation, tab
451 // close, etc.
452#ifdef DEBUG1
453 {
454 MutexAutoLock lock(aChannel->mMutex);
455 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"
, 457); 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) = 457; __attribute__((nomerge)
) ::abort(); } while (false); } } while (false)
456 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"
, 457); 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) = 457; __attribute__((nomerge)
) ::abort(); } while (false); } } while (false)
457 "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"
, 457); 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) = 457; __attribute__((nomerge)
) ::abort(); } while (false); } } while (false)
;
458 }
459#endif
460 Unused << aReason;
461
462 sManager->RemoveFromQueue(aChannel);
463
464 bool wasNotQueued = (aChannel->mConnecting != CONNECTING_QUEUED);
465 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)
;
466 aChannel->mConnecting = NOT_CONNECTING;
467 if (wasNotQueued) {
468 sManager->ConnectNext(aChannel->mAddress, aChannel->mOriginSuffix);
469 }
470 }
471
472 static void IncrementSessionCount() {
473 StaticMutexAutoLock lock(sLock);
474 if (!sManager) {
475 return;
476 }
477 sManager->mSessionCount++;
478 }
479
480 static void DecrementSessionCount() {
481 StaticMutexAutoLock lock(sLock);
482 if (!sManager) {
483 return;
484 }
485 sManager->mSessionCount--;
486 }
487
488 static void GetSessionCount(int32_t& aSessionCount) {
489 StaticMutexAutoLock lock(sLock);
490 if (!sManager) {
491 return;
492 }
493 aSessionCount = sManager->mSessionCount;
494 }
495
496 private:
497 nsWSAdmissionManager() : mSessionCount(0) {
498 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)
;
499 }
500
501 ~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)
; }
502
503 class nsOpenConn {
504 public:
505 nsOpenConn(nsCString& addr, nsCString& originSuffix, bool failed,
506 WebSocketChannel* channel)
507 : mAddress(addr),
508 mOriginSuffix(originSuffix),
509 mFailed(failed),
510 mChannel(channel) {
511 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)
;
512 }
513 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); }
514
515 nsCString mAddress;
516 nsCString mOriginSuffix;
517 bool mFailed = false;
518 RefPtr<WebSocketChannel> mChannel;
519 };
520
521 void ConnectNext(nsCString& hostName, nsCString& originSuffix) {
522 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"
, 522); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
") (" "not main thread" ")"); do { *((volatile int*)__null) =
522; __attribute__((nomerge)) ::abort(); } while (false); } }
while (false)
;
523
524 int32_t index = IndexOf(hostName, originSuffix);
525 if (index >= 0) {
526 WebSocketChannel* chan = mQueue[index]->mChannel;
527
528 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"
, 529); AnnotateMozCrashReason("MOZ_ASSERT" "(" "chan->mConnecting == CONNECTING_QUEUED"
") (" "transaction not queued but in queue" ")"); do { *((volatile
int*)__null) = 529; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
529 "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"
, 529); AnnotateMozCrashReason("MOZ_ASSERT" "(" "chan->mConnecting == CONNECTING_QUEUED"
") (" "transaction not queued but in queue" ")"); do { *((volatile
int*)__null) = 529; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
530 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)
;
531
532 mFailures.DelayOrBegin(chan);
533 }
534 }
535
536 void RemoveFromQueue(WebSocketChannel* aChannel) {
537 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)
;
538 int32_t index = IndexOf(aChannel);
539 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"
, 539); AnnotateMozCrashReason("MOZ_ASSERT" "(" "index >= 0"
") (" "connection to remove not in queue" ")"); do { *((volatile
int*)__null) = 539; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
540 if (index >= 0) {
541 mQueue.RemoveElementAt(index);
542 }
543 }
544
545 int32_t IndexOf(nsCString& aAddress, nsCString& aOriginSuffix) {
546 for (uint32_t i = 0; i < mQueue.Length(); i++) {
547 bool isPartitioned = StaticPrefs::privacy_partition_network_state() ||
548 StaticPrefs::privacy_firstparty_isolate();
549 if (aAddress == (mQueue[i])->mAddress &&
550 (!isPartitioned || aOriginSuffix == (mQueue[i])->mOriginSuffix)) {
551 return i;
552 }
553 }
554 return -1;
555 }
556
557 int32_t IndexOf(WebSocketChannel* aChannel) {
558 for (uint32_t i = 0; i < mQueue.Length(); i++) {
559 if (aChannel == (mQueue[i])->mChannel) return i;
560 }
561 return -1;
562 }
563
564 // Returns the index of the first entry that failed, or else the last entry if
565 // none found
566 uint32_t IndexOfFirstFailure() {
567 for (uint32_t i = 0; i < mQueue.Length(); i++) {
568 if (mQueue[i]->mFailed) return i;
569 }
570 return mQueue.Length();
571 }
572
573 // SessionCount might be decremented from the main or the socket
574 // thread, so manage it with atomic counters
575 Atomic<int32_t> mSessionCount;
576
577 // Queue for websockets that have not completed connecting yet.
578 // The first nsOpenConn with a given address will be either be
579 // CONNECTING_IN_PROGRESS or CONNECTING_DELAYED. Later ones with the same
580 // hostname must be CONNECTING_QUEUED.
581 //
582 // We could hash hostnames instead of using a single big vector here, but the
583 // dataset is expected to be small.
584 nsTArray<UniquePtr<nsOpenConn>> mQueue;
585
586 FailDelayManager mFailures;
587
588 static nsWSAdmissionManager* sManager MOZ_GUARDED_BY(sLock)__attribute__((guarded_by(sLock)));
589 static StaticMutex sLock;
590};
591
592nsWSAdmissionManager* nsWSAdmissionManager::sManager;
593StaticMutex nsWSAdmissionManager::sLock;
594
595//-----------------------------------------------------------------------------
596// CallOnMessageAvailable
597//-----------------------------------------------------------------------------
598
599class CallOnMessageAvailable final : public Runnable {
600 public:
601 CallOnMessageAvailable(WebSocketChannel* aChannel, nsACString& aData,
602 int32_t aLen)
603 : Runnable("net::CallOnMessageAvailable"),
604 mChannel(aChannel),
605 mListenerMT(aChannel->mListenerMT),
606 mData(aData),
607 mLen(aLen) {}
608
609 NS_IMETHODvirtual nsresult Run() override {
610 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"
, 610); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mChannel->IsOnTargetThread()"
")"); do { *((volatile int*)__null) = 610; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
611
612 if (mListenerMT) {
613 nsresult rv;
614 if (mLen < 0) {
615 rv = mListenerMT->mListener->OnMessageAvailable(mListenerMT->mContext,
616 mData);
617 } else {
618 rv = mListenerMT->mListener->OnBinaryMessageAvailable(
619 mListenerMT->mContext, mData);
620 }
621 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
622 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)
623 ("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)
624 "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)
625 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)
;
626 }
627 }
628
629 return NS_OK;
630 }
631
632 private:
633 ~CallOnMessageAvailable() = default;
634
635 RefPtr<WebSocketChannel> mChannel;
636 RefPtr<BaseWebSocketChannel::ListenerAndContextContainer> mListenerMT;
637 nsCString mData;
638 int32_t mLen;
639};
640
641//-----------------------------------------------------------------------------
642// CallOnStop
643//-----------------------------------------------------------------------------
644
645class CallOnStop final : public Runnable {
646 public:
647 CallOnStop(WebSocketChannel* aChannel, nsresult aReason)
648 : Runnable("net::CallOnStop"),
649 mChannel(aChannel),
650 mListenerMT(mChannel->mListenerMT),
651 mReason(aReason) {}
652
653 NS_IMETHODvirtual nsresult Run() override {
654 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"
, 654); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mChannel->IsOnTargetThread()"
")"); do { *((volatile int*)__null) = 654; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
655
656 if (mListenerMT) {
657 nsresult rv =
658 mListenerMT->mListener->OnStop(mListenerMT->mContext, mReason);
659 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
660 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)
661 ("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)
662 "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)
663 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)
;
664 }
665 mChannel->mListenerMT = nullptr;
666 }
667
668 return NS_OK;
669 }
670
671 private:
672 ~CallOnStop() = default;
673
674 RefPtr<WebSocketChannel> mChannel;
675 RefPtr<BaseWebSocketChannel::ListenerAndContextContainer> mListenerMT;
676 nsresult mReason;
677};
678
679//-----------------------------------------------------------------------------
680// CallOnServerClose
681//-----------------------------------------------------------------------------
682
683class CallOnServerClose final : public Runnable {
684 public:
685 CallOnServerClose(WebSocketChannel* aChannel, uint16_t aCode,
686 nsACString& aReason)
687 : Runnable("net::CallOnServerClose"),
688 mChannel(aChannel),
689 mListenerMT(mChannel->mListenerMT),
690 mCode(aCode),
691 mReason(aReason) {}
692
693 NS_IMETHODvirtual nsresult Run() override {
694 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"
, 694); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mChannel->IsOnTargetThread()"
")"); do { *((volatile int*)__null) = 694; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
695
696 if (mListenerMT) {
697 nsresult rv = mListenerMT->mListener->OnServerClose(mListenerMT->mContext,
698 mCode, mReason);
699 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
700 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)
701 ("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)
702 "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)
703 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)
;
704 }
705 }
706 return NS_OK;
707 }
708
709 private:
710 ~CallOnServerClose() = default;
711
712 RefPtr<WebSocketChannel> mChannel;
713 RefPtr<BaseWebSocketChannel::ListenerAndContextContainer> mListenerMT;
714 uint16_t mCode;
715 nsCString mReason;
716};
717
718//-----------------------------------------------------------------------------
719// CallAcknowledge
720//-----------------------------------------------------------------------------
721
722class CallAcknowledge final : public Runnable {
723 public:
724 CallAcknowledge(WebSocketChannel* aChannel, uint32_t aSize)
725 : Runnable("net::CallAcknowledge"),
726 mChannel(aChannel),
727 mListenerMT(mChannel->mListenerMT),
728 mSize(aSize) {}
729
730 NS_IMETHODvirtual nsresult Run() override {
731 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"
, 731); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mChannel->IsOnTargetThread()"
")"); do { *((volatile int*)__null) = 731; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
732
733 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)
;
734 if (mListenerMT) {
735 nsresult rv =
736 mListenerMT->mListener->OnAcknowledge(mListenerMT->mContext, mSize);
737 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
738 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)
739 ")\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__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 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)
;
741 }
742 }
743 return NS_OK;
744 }
745
746 private:
747 ~CallAcknowledge() = default;
748
749 RefPtr<WebSocketChannel> mChannel;
750 RefPtr<BaseWebSocketChannel::ListenerAndContextContainer> mListenerMT;
751 uint32_t mSize;
752};
753
754//-----------------------------------------------------------------------------
755// CallOnTransportAvailable
756//-----------------------------------------------------------------------------
757
758class CallOnTransportAvailable final : public Runnable {
759 public:
760 CallOnTransportAvailable(WebSocketChannel* aChannel,
761 nsISocketTransport* aTransport,
762 nsIAsyncInputStream* aSocketIn,
763 nsIAsyncOutputStream* aSocketOut)
764 : Runnable("net::CallOnTransportAvailble"),
765 mChannel(aChannel),
766 mTransport(aTransport),
767 mSocketIn(aSocketIn),
768 mSocketOut(aSocketOut) {}
769
770 NS_IMETHODvirtual nsresult Run() override {
771 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)
;
772 return mChannel->OnTransportAvailable(mTransport, mSocketIn, mSocketOut);
773 }
774
775 private:
776 ~CallOnTransportAvailable() = default;
777
778 RefPtr<WebSocketChannel> mChannel;
779 nsCOMPtr<nsISocketTransport> mTransport;
780 nsCOMPtr<nsIAsyncInputStream> mSocketIn;
781 nsCOMPtr<nsIAsyncOutputStream> mSocketOut;
782};
783
784//-----------------------------------------------------------------------------
785// PMCECompression
786//-----------------------------------------------------------------------------
787
788class PMCECompression {
789 public:
790 PMCECompression(bool aNoContextTakeover, int32_t aLocalMaxWindowBits,
791 int32_t aRemoteMaxWindowBits)
792 : mActive(false),
793 mNoContextTakeover(aNoContextTakeover),
794 mResetDeflater(false),
795 mMessageDeflated(false) {
796 this->mDeflater.next_in = nullptr;
797 this->mDeflater.avail_in = 0;
798 this->mDeflater.total_in = 0;
799 this->mDeflater.next_out = nullptr;
800 this->mDeflater.avail_out = 0;
801 this->mDeflater.total_out = 0;
802 this->mDeflater.msg = nullptr;
803 this->mDeflater.state = nullptr;
804 this->mDeflater.data_type = 0;
805 this->mDeflater.adler = 0;
806 this->mDeflater.reserved = 0;
807 this->mInflater.next_in = nullptr;
808 this->mInflater.avail_in = 0;
809 this->mInflater.total_in = 0;
810 this->mInflater.next_out = nullptr;
811 this->mInflater.avail_out = 0;
812 this->mInflater.total_out = 0;
813 this->mInflater.msg = nullptr;
814 this->mInflater.state = nullptr;
815 this->mInflater.data_type = 0;
816 this->mInflater.adler = 0;
817 this->mInflater.reserved = 0;
818 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)
;
819
820 mDeflater.zalloc = mInflater.zalloc = Z_NULL0;
821 mDeflater.zfree = mInflater.zfree = Z_NULL0;
822 mDeflater.opaque = mInflater.opaque = Z_NULL0;
823
824 if (deflateInit2(&mDeflater, Z_DEFAULT_COMPRESSION, Z_DEFLATED,MOZ_Z_deflateInit2_((&mDeflater),((-1)),(8),(-aLocalMaxWindowBits
),(8), (0), "1.3.1", (int)sizeof(z_stream))
825 -aLocalMaxWindowBits, 8, Z_DEFAULT_STRATEGY)MOZ_Z_deflateInit2_((&mDeflater),((-1)),(8),(-aLocalMaxWindowBits
),(8), (0), "1.3.1", (int)sizeof(z_stream))
== Z_OK0) {
826 if (inflateInit2(&mInflater, -aRemoteMaxWindowBits)MOZ_Z_inflateInit2_((&mInflater), (-aRemoteMaxWindowBits)
, "1.3.1", (int)sizeof(z_stream))
== Z_OK0) {
827 mActive = true;
828 } else {
829 deflateEndMOZ_Z_deflateEnd(&mDeflater);
830 }
831 }
832 }
833
834 ~PMCECompression() {
835 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)
;
836
837 if (mActive) {
838 inflateEndMOZ_Z_inflateEnd(&mInflater);
839 deflateEndMOZ_Z_deflateEnd(&mDeflater);
840 }
841 }
842
843 bool Active() { return mActive; }
844
845 void SetMessageDeflated() {
846 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"
, 846); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mMessageDeflated"
")"); do { *((volatile int*)__null) = 846; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
847 mMessageDeflated = true;
848 }
849 bool IsMessageDeflated() { return mMessageDeflated; }
850
851 bool UsingContextTakeover() { return !mNoContextTakeover; }
852
853 nsresult Deflate(uint8_t* data, uint32_t dataLen, nsACString& _retval) {
854 if (mResetDeflater || mNoContextTakeover) {
855 if (deflateResetMOZ_Z_deflateReset(&mDeflater) != Z_OK0) {
856 return NS_ERROR_UNEXPECTED;
857 }
858 mResetDeflater = false;
859 }
860
861 mDeflater.avail_out = kBufferLen;
862 mDeflater.next_out = mBuffer;
863 mDeflater.avail_in = dataLen;
864 mDeflater.next_in = data;
865
866 while (true) {
867 int zerr = deflateMOZ_Z_deflate(&mDeflater, Z_SYNC_FLUSH2);
868
869 if (zerr != Z_OK0) {
870 mResetDeflater = true;
871 return NS_ERROR_UNEXPECTED;
872 }
873
874 uint32_t deflated = kBufferLen - mDeflater.avail_out;
875 if (deflated > 0) {
876 _retval.Append(reinterpret_cast<char*>(mBuffer), deflated);
877 }
878
879 mDeflater.avail_out = kBufferLen;
880 mDeflater.next_out = mBuffer;
881
882 if (mDeflater.avail_in > 0) {
883 continue; // There is still some data to deflate
884 }
885
886 if (deflated == kBufferLen) {
887 continue; // There was not enough space in the buffer
888 }
889
890 break;
891 }
892
893 if (_retval.Length() < 4) {
894 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"
, 894); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"Expected trailing not found in deflated data!" ")"); do { *
((volatile int*)__null) = 894; __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
;
895 mResetDeflater = true;
896 return NS_ERROR_UNEXPECTED;
897 }
898
899 _retval.Truncate(_retval.Length() - 4);
900
901 return NS_OK;
902 }
903
904 nsresult Inflate(uint8_t* data, uint32_t dataLen, nsACString& _retval) {
905 mMessageDeflated = false;
906
907 Bytef trailingData[] = {0x00, 0x00, 0xFF, 0xFF};
908 bool trailingDataUsed = false;
909
910 mInflater.avail_out = kBufferLen;
911 mInflater.next_out = mBuffer;
912 mInflater.avail_in = dataLen;
913 mInflater.next_in = data;
914
915 while (true) {
916 int zerr = inflateMOZ_Z_inflate(&mInflater, Z_NO_FLUSH0);
917
918 if (zerr == Z_STREAM_END1) {
919 Bytef* saveNextIn = mInflater.next_in;
920 uint32_t saveAvailIn = mInflater.avail_in;
921 Bytef* saveNextOut = mInflater.next_out;
922 uint32_t saveAvailOut = mInflater.avail_out;
923
924 inflateResetMOZ_Z_inflateReset(&mInflater);
925
926 mInflater.next_in = saveNextIn;
927 mInflater.avail_in = saveAvailIn;
928 mInflater.next_out = saveNextOut;
929 mInflater.avail_out = saveAvailOut;
930 } else if (zerr != Z_OK0 && zerr != Z_BUF_ERROR(-5)) {
931 return NS_ERROR_INVALID_CONTENT_ENCODING;
932 }
933
934 uint32_t inflated = kBufferLen - mInflater.avail_out;
935 if (inflated > 0) {
936 if (!_retval.Append(reinterpret_cast<char*>(mBuffer), inflated,
937 fallible)) {
938 return NS_ERROR_OUT_OF_MEMORY;
939 }
940 }
941
942 mInflater.avail_out = kBufferLen;
943 mInflater.next_out = mBuffer;
944
945 if (mInflater.avail_in > 0) {
946 continue; // There is still some data to inflate
947 }
948
949 if (inflated == kBufferLen) {
950 continue; // There was not enough space in the buffer
951 }
952
953 if (!trailingDataUsed) {
954 trailingDataUsed = true;
955 mInflater.avail_in = sizeof(trailingData);
956 mInflater.next_in = trailingData;
957 continue;
958 }
959
960 return NS_OK;
961 }
962 }
963
964 private:
965 bool mActive;
966 bool mNoContextTakeover;
967 bool mResetDeflater;
968 bool mMessageDeflated;
969 z_stream mDeflater{};
970 z_stream mInflater{};
971 const static uint32_t kBufferLen = 4096;
972 uint8_t mBuffer[kBufferLen]{0};
973};
974
975//-----------------------------------------------------------------------------
976// OutboundMessage
977//-----------------------------------------------------------------------------
978
979enum WsMsgType {
980 kMsgTypeString = 0,
981 kMsgTypeBinaryString,
982 kMsgTypeStream,
983 kMsgTypePing,
984 kMsgTypePong,
985 kMsgTypeFin
986};
987
988static const char* msgNames[] = {"text", "binaryString", "binaryStream",
989 "ping", "pong", "close"};
990
991class OutboundMessage {
992 public:
993 OutboundMessage(WsMsgType type, const nsACString& str)
994 : mMsg(mozilla::AsVariant(pString(str))),
995 mMsgType(type),
996 mDeflated(false) {
997 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)
;
998 }
999
1000 OutboundMessage(nsIInputStream* stream, uint32_t length)
1001 : mMsg(mozilla::AsVariant(StreamWithLength(stream, length))),
1002 mMsgType(kMsgTypeStream),
1003 mDeflated(false) {
1004 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)
;
1005 }
1006
1007 ~OutboundMessage() {
1008 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)
;
1009 switch (mMsgType) {
1010 case kMsgTypeString:
1011 case kMsgTypeBinaryString:
1012 case kMsgTypePing:
1013 case kMsgTypePong:
1014 break;
1015 case kMsgTypeStream:
1016 // for now this only gets hit if msg deleted w/o being sent
1017 if (mMsg.as<StreamWithLength>().mStream) {
1018 mMsg.as<StreamWithLength>().mStream->Close();
1019 }
1020 break;
1021 case kMsgTypeFin:
1022 break; // do-nothing: avoid compiler warning
1023 }
1024 }
1025
1026 WsMsgType GetMsgType() const { return mMsgType; }
1027 int32_t Length() {
1028 if (mMsg.is<pString>()) {
1029 return mMsg.as<pString>().mValue.Length();
1030 }
1031
1032 return mMsg.as<StreamWithLength>().mLength;
1033 }
1034 int32_t OrigLength() {
1035 if (mMsg.is<pString>()) {
1036 pString& ref = mMsg.as<pString>();
1037 return mDeflated ? ref.mOrigValue.Length() : ref.mValue.Length();
1038 }
1039
1040 return mMsg.as<StreamWithLength>().mLength;
1041 }
1042
1043 uint8_t* BeginWriting() {
1044 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"
, 1045); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mMsgType != kMsgTypeStream"
") (" "Stream should have been converted to string by now" ")"
); do { *((volatile int*)__null) = 1045; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1045 "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"
, 1045); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mMsgType != kMsgTypeStream"
") (" "Stream should have been converted to string by now" ")"
); do { *((volatile int*)__null) = 1045; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1046 if (!mMsg.as<pString>().mValue.IsVoid()) {
1047 return (uint8_t*)mMsg.as<pString>().mValue.BeginWriting();
1048 }
1049 return nullptr;
1050 }
1051
1052 uint8_t* BeginReading() {
1053 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"
, 1054); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mMsgType != kMsgTypeStream"
") (" "Stream should have been converted to string by now" ")"
); do { *((volatile int*)__null) = 1054; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1054 "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"
, 1054); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mMsgType != kMsgTypeStream"
") (" "Stream should have been converted to string by now" ")"
); do { *((volatile int*)__null) = 1054; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1055 if (!mMsg.as<pString>().mValue.IsVoid()) {
1056 return (uint8_t*)mMsg.as<pString>().mValue.BeginReading();
1057 }
1058 return nullptr;
1059 }
1060
1061 uint8_t* BeginOrigReading() {
1062 MOZ_ASSERT(mMsgType != kMsgTypeStream,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mMsgType != kMsgTypeStream)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mMsgType != kMsgTypeStream))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("mMsgType != kMsgTypeStream"
" (" "Stream should have been converted to string by now" ")"
, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/websocket/WebSocketChannel.cpp"
, 1063); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mMsgType != kMsgTypeStream"
") (" "Stream should have been converted to string by now" ")"
); do { *((volatile int*)__null) = 1063; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1063 "Stream should have been converted to string by now")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mMsgType != kMsgTypeStream)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mMsgType != kMsgTypeStream))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("mMsgType != kMsgTypeStream"
" (" "Stream should have been converted to string by now" ")"
, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/websocket/WebSocketChannel.cpp"
, 1063); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mMsgType != kMsgTypeStream"
") (" "Stream should have been converted to string by now" ")"
); do { *((volatile int*)__null) = 1063; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1064 if (!mDeflated) return BeginReading();
1065 if (!mMsg.as<pString>().mOrigValue.IsVoid()) {
1066 return (uint8_t*)mMsg.as<pString>().mOrigValue.BeginReading();
1067 }
1068 return nullptr;
1069 }
1070
1071 nsresult ConvertStreamToString() {
1072 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"
, 1072); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mMsgType == kMsgTypeStream"
") (" "Not a stream!" ")"); do { *((volatile int*)__null) = 1072
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
;
1073 nsAutoCString temp;
1074 {
1075 StreamWithLength& ref = mMsg.as<StreamWithLength>();
1076 nsresult rv = NS_ReadInputStreamToString(ref.mStream, temp, ref.mLength);
1077
1078 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"
, 1078); return rv; } } while (false)
;
1079 if (temp.Length() != ref.mLength) {
1080 return NS_ERROR_UNEXPECTED;
1081 }
1082 ref.mStream->Close();
1083 }
1084
1085 mMsg = mozilla::AsVariant(pString(temp));
1086 mMsgType = kMsgTypeBinaryString;
1087
1088 return NS_OK;
1089 }
1090
1091 bool DeflatePayload(PMCECompression* aCompressor) {
1092 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"
, 1093); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mMsgType != kMsgTypeStream"
") (" "Stream should have been converted to string by now" ")"
); do { *((volatile int*)__null) = 1093; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
1093 "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"
, 1093); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mMsgType != kMsgTypeStream"
") (" "Stream should have been converted to string by now" ")"
); do { *((volatile int*)__null) = 1093; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1094 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"
, 1094); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mDeflated"
")"); do { *((volatile int*)__null) = 1094; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1095
1096 nsresult rv;
1097 pString& ref = mMsg.as<pString>();
1098 if (ref.mValue.Length() == 0) {
1099 // Empty message
1100 return false;
1101 }
1102
1103 nsAutoCString temp;
1104 rv = aCompressor->Deflate(BeginReading(), ref.mValue.Length(), temp);
1105 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
1106 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)
1107 ("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)
1108 "[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)
1109 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)
;
1110 return false;
1111 }
1112
1113 if (!aCompressor->UsingContextTakeover() &&
1114 temp.Length() > ref.mValue.Length()) {
1115 // When "<local>_no_context_takeover" was negotiated, do not send deflated
1116 // payload if it's larger that the original one. OTOH, it makes sense
1117 // to send the larger deflated payload when the sliding window is not
1118 // reset between messages because if we would skip some deflated block
1119 // we would need to empty the sliding window which could affect the
1120 // compression of the subsequent messages.
1121 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)
1122 ("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)
1123 "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)
1124 "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)
1125 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)
;
1126 return false;
1127 }
1128
1129 mDeflated = true;
1130 mMsg.as<pString>().mOrigValue = mMsg.as<pString>().mValue;
1131 mMsg.as<pString>().mValue = temp;
1132 return true;
1133 }
1134
1135 private:
1136 struct pString {
1137 nsCString mValue;
1138 nsCString mOrigValue;
1139 explicit pString(const nsACString& value)
1140 : mValue(value), mOrigValue(VoidCString()) {}
1141 };
1142 struct StreamWithLength {
1143 nsCOMPtr<nsIInputStream> mStream;
1144 uint32_t mLength;
1145 explicit StreamWithLength(nsIInputStream* stream, uint32_t Length)
1146 : mStream(stream), mLength(Length) {}
1147 };
1148 mozilla::Variant<pString, StreamWithLength> mMsg;
1149 WsMsgType mMsgType;
1150 bool mDeflated;
1151};
1152
1153//-----------------------------------------------------------------------------
1154// OutboundEnqueuer
1155//-----------------------------------------------------------------------------
1156
1157class OutboundEnqueuer final : public Runnable {
1158 public:
1159 OutboundEnqueuer(WebSocketChannel* aChannel, OutboundMessage* aMsg)
1160 : Runnable("OutboundEnquerer"), mChannel(aChannel), mMessage(aMsg) {}
1161
1162 NS_IMETHODvirtual nsresult Run() override {
1163 mChannel->EnqueueOutgoingMessage(mChannel->mOutgoingMessages, mMessage);
1164 return NS_OK;
1165 }
1166
1167 private:
1168 ~OutboundEnqueuer() = default;
1169
1170 RefPtr<WebSocketChannel> mChannel;
1171 OutboundMessage* mMessage;
1172};
1173
1174//-----------------------------------------------------------------------------
1175// WebSocketChannel
1176//-----------------------------------------------------------------------------
1177
1178WebSocketChannel::WebSocketChannel()
1179 : mPort(0),
1180 mCloseTimeout(20000),
1181 mOpenTimeout(20000),
1182 mConnecting(NOT_CONNECTING),
1183 mMaxConcurrentConnections(200),
1184 mInnerWindowID(0),
1185 mGotUpgradeOK(0),
1186 mRecvdHttpUpgradeTransport(0),
1187 mAllowPMCE(1),
1188 mPingOutstanding(0),
1189 mReleaseOnTransmit(0),
1190 mDataStarted(false),
1191 mRequestedClose(false),
1192 mClientClosed(false),
1193 mServerClosed(false),
1194 mStopped(false),
1195 mCalledOnStop(false),
1196 mTCPClosed(false),
1197 mOpenedHttpChannel(false),
1198 mIncrementedSessionCount(false),
1199 mDecrementedSessionCount(false),
1200 mMaxMessageSize(INT32_MAX(2147483647)),
1201 mStopOnClose(NS_OK),
1202 mServerCloseCode(CLOSE_ABNORMAL),
1203 mScriptCloseCode(0),
1204 mFragmentOpcode(nsIWebSocketFrame::OPCODE_CONTINUATION),
1205 mFragmentAccumulator(0),
1206 mBuffered(0),
1207 mBufferSize(kIncomingBufferInitialSize),
1208 mCurrentOut(nullptr),
1209 mCurrentOutSent(0),
1210 mHdrOutToSend(0),
1211 mHdrOut(nullptr),
1212 mCompressorMutex("WebSocketChannel::mCompressorMutex"),
1213 mDynamicOutputSize(0),
1214 mDynamicOutput(nullptr),
1215 mPrivateBrowsing(false),
1216 mConnectionLogService(nullptr),
1217 mMutex("WebSocketChannel::mMutex") {
1218 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"
, 1218); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
") (" "not main thread" ")"); do { *((volatile int*)__null) =
1218; __attribute__((nomerge)) ::abort(); } while (false); }
} while (false)
;
1219
1220 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)
;
1221
1222 nsWSAdmissionManager::Init();
1223
1224 mFramePtr = mBuffer = static_cast<uint8_t*>(moz_xmalloc(mBufferSize));
1225
1226 nsresult rv;
1227 mConnectionLogService =
1228 do_GetService("@mozilla.org/network/dashboard;1", &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 do_GetService(NS_PREFSERVICE_CONTRACTID"@mozilla.org/preferences-service;1");
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 = do_GetService(NS_DNSSERVICE_CONTRACTID"@mozilla.org/network/dns-service;1", &rv);
2899 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"
, 2899); return rv; } } while (false)
;
2900 nsCOMPtr<nsIEventTarget> main = GetMainThreadSerialEventTarget();
2901 nsCOMPtr<nsICancelable> cancelable;
2902 rv = dns->AsyncResolveNative(hostName, nsIDNSService::RESOLVE_TYPE_DEFAULT,
2903 nsIDNSService::RESOLVE_DEFAULT_FLAGS, nullptr,
2904 this, main, mLoadInfo->GetOriginAttributes(),
2905 getter_AddRefs(cancelable));
2906 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
2907 return rv;
2908 }
2909
2910 MutexAutoLock lock(mMutex);
2911 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"
, 2911); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mCancelable"
")"); do { *((volatile int*)__null) = 2911; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2912 mCancelable = std::move(cancelable);
2913 return rv;
2914}
2915
2916nsresult WebSocketChannel::ApplyForAdmission() {
2917 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)
;
2918
2919 // Websockets has a policy of 1 session at a time being allowed in the
2920 // CONNECTING state per server IP address (not hostname)
2921
2922 // Check to see if a proxy is being used before making DNS call
2923 nsCOMPtr<nsIProtocolProxyService> pps =
2924 do_GetService(NS_PROTOCOLPROXYSERVICE_CONTRACTID"@mozilla.org/network/protocol-proxy-service;1");
2925
2926 if (!pps) {
2927 // go straight to DNS
2928 // expect the callback in ::OnLookupComplete
2929 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)
2930 "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)
;
2931 return DoAdmissionDNS();
2932 }
2933
2934 nsresult rv;
2935 nsCOMPtr<nsICancelable> cancelable;
2936 rv = pps->AsyncResolve(
2937 mHttpChannel,
2938 nsIProtocolProxyService::RESOLVE_PREFER_SOCKS_PROXY |
2939 nsIProtocolProxyService::RESOLVE_PREFER_HTTPS_PROXY |
2940 nsIProtocolProxyService::RESOLVE_ALWAYS_TUNNEL,
2941 this, nullptr, getter_AddRefs(cancelable));
2942
2943 MutexAutoLock lock(mMutex);
2944 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"
, 2944); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mCancelable"
")"); do { *((volatile int*)__null) = 2944; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
2945 mCancelable = std::move(cancelable);
2946 return rv;
2947}
2948
2949// Called after both OnStartRequest and OnTransportAvailable have
2950// executed. This essentially ends the handshake and starts the websockets
2951// protocol state machine.
2952nsresult WebSocketChannel::CallStartWebsocketData() {
2953 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)
;
2954 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"
, 2954); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
") (" "not main thread" ")"); do { *((volatile int*)__null) =
2954; __attribute__((nomerge)) ::abort(); } while (false); }
} while (false)
;
2955
2956 if (mOpenTimer) {
2957 mOpenTimer->Cancel();
2958 mOpenTimer = nullptr;
2959 }
2960
2961 nsCOMPtr<nsIEventTarget> target = GetTargetThread();
2962 if (target && !target->IsOnCurrentThread()) {
2963 return target->Dispatch(
2964 NewRunnableMethod("net::WebSocketChannel::StartWebsocketData", this,
2965 &WebSocketChannel::StartWebsocketData),
2966 NS_DISPATCH_NORMALnsIEventTarget::DISPATCH_NORMAL);
2967 }
2968
2969 return StartWebsocketData();
2970}
2971
2972nsresult WebSocketChannel::StartWebsocketData() {
2973 {
2974 MutexAutoLock lock(mMutex);
2975 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)
;
2976 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"
, 2976); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mDataStarted"
") (" "StartWebsocketData twice" ")"); do { *((volatile int*
)__null) = 2976; __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
2977
2978 if (mStopped) {
2979 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)
2980 ("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)
2981 "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)
;
2982 return NS_ERROR_NOT_AVAILABLE;
2983 }
2984 }
2985
2986 RefPtr<WebSocketChannel> self = this;
2987 mIOThread->Dispatch(NS_NewRunnableFunction(
2988 "WebSocketChannel::StartWebsocketData", [self{std::move(self)}] {
2989 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)
;
2990
2991 NS_DispatchToMainThread(
2992 NewRunnableMethod("net::WebSocketChannel::NotifyOnStart", self,
2993 &WebSocketChannel::NotifyOnStart),
2994 NS_DISPATCH_NORMALnsIEventTarget::DISPATCH_NORMAL);
2995
2996 nsresult rv = self->mConnection ? self->mConnection->StartReading()
2997 : self->mSocketIn->AsyncWait(
2998 self, 0, 0, self->mIOThread);
2999 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
3000 self->AbortSession(rv);
3001 }
3002
3003 if (self->mPingInterval) {
3004 rv = self->StartPinging();
3005 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
3006 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)
3007 "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)
3008 "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)
3009 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)
;
3010 self->AbortSession(rv);
3011 }
3012 }
3013 }));
3014
3015 return NS_OK;
3016}
3017
3018void WebSocketChannel::NotifyOnStart() {
3019 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)
3020 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)
;
3021 mDataStarted = true;
3022 if (mListenerMT) {
3023 nsresult rv = mListenerMT->mListener->OnStart(mListenerMT->mContext);
3024 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
3025 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::NotifyOnStart "
"mListenerMT->mListener->OnStart() failed with error 0x%08"
"x", static_cast<uint32_t>(rv)); } } while (0)
3026 ("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)
3027 "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)
3028 static_cast<uint32_t>(rv)))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::webSocketLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Debug)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Debug, "WebSocketChannel::NotifyOnStart "
"mListenerMT->mListener->OnStart() failed with error 0x%08"
"x", static_cast<uint32_t>(rv)); } } while (0)
;
3029 }
3030 }
3031}
3032
3033nsresult WebSocketChannel::StartPinging() {
3034 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)
;
3035 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"
, 3035); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mIOThread->IsOnCurrentThread()"
") (" "not on right thread" ")"); do { *((volatile int*)__null
) = 3035; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false)
;
3036 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"
, 3036); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mPingInterval"
")"); do { *((volatile int*)__null) = 3036; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3037 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"
, 3037); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mPingTimer"
")"); do { *((volatile int*)__null) = 3037; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3038
3039 nsresult rv;
3040 rv = NS_NewTimerWithCallback(getter_AddRefs(mPingTimer), this, mPingInterval,
3041 nsITimer::TYPE_ONE_SHOT);
3042 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
3043 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)
3044 (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)
;
3045 } else {
3046 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"
, 3046)
;
3047 }
3048
3049 return NS_OK;
3050}
3051
3052void WebSocketChannel::ReportConnectionTelemetry(nsresult aStatusCode) {
3053 // 3 bits are used. high bit is for wss, middle bit for failed,
3054 // and low bit for proxy..
3055 // 0 - 7 : ws-ok-plain, ws-ok-proxy, ws-failed-plain, ws-failed-proxy,
3056 // wss-ok-plain, wss-ok-proxy, wss-failed-plain, wss-failed-proxy
3057
3058 bool didProxy = false;
3059
3060 nsCOMPtr<nsIProxyInfo> pi;
3061 nsCOMPtr<nsIProxiedChannel> pc = do_QueryInterface(mChannel);
3062 if (pc) pc->GetProxyInfo(getter_AddRefs(pi));
3063 if (pi) {
3064 nsAutoCString proxyType;
3065 pi->GetType(proxyType);
3066 if (!proxyType.IsEmpty() && !proxyType.EqualsLiteral("direct")) {
3067 didProxy = true;
3068 }
3069 }
3070
3071 uint8_t value =
3072 (mEncrypted ? (1 << 2) : 0) |
3073 (!(mGotUpgradeOK && NS_SUCCEEDED(aStatusCode)((bool)(__builtin_expect(!!(!NS_FAILED_impl(aStatusCode)), 1)
))
) ? (1 << 1) : 0) |
3074 (didProxy ? (1 << 0) : 0);
3075
3076 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)
;
3077 Telemetry::Accumulate(Telemetry::WEBSOCKETS_HANDSHAKE_TYPE, value);
3078}
3079
3080// nsIDNSListener
3081
3082NS_IMETHODIMPnsresult
3083WebSocketChannel::OnLookupComplete(nsICancelable* aRequest,
3084 nsIDNSRecord* aRecord, nsresult aStatus) {
3085 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)
3086 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)
;
3087
3088 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"
, 3088); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
") (" "not main thread" ")"); do { *((volatile int*)__null) =
3088; __attribute__((nomerge)) ::abort(); } while (false); }
} while (false)
;
3089
3090 {
3091 MutexAutoLock lock(mMutex);
3092 mCancelable = nullptr;
3093 }
3094
3095 if (mStopped) {
3096 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)
;
3097 return NS_OK;
3098 }
3099
3100 // These failures are not fatal - we just use the hostname as the key
3101 if (NS_FAILED(aStatus)((bool)(__builtin_expect(!!(NS_FAILED_impl(aStatus)), 0)))) {
3102 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)
;
3103
3104 // set host in case we got here without calling DoAdmissionDNS()
3105 mURI->GetHost(mAddress);
3106 } else {
3107 nsCOMPtr<nsIDNSAddrRecord> record = do_QueryInterface(aRecord);
3108 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"
, 3108); AnnotateMozCrashReason("MOZ_ASSERT" "(" "record" ")"
); do { *((volatile int*)__null) = 3108; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3109 nsresult rv = record->GetNextAddrAsString(mAddress);
3110 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
3111 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)
;
3112 }
3113 }
3114
3115 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)
;
3116 nsWSAdmissionManager::ConditionallyConnect(this);
3117
3118 return NS_OK;
3119}
3120
3121// nsIProtocolProxyCallback
3122NS_IMETHODIMPnsresult
3123WebSocketChannel::OnProxyAvailable(nsICancelable* aRequest,
3124 nsIChannel* aChannel, nsIProxyInfo* pi,
3125 nsresult status) {
3126 {
3127 MutexAutoLock lock(mMutex);
3128 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"
, 3128); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!mCancelable || (aRequest == mCancelable)"
")"); do { *((volatile int*)__null) = 3128; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3129 mCancelable = nullptr;
3130 }
3131
3132 if (mStopped) {
3133 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)
3134 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)
;
3135 return NS_OK;
3136 }
3137
3138 nsAutoCString type;
3139 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)))
&&
3140 !type.EqualsLiteral("direct")) {
3141 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)
3142 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)
;
3143 // call DNS callback directly without DNS resolver
3144 OnLookupComplete(nullptr, nullptr, NS_ERROR_FAILURE);
3145 } else {
3146 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)
3147 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)
;
3148 nsresult rv = DoAdmissionDNS();
3149 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
3150 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)
;
3151 // call DNS callback directly without DNS resolver
3152 OnLookupComplete(nullptr, nullptr, NS_ERROR_FAILURE);
3153 }
3154 }
3155
3156 // notify listener of OnProxyAvailable
3157 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)
3158 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)
;
3159 nsresult rv;
3160 nsCOMPtr<nsIProtocolProxyCallback> ppc(
3161 do_QueryInterface(mListenerMT->mListener, &rv));
3162 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
3163 rv = ppc->OnProxyAvailable(aRequest, aChannel, pi, status);
3164 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
3165 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)
3166 ("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)
3167 " 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)
3168 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)
;
3169 }
3170 }
3171
3172 return NS_OK;
3173}
3174
3175// nsIInterfaceRequestor
3176
3177NS_IMETHODIMPnsresult
3178WebSocketChannel::GetInterface(const nsIID& iid, void** result) {
3179 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)
;
3180
3181 if (iid.Equals(NS_GET_IID(nsIChannelEventSink)(nsIChannelEventSink::COMTypeInfo<nsIChannelEventSink, void
>::kIID)
)) {
3182 return QueryInterface(iid, result);
3183 }
3184
3185 if (mCallbacks) return mCallbacks->GetInterface(iid, result);
3186
3187 return NS_ERROR_NO_INTERFACE;
3188}
3189
3190// nsIChannelEventSink
3191
3192NS_IMETHODIMPnsresult
3193WebSocketChannel::AsyncOnChannelRedirect(
3194 nsIChannel* oldChannel, nsIChannel* newChannel, uint32_t flags,
3195 nsIAsyncVerifyRedirectCallback* callback) {
3196 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)
;
3197
3198 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"
, 3198); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
") (" "not main thread" ")"); do { *((volatile int*)__null) =
3198; __attribute__((nomerge)) ::abort(); } while (false); }
} while (false)
;
3199
3200 nsresult rv;
3201
3202 nsCOMPtr<nsIURI> newuri;
3203 rv = newChannel->GetURI(getter_AddRefs(newuri));
3204 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"
, 3204); return rv; } } while (false)
;
3205
3206 // newuri is expected to be http or https
3207 bool newuriIsHttps = newuri->SchemeIs("https");
3208
3209 // allow insecure->secure redirects for HTTP Strict Transport Security (from
3210 // ws://FOO to https://FOO (mapped to wss://FOO)
3211 if (!(flags & (nsIChannelEventSink::REDIRECT_INTERNAL |
3212 nsIChannelEventSink::REDIRECT_STS_UPGRADE))) {
3213 nsAutoCString newSpec;
3214 rv = newuri->GetSpec(newSpec);
3215 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"
, 3215); return rv; } } while (false)
;
3216
3217 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)
3218 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)
;
3219 return NS_ERROR_FAILURE;
3220 }
3221
3222 if (mEncrypted && !newuriIsHttps) {
3223 nsAutoCString spec;
3224 if (NS_SUCCEEDED(newuri->GetSpec(spec))((bool)(__builtin_expect(!!(!NS_FAILED_impl(newuri->GetSpec
(spec))), 1)))
) {
3225 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)
3226 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)
;
3227 }
3228 return NS_ERROR_FAILURE;
3229 }
3230
3231 nsCOMPtr<nsIHttpChannel> newHttpChannel = do_QueryInterface(newChannel, &rv);
3232 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
3233 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)
;
3234 return rv;
3235 }
3236
3237 nsCOMPtr<nsIHttpChannelInternal> newUpgradeChannel =
3238 do_QueryInterface(newChannel, &rv);
3239
3240 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
3241 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)
;
3242 return rv;
3243 }
3244
3245 // The redirect is likely OK
3246
3247 newChannel->SetNotificationCallbacks(this);
3248
3249 mEncrypted = newuriIsHttps;
3250 rv = NS_MutateURI(newuri)
3251 .SetScheme(mEncrypted ? "wss"_ns : "ws"_ns)
3252 .Finalize(mURI);
3253
3254 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
3255 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)
;
3256 return rv;
3257 }
3258
3259 mHttpChannel = newHttpChannel;
3260 mChannel = newUpgradeChannel;
3261 rv = SetupRequest();
3262 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
3263 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)
;
3264 return rv;
3265 }
3266
3267 // Redirected-to URI may need to be delayed by 1-connecting-per-host and
3268 // delay-after-fail algorithms. So hold off calling OnRedirectVerifyCallback
3269 // until BeginOpen, when we know it's OK to proceed with new channel.
3270 mRedirectCallback = callback;
3271
3272 // Mark old channel as successfully connected so we'll clear any FailDelay
3273 // associated with the old URI. Note: no need to also call OnStopSession:
3274 // it's a no-op for successful, already-connected channels.
3275 nsWSAdmissionManager::OnConnected(this);
3276
3277 // ApplyForAdmission as if we were starting from fresh...
3278 mAddress.Truncate();
3279 mOpenedHttpChannel = false;
3280 rv = ApplyForAdmission();
3281 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
3282 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)
;
3283 mRedirectCallback = nullptr;
3284 return rv;
3285 }
3286
3287 return NS_OK;
3288}
3289
3290// nsITimerCallback
3291
3292NS_IMETHODIMPnsresult
3293WebSocketChannel::Notify(nsITimer* timer) {
3294 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)
;
3295
3296 if (timer == mCloseTimer) {
3297 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"
, 3297); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mClientClosed"
") (" "Close Timeout without local close" ")"); do { *((volatile
int*)__null) = 3297; __attribute__((nomerge)) ::abort(); } while
(false); } } while (false)
;
3298 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"
, 3298); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mIOThread->IsOnCurrentThread()"
") (" "not on right thread" ")"); do { *((volatile int*)__null
) = 3298; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false)
;
3299
3300 mCloseTimer = nullptr;
3301 if (mStopped || mServerClosed) { /* no longer relevant */
3302 return NS_OK;
3303 }
3304
3305 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)
;
3306 AbortSession(NS_ERROR_NET_TIMEOUT_EXTERNAL);
3307 } else if (timer == mOpenTimer) {
3308 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"
, 3308); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
") (" "not main thread" ")"); do { *((volatile int*)__null) =
3308; __attribute__((nomerge)) ::abort(); } while (false); }
} while (false)
;
3309
3310 mOpenTimer = nullptr;
3311 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)
;
3312 if (mStopped || mServerClosed) { /* no longer relevant */
3313 return NS_OK;
3314 }
3315
3316 AbortSession(NS_ERROR_NET_TIMEOUT_EXTERNAL);
3317 MOZ_PUSH_IGNORE_THREAD_SAFETYGCC diagnostic push GCC diagnostic ignored "-Wthread-safety"
3318 // mReconnectDelayTimer is only modified on MainThread, we can read it
3319 // without a lock, but ONLY if we're on MainThread! And if we're not
3320 // on MainThread, it can't be mReconnectDelayTimer
3321 } else if (NS_IsMainThread() && timer == mReconnectDelayTimer) {
3322 MOZ_POP_THREAD_SAFETYGCC diagnostic pop
3323 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"
, 3324); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mConnecting == CONNECTING_DELAYED"
") (" "woke up from delay w/o being delayed?" ")"); do { *((
volatile int*)__null) = 3324; __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
3324 "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"
, 3324); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mConnecting == CONNECTING_DELAYED"
") (" "woke up from delay w/o being delayed?" ")"); do { *((
volatile int*)__null) = 3324; __attribute__((nomerge)) ::abort
(); } while (false); } } while (false)
;
3325
3326 {
3327 MutexAutoLock lock(mMutex);
3328 mReconnectDelayTimer = nullptr;
3329 }
3330 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)
;
3331 BeginOpen(false);
3332 } else if (timer == mPingTimer) {
3333 MOZ_ASSERT(mIOThread->IsOnCurrentThread(), "not on right thread")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mIOThread->IsOnCurrentThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mIOThread->IsOnCurrentThread
()))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("mIOThread->IsOnCurrentThread()" " (" "not on right thread"
")", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/websocket/WebSocketChannel.cpp"
, 3333); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mIOThread->IsOnCurrentThread()"
") (" "not on right thread" ")"); do { *((volatile int*)__null
) = 3333; __attribute__((nomerge)) ::abort(); } while (false)
; } } while (false)
;
3334
3335 if (mClientClosed || mServerClosed || mRequestedClose) {
3336 // no point in worrying about ping now
3337 mPingTimer = nullptr;
3338 return NS_OK;
3339 }
3340
3341 if (!mPingOutstanding) {
3342 // Ping interval must be non-null or PING was forced by OnNetworkChanged()
3343 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"
, 3343); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mPingInterval || mPingForced"
")"); do { *((volatile int*)__null) = 3343; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3344 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)
;
3345 mPingOutstanding = 1;
3346 mPingForced = false;
3347 mPingTimer->InitWithCallback(this, mPingResponseTimeout,
3348 nsITimer::TYPE_ONE_SHOT);
3349 GeneratePing();
3350 } else {
3351 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)
;
3352 mPingTimer = nullptr;
3353 AbortSession(NS_ERROR_NET_TIMEOUT_EXTERNAL);
3354 }
3355 } else if (timer == mLingeringCloseTimer) {
3356 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)
;
3357 CleanupConnection();
3358 } else {
3359 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"
, 3359); AnnotateMozCrashReason("MOZ_ASSERT" "(" "0" ") (" "Unknown Timer"
")"); do { *((volatile int*)__null) = 3359; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3360 }
3361
3362 return NS_OK;
3363}
3364
3365// nsINamed
3366
3367NS_IMETHODIMPnsresult
3368WebSocketChannel::GetName(nsACString& aName) {
3369 aName.AssignLiteral("WebSocketChannel");
3370 return NS_OK;
3371}
3372
3373// nsIWebSocketChannel
3374
3375NS_IMETHODIMPnsresult
3376WebSocketChannel::GetSecurityInfo(nsITransportSecurityInfo** aSecurityInfo) {
3377 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)
;
3378 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"
, 3378); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
") (" "not main thread" ")"); do { *((volatile int*)__null) =
3378; __attribute__((nomerge)) ::abort(); } while (false); }
} while (false)
;
3379
3380 *aSecurityInfo = nullptr;
3381
3382 if (mConnection) {
3383 nsresult rv = mConnection->GetSecurityInfo(aSecurityInfo);
3384 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
3385 return rv;
3386 }
3387 return NS_OK;
3388 }
3389
3390 if (mTransport) {
3391 nsCOMPtr<nsITLSSocketControl> tlsSocketControl;
3392 nsresult rv =
3393 mTransport->GetTlsSocketControl(getter_AddRefs(tlsSocketControl));
3394 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
3395 return rv;
3396 }
3397 nsCOMPtr<nsITransportSecurityInfo> securityInfo(
3398 do_QueryInterface(tlsSocketControl));
3399 if (securityInfo) {
3400 securityInfo.forget(aSecurityInfo);
3401 }
3402 }
3403 return NS_OK;
3404}
3405
3406NS_IMETHODIMPnsresult
3407WebSocketChannel::AsyncOpen(nsIURI* aURI, const nsACString& aOrigin,
3408 JS::Handle<JS::Value> aOriginAttributes,
3409 uint64_t aInnerWindowID,
3410 nsIWebSocketListener* aListener,
3411 nsISupports* aContext, JSContext* aCx) {
3412 OriginAttributes attrs;
3413 if (!aOriginAttributes.isObject() || !attrs.Init(aCx, aOriginAttributes)) {
3414 return NS_ERROR_INVALID_ARG;
3415 }
3416 return AsyncOpenNative(aURI, aOrigin, attrs, aInnerWindowID, aListener,
3417 aContext);
3418}
3419
3420NS_IMETHODIMPnsresult
3421WebSocketChannel::AsyncOpenNative(nsIURI* aURI, const nsACString& aOrigin,
3422 const OriginAttributes& aOriginAttributes,
3423 uint64_t aInnerWindowID,
3424 nsIWebSocketListener* aListener,
3425 nsISupports* aContext) {
3426 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)
;
3427
3428 aOriginAttributes.CreateSuffix(mOriginSuffix);
3429
3430 if (!NS_IsMainThread()) {
3431 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"
, 3431); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"not main thread" ")"); do { *((volatile int*)__null) = 3431
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false)
;
3432 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)
;
3433 return NS_ERROR_UNEXPECTED;
3434 }
3435
3436 if ((!aURI && !mIsServerSide) || !aListener) {
3437 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)
;
3438 return NS_ERROR_UNEXPECTED;
3439 }
3440
3441 if (mListenerMT || mWasOpened) return NS_ERROR_ALREADY_OPENED;
3442
3443 nsresult rv;
3444
3445 // Ensure target thread is set if RetargetDeliveryTo isn't called
3446 {
3447 auto lock = mTargetThread.Lock();
3448 if (!lock.ref()) {
3449 lock.ref() = GetMainThreadSerialEventTarget();
3450 }
3451 }
3452
3453 mIOThread = do_GetService(NS_SOCKETTRANSPORTSERVICE_CONTRACTID"@mozilla.org/network/socket-transport-service;1", &rv);
3454 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
3455 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"
, 3455)
;
3456 return rv;
3457 }
3458
3459 nsCOMPtr<nsIPrefBranch> prefService;
3460 prefService = do_GetService(NS_PREFSERVICE_CONTRACTID"@mozilla.org/preferences-service;1");
3461
3462 if (prefService) {
3463 int32_t intpref;
3464 bool boolpref;
3465 rv =
3466 prefService->GetIntPref("network.websocket.max-message-size", &intpref);
3467 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
3468 mMaxMessageSize = clamped(intpref, 1024, INT32_MAX(2147483647));
3469 }
3470 rv = prefService->GetIntPref("network.websocket.timeout.close", &intpref);
3471 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
3472 mCloseTimeout = clamped(intpref, 1, 1800) * 1000;
3473 }
3474 rv = prefService->GetIntPref("network.websocket.timeout.open", &intpref);
3475 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
3476 mOpenTimeout = clamped(intpref, 1, 1800) * 1000;
3477 }
3478 rv = prefService->GetIntPref("network.websocket.timeout.ping.request",
3479 &intpref);
3480 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) && !mClientSetPingInterval) {
3481 mPingInterval = clamped(intpref, 0, 86400) * 1000;
3482 }
3483 rv = prefService->GetIntPref("network.websocket.timeout.ping.response",
3484 &intpref);
3485 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) && !mClientSetPingTimeout) {
3486 mPingResponseTimeout = clamped(intpref, 1, 3600) * 1000;
3487 }
3488 rv = prefService->GetBoolPref(
3489 "network.websocket.extensions.permessage-deflate", &boolpref);
3490 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
3491 mAllowPMCE = boolpref ? 1 : 0;
3492 }
3493 rv = prefService->GetIntPref("network.websocket.max-connections", &intpref);
3494 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
3495 mMaxConcurrentConnections = clamped(intpref, 1, 0xffff);
3496 }
3497 }
3498
3499 int32_t sessionCount = -1;
3500 nsWSAdmissionManager::GetSessionCount(sessionCount);
3501 if (sessionCount >= 0) {
3502 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)
3503 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)
;
3504 }
3505
3506 if (sessionCount >= mMaxConcurrentConnections) {
3507 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)
3508 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)
;
3509
3510 // WebSocket connections are expected to be long lived, so return
3511 // an error here instead of queueing
3512 return NS_ERROR_SOCKET_CREATE_FAILED;
3513 }
3514
3515 mInnerWindowID = aInnerWindowID;
3516 mOriginalURI = aURI;
3517 mURI = mOriginalURI;
3518 mOrigin = aOrigin;
3519
3520 if (mIsServerSide) {
3521 // IncrementSessionCount();
3522 mWasOpened = 1;
3523 mListenerMT = new ListenerAndContextContainer(aListener, aContext);
3524 rv = mServerTransportProvider->SetListener(this);
3525 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"
, 3525); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))"
")"); do { *((volatile int*)__null) = 3525; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
3526 mServerTransportProvider = nullptr;
3527
3528 return NS_OK;
3529 }
3530
3531 mURI->GetHostPort(mHost);
3532
3533 mRandomGenerator =
3534 do_GetService("@mozilla.org/security/random-generator;1", &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 = do_GetService(NS_IOSERVICE_CONTRACTID"@mozilla.org/network/io-service;1", &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 do_GetService("@mozilla.org/nss_errors_service;1");
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