Bug Summary

File:var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/Http2Compression.cpp
Warning:line 391, column 17
Value stored to 'preamble' during its initialization 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_http1.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/http -fcoverage-compilation-dir=/var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/netwerk/protocol/http -resource-dir /usr/lib/llvm-19/lib/clang/19 -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_APP_UA_NAME="" -D MOZ_HAS_MOZGLUE -D MOZILLA_INTERNAL_API -D IMPL_LIBXUL -D MOZ_SUPPORT_LEAKCHECKING -D STATIC_EXPORTABLE_JS_API -I /var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/netwerk/protocol/http -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/netwerk/cookie -I /var/lib/jenkins/workspace/firefox-scan-build/netwerk/dns -I /var/lib/jenkins/workspace/firefox-scan-build/netwerk/ipc -I /var/lib/jenkins/workspace/firefox-scan-build/netwerk/socket/neqo_glue -I /var/lib/jenkins/workspace/firefox-scan-build/netwerk/url-classifier -I /var/lib/jenkins/workspace/firefox-scan-build/extensions/auth -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nspr -I /var/lib/jenkins/workspace/firefox-scan-build/obj-x86_64-pc-linux-gnu/dist/include/nss -D MOZILLA_CLIENT -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/x86_64-linux-gnu/c++/14 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../include/c++/14/backward -internal-isystem /usr/lib/llvm-19/lib/clang/19/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/14/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-error=tautological-type-limit-compare -Wno-invalid-offsetof -Wno-range-loop-analysis -Wno-deprecated-anon-enum-enum-conversion -Wno-deprecated-enum-enum-conversion -Wno-deprecated-this-capture -Wno-inline-new-delete -Wno-error=deprecated-declarations -Wno-error=array-bounds -Wno-error=free-nonheap-object -Wno-error=atomic-alignment -Wno-error=deprecated-builtins -Wno-psabi -Wno-error=builtin-macro-redefined -Wno-vla-cxx-extension -Wno-unknown-warning-option -fdeprecated-macro -ferror-limit 19 -fstrict-flex-arrays=1 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fno-rtti -fgnuc-version=4.2.1 -fskip-odr-check-in-gmf -fno-sized-deallocation -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-09-22-115206-3586786-1 -x c++ Unified_cpp_protocol_http1.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// HttpLog.h should generally be included first
8#include "HttpLog.h"
9
10// Log on level :5, instead of default :4.
11#undef LOG
12#define LOG(args)do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, MOZ_LOG_EXPAND_ARGS args); } } while (0)
LOG5(args)do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, MOZ_LOG_EXPAND_ARGS args); } } while (0)
13#undef LOG_ENABLED
14#define LOG_ENABLED()(__builtin_expect(!!(mozilla::detail::log_test(mozilla::net::
gHttpLog, mozilla::LogLevel::Verbose)), 0))
LOG5_ENABLED()(__builtin_expect(!!(mozilla::detail::log_test(mozilla::net::
gHttpLog, mozilla::LogLevel::Verbose)), 0))
15
16#include "Http2Compression.h"
17#include "Http2HuffmanIncoming.h"
18#include "Http2HuffmanOutgoing.h"
19#include "mozilla/StaticPtr.h"
20#include "nsCharSeparatedTokenizer.h"
21#include "nsIMemoryReporter.h"
22#include "nsHttpHandler.h"
23
24namespace mozilla {
25namespace net {
26
27static nsDeque<nvPair>* gStaticHeaders = nullptr;
28
29class HpackStaticTableReporter final : public nsIMemoryReporter {
30 public:
31 NS_DECL_THREADSAFE_ISUPPORTSpublic: virtual nsresult QueryInterface(const nsIID& aIID
, void** aInstancePtr) override; virtual MozExternalRefCountType
AddRef(void) override; virtual MozExternalRefCountType Release
(void) override; using HasThreadSafeRefCnt = std::true_type; protected
: ::mozilla::ThreadSafeAutoRefCnt mRefCnt; nsAutoOwningThread
_mOwningThread; public:
32
33 HpackStaticTableReporter() = default;
34
35 NS_IMETHODvirtual nsresult
36 CollectReports(nsIHandleReportCallback* aHandleReport, nsISupports* aData,
37 bool aAnonymize) override {
38 MOZ_COLLECT_REPORT("explicit/network/hpack/static-table", KIND_HEAP,(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/network/hpack/static-table"
), KIND_HEAP, UNITS_BYTES, gStaticHeaders->SizeOfIncludingThis
(MallocSizeOf), nsLiteralCString("Memory usage of HPACK static table."
), aData)
39 UNITS_BYTES,(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/network/hpack/static-table"
), KIND_HEAP, UNITS_BYTES, gStaticHeaders->SizeOfIncludingThis
(MallocSizeOf), nsLiteralCString("Memory usage of HPACK static table."
), aData)
40 gStaticHeaders->SizeOfIncludingThis(MallocSizeOf),(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/network/hpack/static-table"
), KIND_HEAP, UNITS_BYTES, gStaticHeaders->SizeOfIncludingThis
(MallocSizeOf), nsLiteralCString("Memory usage of HPACK static table."
), aData)
41 "Memory usage of HPACK static table.")(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/network/hpack/static-table"
), KIND_HEAP, UNITS_BYTES, gStaticHeaders->SizeOfIncludingThis
(MallocSizeOf), nsLiteralCString("Memory usage of HPACK static table."
), aData)
;
42
43 return NS_OK;
44 }
45
46 private:
47 MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf)static size_t MallocSizeOf(const void* aPtr) { mozilla::dmd::
Report(aPtr); return moz_malloc_size_of(aPtr); }
48
49 ~HpackStaticTableReporter() = default;
50};
51
52NS_IMPL_ISUPPORTS(HpackStaticTableReporter, nsIMemoryReporter)MozExternalRefCountType HpackStaticTableReporter::AddRef(void
) { static_assert(!std::is_destructible_v<HpackStaticTableReporter
>, "Reference-counted class " "HpackStaticTableReporter" " 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/http/Http2Compression.cpp"
, 52); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { *((volatile int*)__null) =
52; __attribute__((nomerge)) ::abort(); } while (false); } }
while (false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("HpackStaticTableReporter" != nullptr)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!("HpackStaticTableReporter" != nullptr))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("\"HpackStaticTableReporter\" != nullptr"
" (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/Http2Compression.cpp"
, 52); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"HpackStaticTableReporter\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 52; __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); if (!mRefCnt.isThreadSafe) _mOwningThread.AssertOwnership
("HpackStaticTableReporter" " not thread-safe"); nsrefcnt count
= ++mRefCnt; NS_LogAddRef((this), (count), ("HpackStaticTableReporter"
), (uint32_t)(sizeof(*this))); return count; } MozExternalRefCountType
HpackStaticTableReporter::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/http/Http2Compression.cpp"
, 52); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { *((volatile int*)__null) = 52
; __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("HpackStaticTableReporter" != nullptr)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!("HpackStaticTableReporter" != nullptr))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("\"HpackStaticTableReporter\" != nullptr"
" (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/Http2Compression.cpp"
, 52); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"HpackStaticTableReporter\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 52; __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); if (!mRefCnt.isThreadSafe) _mOwningThread.AssertOwnership
("HpackStaticTableReporter" " not thread-safe"); const char* const
nametmp = "HpackStaticTableReporter"; nsrefcnt count = --mRefCnt
; NS_LogRelease((this), (count), (nametmp)); if (count == 0) {
mRefCnt = 1; delete (this); return 0; } return count; } nsresult
HpackStaticTableReporter::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/http/Http2Compression.cpp"
, 52); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE
; static_assert(1 > 0, "Need more arguments to NS_INTERFACE_TABLE"
); static const QITableEntry table[] = { {&mozilla::detail
::kImplementedIID<HpackStaticTableReporter, nsIMemoryReporter
>, int32_t( reinterpret_cast<char*>(static_cast<nsIMemoryReporter
*>((HpackStaticTableReporter*)0x1000)) - reinterpret_cast<
char*>((HpackStaticTableReporter*)0x1000))}, {&mozilla
::detail::kImplementedIID<HpackStaticTableReporter, nsISupports
>, int32_t(reinterpret_cast<char*>(static_cast<nsISupports
*>( static_cast<nsIMemoryReporter*>((HpackStaticTableReporter
*)0x1000))) - reinterpret_cast<char*>((HpackStaticTableReporter
*)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; }
53
54class HpackDynamicTableReporter final : public nsIMemoryReporter {
55 public:
56 NS_DECL_THREADSAFE_ISUPPORTSpublic: virtual nsresult QueryInterface(const nsIID& aIID
, void** aInstancePtr) override; virtual MozExternalRefCountType
AddRef(void) override; virtual MozExternalRefCountType Release
(void) override; using HasThreadSafeRefCnt = std::true_type; protected
: ::mozilla::ThreadSafeAutoRefCnt mRefCnt; nsAutoOwningThread
_mOwningThread; public:
57
58 explicit HpackDynamicTableReporter(Http2BaseCompressor* aCompressor)
59 : mCompressor(aCompressor) {}
60
61 NS_IMETHODvirtual nsresult
62 CollectReports(nsIHandleReportCallback* aHandleReport, nsISupports* aData,
63 bool aAnonymize) override {
64 MutexAutoLock lock(mMutex);
65 if (mCompressor) {
66 MOZ_COLLECT_REPORT("explicit/network/hpack/dynamic-tables", KIND_HEAP,(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/network/hpack/dynamic-tables"
), KIND_HEAP, UNITS_BYTES, mCompressor->SizeOfExcludingThis
(MallocSizeOf), nsLiteralCString("Aggregate memory usage of HPACK dynamic tables."
), aData)
67 UNITS_BYTES,(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/network/hpack/dynamic-tables"
), KIND_HEAP, UNITS_BYTES, mCompressor->SizeOfExcludingThis
(MallocSizeOf), nsLiteralCString("Aggregate memory usage of HPACK dynamic tables."
), aData)
68 mCompressor->SizeOfExcludingThis(MallocSizeOf),(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/network/hpack/dynamic-tables"
), KIND_HEAP, UNITS_BYTES, mCompressor->SizeOfExcludingThis
(MallocSizeOf), nsLiteralCString("Aggregate memory usage of HPACK dynamic tables."
), aData)
69 "Aggregate memory usage of HPACK dynamic tables.")(void)aHandleReport->Callback(""_ns, nsLiteralCString("explicit/network/hpack/dynamic-tables"
), KIND_HEAP, UNITS_BYTES, mCompressor->SizeOfExcludingThis
(MallocSizeOf), nsLiteralCString("Aggregate memory usage of HPACK dynamic tables."
), aData)
;
70 }
71 return NS_OK;
72 }
73
74 private:
75 MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf)static size_t MallocSizeOf(const void* aPtr) { mozilla::dmd::
Report(aPtr); return moz_malloc_size_of(aPtr); }
76
77 ~HpackDynamicTableReporter() = default;
78
79 Mutex mMutex{"HpackDynamicTableReporter"};
80 Http2BaseCompressor* mCompressor MOZ_GUARDED_BY(mMutex)__attribute__((guarded_by(mMutex)));
81
82 friend class Http2BaseCompressor;
83};
84
85NS_IMPL_ISUPPORTS(HpackDynamicTableReporter, nsIMemoryReporter)MozExternalRefCountType HpackDynamicTableReporter::AddRef(void
) { static_assert(!std::is_destructible_v<HpackDynamicTableReporter
>, "Reference-counted class " "HpackDynamicTableReporter" " 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/http/Http2Compression.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("HpackDynamicTableReporter" != nullptr)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!("HpackDynamicTableReporter" != nullptr))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("\"HpackDynamicTableReporter\" != nullptr"
" (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/Http2Compression.cpp"
, 85); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"HpackDynamicTableReporter\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 85; __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); if (!mRefCnt.isThreadSafe) _mOwningThread.AssertOwnership
("HpackDynamicTableReporter" " not thread-safe"); nsrefcnt count
= ++mRefCnt; NS_LogAddRef((this), (count), ("HpackDynamicTableReporter"
), (uint32_t)(sizeof(*this))); return count; } MozExternalRefCountType
HpackDynamicTableReporter::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/http/Http2Compression.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("HpackDynamicTableReporter" != nullptr)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!("HpackDynamicTableReporter" != nullptr))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("\"HpackDynamicTableReporter\" != nullptr"
" (" "Must specify a name" ")", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/Http2Compression.cpp"
, 85); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"HpackDynamicTableReporter\" != nullptr"
") (" "Must specify a name" ")"); do { *((volatile int*)__null
) = 85; __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); if (!mRefCnt.isThreadSafe) _mOwningThread.AssertOwnership
("HpackDynamicTableReporter" " not thread-safe"); const char*
const nametmp = "HpackDynamicTableReporter"; nsrefcnt count =
--mRefCnt; NS_LogRelease((this), (count), (nametmp)); if (count
== 0) { mRefCnt = 1; delete (this); return 0; } return count
; } nsresult HpackDynamicTableReporter::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/http/Http2Compression.cpp"
, 85); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE
; static_assert(1 > 0, "Need more arguments to NS_INTERFACE_TABLE"
); static const QITableEntry table[] = { {&mozilla::detail
::kImplementedIID<HpackDynamicTableReporter, nsIMemoryReporter
>, int32_t( reinterpret_cast<char*>(static_cast<nsIMemoryReporter
*>((HpackDynamicTableReporter*)0x1000)) - reinterpret_cast
<char*>((HpackDynamicTableReporter*)0x1000))}, {&mozilla
::detail::kImplementedIID<HpackDynamicTableReporter, nsISupports
>, int32_t(reinterpret_cast<char*>(static_cast<nsISupports
*>( static_cast<nsIMemoryReporter*>((HpackDynamicTableReporter
*)0x1000))) - reinterpret_cast<char*>((HpackDynamicTableReporter
*)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
87StaticRefPtr<HpackStaticTableReporter> gStaticReporter;
88
89void Http2CompressionCleanup() {
90 // this happens after the socket thread has been destroyed
91 delete gStaticHeaders;
92 gStaticHeaders = nullptr;
93 UnregisterStrongMemoryReporter(gStaticReporter);
94 gStaticReporter = nullptr;
95}
96
97static void AddStaticElement(const nsCString& name, const nsCString& value) {
98 nvPair* pair = new nvPair(name, value);
99 gStaticHeaders->Push(pair);
100}
101
102static void AddStaticElement(const nsCString& name) {
103 AddStaticElement(name, ""_ns);
104}
105
106static void InitializeStaticHeaders() {
107 MOZ_ASSERT(OnSocketThread(), "not on socket thread")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(OnSocketThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(OnSocketThread()))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("OnSocketThread()"
" (" "not on socket thread" ")", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/Http2Compression.cpp"
, 107); AnnotateMozCrashReason("MOZ_ASSERT" "(" "OnSocketThread()"
") (" "not on socket thread" ")"); do { *((volatile int*)__null
) = 107; __attribute__((nomerge)) ::abort(); } while (false);
} } while (false)
;
108 if (!gStaticHeaders) {
109 gStaticHeaders = new nsDeque<nvPair>();
110 gStaticReporter = new HpackStaticTableReporter();
111 RegisterStrongMemoryReporter(gStaticReporter);
112 AddStaticElement(":authority"_ns);
113 AddStaticElement(":method"_ns, "GET"_ns);
114 AddStaticElement(":method"_ns, "POST"_ns);
115 AddStaticElement(":path"_ns, "/"_ns);
116 AddStaticElement(":path"_ns, "/index.html"_ns);
117 AddStaticElement(":scheme"_ns, "http"_ns);
118 AddStaticElement(":scheme"_ns, "https"_ns);
119 AddStaticElement(":status"_ns, "200"_ns);
120 AddStaticElement(":status"_ns, "204"_ns);
121 AddStaticElement(":status"_ns, "206"_ns);
122 AddStaticElement(":status"_ns, "304"_ns);
123 AddStaticElement(":status"_ns, "400"_ns);
124 AddStaticElement(":status"_ns, "404"_ns);
125 AddStaticElement(":status"_ns, "500"_ns);
126 AddStaticElement("accept-charset"_ns);
127 AddStaticElement("accept-encoding"_ns, "gzip, deflate"_ns);
128 AddStaticElement("accept-language"_ns);
129 AddStaticElement("accept-ranges"_ns);
130 AddStaticElement("accept"_ns);
131 AddStaticElement("access-control-allow-origin"_ns);
132 AddStaticElement("age"_ns);
133 AddStaticElement("allow"_ns);
134 AddStaticElement("authorization"_ns);
135 AddStaticElement("cache-control"_ns);
136 AddStaticElement("content-disposition"_ns);
137 AddStaticElement("content-encoding"_ns);
138 AddStaticElement("content-language"_ns);
139 AddStaticElement("content-length"_ns);
140 AddStaticElement("content-location"_ns);
141 AddStaticElement("content-range"_ns);
142 AddStaticElement("content-type"_ns);
143 AddStaticElement("cookie"_ns);
144 AddStaticElement("date"_ns);
145 AddStaticElement("etag"_ns);
146 AddStaticElement("expect"_ns);
147 AddStaticElement("expires"_ns);
148 AddStaticElement("from"_ns);
149 AddStaticElement("host"_ns);
150 AddStaticElement("if-match"_ns);
151 AddStaticElement("if-modified-since"_ns);
152 AddStaticElement("if-none-match"_ns);
153 AddStaticElement("if-range"_ns);
154 AddStaticElement("if-unmodified-since"_ns);
155 AddStaticElement("last-modified"_ns);
156 AddStaticElement("link"_ns);
157 AddStaticElement("location"_ns);
158 AddStaticElement("max-forwards"_ns);
159 AddStaticElement("proxy-authenticate"_ns);
160 AddStaticElement("proxy-authorization"_ns);
161 AddStaticElement("range"_ns);
162 AddStaticElement("referer"_ns);
163 AddStaticElement("refresh"_ns);
164 AddStaticElement("retry-after"_ns);
165 AddStaticElement("server"_ns);
166 AddStaticElement("set-cookie"_ns);
167 AddStaticElement("strict-transport-security"_ns);
168 AddStaticElement("transfer-encoding"_ns);
169 AddStaticElement("user-agent"_ns);
170 AddStaticElement("vary"_ns);
171 AddStaticElement("via"_ns);
172 AddStaticElement("www-authenticate"_ns);
173 }
174}
175
176size_t nvPair::SizeOfExcludingThis(MallocSizeOf aMallocSizeOf) const {
177 return mName.SizeOfExcludingThisIfUnshared(aMallocSizeOf) +
178 mValue.SizeOfExcludingThisIfUnshared(aMallocSizeOf);
179}
180
181size_t nvPair::SizeOfIncludingThis(MallocSizeOf aMallocSizeOf) const {
182 return aMallocSizeOf(this) + SizeOfExcludingThis(aMallocSizeOf);
183}
184
185nvFIFO::nvFIFO() { InitializeStaticHeaders(); }
186
187nvFIFO::~nvFIFO() { Clear(); }
188
189void nvFIFO::AddElement(const nsCString& name, const nsCString& value) {
190 nvPair* pair = new nvPair(name, value);
191 mByteCount += pair->Size();
192 MutexAutoLock lock(mMutex);
193 mTable.PushFront(pair);
194}
195
196void nvFIFO::AddElement(const nsCString& name) { AddElement(name, ""_ns); }
197
198void nvFIFO::RemoveElement() {
199 nvPair* pair = nullptr;
200 {
201 MutexAutoLock lock(mMutex);
202 pair = mTable.Pop();
203 }
204 if (pair) {
205 mByteCount -= pair->Size();
206 delete pair;
207 }
208}
209
210uint32_t nvFIFO::ByteCount() const { return mByteCount; }
211
212uint32_t nvFIFO::Length() const {
213 return mTable.GetSize() + gStaticHeaders->GetSize();
214}
215
216uint32_t nvFIFO::VariableLength() const { return mTable.GetSize(); }
217
218size_t nvFIFO::StaticLength() const { return gStaticHeaders->GetSize(); }
219
220void nvFIFO::Clear() {
221 mByteCount = 0;
222 MutexAutoLock lock(mMutex);
223 while (mTable.GetSize()) {
224 delete mTable.Pop();
225 }
226}
227
228const nvPair* nvFIFO::operator[](size_t index) const {
229 // NWGH - ensure index > 0
230 // NWGH - subtract 1 from index here
231 if (index >= (mTable.GetSize() + gStaticHeaders->GetSize())) {
232 MOZ_ASSERT(false)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/Http2Compression.cpp"
, 232); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ")");
do { *((volatile int*)__null) = 232; __attribute__((nomerge)
) ::abort(); } while (false); } } while (false)
;
233 NS_WARNING("nvFIFO Table Out of Range")NS_DebugBreak(NS_DEBUG_WARNING, "nvFIFO Table Out of Range", nullptr
, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/Http2Compression.cpp"
, 233)
;
234 return nullptr;
235 }
236 if (index >= gStaticHeaders->GetSize()) {
237 return mTable.ObjectAt(index - gStaticHeaders->GetSize());
238 }
239 return gStaticHeaders->ObjectAt(index);
240}
241
242Http2BaseCompressor::Http2BaseCompressor() {
243 mDynamicReporter = new HpackDynamicTableReporter(this);
244 RegisterStrongMemoryReporter(mDynamicReporter);
245}
246
247Http2BaseCompressor::~Http2BaseCompressor() {
248 if (mPeakSize) {
249 Telemetry::Accumulate(mPeakSizeID, mPeakSize);
250 }
251 if (mPeakCount) {
252 Telemetry::Accumulate(mPeakCountID, mPeakCount);
253 }
254 UnregisterStrongMemoryReporter(mDynamicReporter);
255 {
256 MutexAutoLock lock(mDynamicReporter->mMutex);
257 mDynamicReporter->mCompressor = nullptr;
258 }
259 mDynamicReporter = nullptr;
260}
261
262size_t nvFIFO::SizeOfDynamicTable(mozilla::MallocSizeOf aMallocSizeOf) const {
263 size_t size = 0;
264 MutexAutoLock lock(mMutex);
265 for (const auto elem : mTable) {
266 size += elem->SizeOfIncludingThis(aMallocSizeOf);
267 }
268 return size;
269}
270
271void Http2BaseCompressor::ClearHeaderTable() { mHeaderTable.Clear(); }
272
273size_t Http2BaseCompressor::SizeOfExcludingThis(
274 mozilla::MallocSizeOf aMallocSizeOf) const {
275 return mHeaderTable.SizeOfDynamicTable(aMallocSizeOf);
276}
277
278void Http2BaseCompressor::MakeRoom(uint32_t amount, const char* direction) {
279 uint32_t countEvicted = 0;
280 uint32_t bytesEvicted = 0;
281
282 // make room in the header table
283 while (mHeaderTable.VariableLength() &&
284 ((mHeaderTable.ByteCount() + amount) > mMaxBuffer)) {
285 // NWGH - remove the "- 1" here
286 uint32_t index = mHeaderTable.Length() - 1;
287 LOG(("HTTP %s header table index %u %s %s removed for size.\n", direction,do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "HTTP %s header table index %u %s %s removed for size.\n", direction
, index, mHeaderTable[index]->mName.get(), mHeaderTable[index
]->mValue.get()); } } while (0)
288 index, mHeaderTable[index]->mName.get(),do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "HTTP %s header table index %u %s %s removed for size.\n", direction
, index, mHeaderTable[index]->mName.get(), mHeaderTable[index
]->mValue.get()); } } while (0)
289 mHeaderTable[index]->mValue.get()))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "HTTP %s header table index %u %s %s removed for size.\n", direction
, index, mHeaderTable[index]->mName.get(), mHeaderTable[index
]->mValue.get()); } } while (0)
;
290 ++countEvicted;
291 bytesEvicted += mHeaderTable[index]->Size();
292 mHeaderTable.RemoveElement();
293 }
294
295 if (!strcmp(direction, "decompressor")) {
296 Telemetry::Accumulate(Telemetry::HPACK_ELEMENTS_EVICTED_DECOMPRESSOR,
297 countEvicted);
298 Telemetry::Accumulate(Telemetry::HPACK_BYTES_EVICTED_DECOMPRESSOR,
299 bytesEvicted);
300 Telemetry::Accumulate(
301 Telemetry::HPACK_BYTES_EVICTED_RATIO_DECOMPRESSOR,
302 (uint32_t)((100.0 * (double)bytesEvicted) / (double)amount));
303 } else {
304 Telemetry::Accumulate(Telemetry::HPACK_ELEMENTS_EVICTED_COMPRESSOR,
305 countEvicted);
306 Telemetry::Accumulate(Telemetry::HPACK_BYTES_EVICTED_COMPRESSOR,
307 bytesEvicted);
308 Telemetry::Accumulate(
309 Telemetry::HPACK_BYTES_EVICTED_RATIO_COMPRESSOR,
310 (uint32_t)((100.0 * (double)bytesEvicted) / (double)amount));
311 }
312}
313
314void Http2BaseCompressor::DumpState(const char* preamble) {
315 if (!LOG_ENABLED()(__builtin_expect(!!(mozilla::detail::log_test(mozilla::net::
gHttpLog, mozilla::LogLevel::Verbose)), 0))
) {
316 return;
317 }
318
319 if (!mDumpTables) {
320 return;
321 }
322
323 LOG(("%s", preamble))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "%s", preamble); } } while (0)
;
324
325 LOG(("Header Table"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Header Table"); } } while (0)
;
326 uint32_t i;
327 uint32_t length = mHeaderTable.Length();
328 uint32_t staticLength = mHeaderTable.StaticLength();
329 // NWGH - make i = 1; i <= length; ++i
330 for (i = 0; i < length; ++i) {
331 const nvPair* pair = mHeaderTable[i];
332 // NWGH - make this <= staticLength
333 LOG(("%sindex %u: %s %s", i < staticLength ? "static " : "", i,do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "%sindex %u: %s %s", i < staticLength ? "static " : "", i
, pair->mName.get(), pair->mValue.get()); } } while (0)
334 pair->mName.get(), pair->mValue.get()))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "%sindex %u: %s %s", i < staticLength ? "static " : "", i
, pair->mName.get(), pair->mValue.get()); } } while (0)
;
335 }
336}
337
338void Http2BaseCompressor::SetMaxBufferSizeInternal(uint32_t maxBufferSize) {
339 MOZ_ASSERT(maxBufferSize <= mMaxBufferSetting)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(maxBufferSize <= mMaxBufferSetting)>::isValid,
"invalid assertion condition"); if ((__builtin_expect(!!(!(!
!(maxBufferSize <= mMaxBufferSetting))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("maxBufferSize <= mMaxBufferSetting"
, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/Http2Compression.cpp"
, 339); AnnotateMozCrashReason("MOZ_ASSERT" "(" "maxBufferSize <= mMaxBufferSetting"
")"); do { *((volatile int*)__null) = 339; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
340
341 LOG(("Http2BaseCompressor::SetMaxBufferSizeInternal %u called",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Http2BaseCompressor::SetMaxBufferSizeInternal %u called", maxBufferSize
); } } while (0)
342 maxBufferSize))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Http2BaseCompressor::SetMaxBufferSizeInternal %u called", maxBufferSize
); } } while (0)
;
343
344 while (mHeaderTable.VariableLength() &&
345 (mHeaderTable.ByteCount() > maxBufferSize)) {
346 mHeaderTable.RemoveElement();
347 }
348
349 mMaxBuffer = maxBufferSize;
350}
351
352nsresult Http2BaseCompressor::SetInitialMaxBufferSize(uint32_t maxBufferSize) {
353 MOZ_ASSERT(mSetInitialMaxBufferSizeAllowed)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mSetInitialMaxBufferSizeAllowed)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mSetInitialMaxBufferSizeAllowed
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"mSetInitialMaxBufferSizeAllowed", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/Http2Compression.cpp"
, 353); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mSetInitialMaxBufferSizeAllowed"
")"); do { *((volatile int*)__null) = 353; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
354
355 if (mSetInitialMaxBufferSizeAllowed) {
356 mMaxBufferSetting = maxBufferSize;
357 return NS_OK;
358 }
359
360 return NS_ERROR_FAILURE;
361}
362
363void Http2BaseCompressor::SetDumpTables(bool dumpTables) {
364 mDumpTables = dumpTables;
365}
366
367nsresult Http2Decompressor::DecodeHeaderBlock(const uint8_t* data,
368 uint32_t datalen,
369 nsACString& output, bool isPush) {
370 mSetInitialMaxBufferSizeAllowed = false;
371 mOffset = 0;
372 mData = data;
373 mDataLen = datalen;
374 mOutput = &output;
375 // Add in some space to hopefully not have to reallocate while decompressing
376 // the headers. 512 bytes seems like a good enough number.
377 mOutput->Truncate();
378 mOutput->SetCapacity(datalen + 512);
379 mHeaderStatus.Truncate();
380 mHeaderHost.Truncate();
381 mHeaderScheme.Truncate();
382 mHeaderPath.Truncate();
383 mHeaderMethod.Truncate();
384 mSeenNonColonHeader = false;
385 mIsPush = isPush;
386
387 nsresult rv = NS_OK;
388 nsresult softfail_rv = NS_OK;
389 while (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1))) && (mOffset < mDataLen)) {
390 bool modifiesTable = true;
391 const char* preamble = "Decompressor state after ?";
Value stored to 'preamble' during its initialization is never read
392 if (mData[mOffset] & 0x80) {
393 rv = DoIndexed();
394 preamble = "Decompressor state after indexed";
395 } else if (mData[mOffset] & 0x40) {
396 rv = DoLiteralWithIncremental();
397 preamble = "Decompressor state after literal with incremental";
398 } else if (mData[mOffset] & 0x20) {
399 rv = DoContextUpdate();
400 preamble = "Decompressor state after context update";
401 } else if (mData[mOffset] & 0x10) {
402 modifiesTable = false;
403 rv = DoLiteralNeverIndexed();
404 preamble = "Decompressor state after literal never index";
405 } else {
406 modifiesTable = false;
407 rv = DoLiteralWithoutIndex();
408 preamble = "Decompressor state after literal without index";
409 }
410 DumpState(preamble);
411 if (rv == NS_ERROR_ILLEGAL_VALUE) {
412 if (modifiesTable) {
413 // Unfortunately, we can't count on our peer now having the same state
414 // as us, so let's terminate the session and we can try again later.
415 return NS_ERROR_FAILURE;
416 }
417
418 // This is an http-level error that we can handle by resetting the stream
419 // in the upper layers. Let's note that we saw this, then continue
420 // decompressing until we either hit the end of the header block or find a
421 // hard failure. That way we won't get an inconsistent compression state
422 // with the server.
423 softfail_rv = rv;
424 rv = NS_OK;
425 } else if (rv == NS_ERROR_NET_RESET) {
426 // This happens when we detect connection-based auth being requested in
427 // the response headers. We'll paper over it for now, and the session will
428 // handle this as if it received RST_STREAM with HTTP_1_1_REQUIRED.
429 softfail_rv = rv;
430 rv = NS_OK;
431 }
432 }
433
434 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
435 return rv;
436 }
437
438 return softfail_rv;
439}
440
441nsresult Http2Decompressor::DecodeInteger(uint32_t prefixLen, uint32_t& accum) {
442 accum = 0;
443
444 if (prefixLen) {
445 uint32_t mask = (1 << prefixLen) - 1;
446
447 accum = mData[mOffset] & mask;
448 ++mOffset;
449
450 if (accum != mask) {
451 // the simple case for small values
452 return NS_OK;
453 }
454 }
455
456 uint32_t factor = 1; // 128 ^ 0
457
458 // we need a series of bytes. The high bit signifies if we need another one.
459 // The first one is a a factor of 128 ^ 0, the next 128 ^1, the next 128 ^2,
460 // ..
461
462 if (mOffset >= mDataLen) {
463 NS_WARNING("Ran out of data to decode integer")NS_DebugBreak(NS_DEBUG_WARNING, "Ran out of data to decode integer"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/Http2Compression.cpp"
, 463)
;
464 // This is session-fatal.
465 return NS_ERROR_FAILURE;
466 }
467 bool chainBit = mData[mOffset] & 0x80;
468 accum += (mData[mOffset] & 0x7f) * factor;
469
470 ++mOffset;
471 factor = factor * 128;
472
473 while (chainBit) {
474 // really big offsets are just trawling for overflows
475 if (accum >= 0x800000) {
476 NS_WARNING("Decoding integer >= 0x800000")NS_DebugBreak(NS_DEBUG_WARNING, "Decoding integer >= 0x800000"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/Http2Compression.cpp"
, 476)
;
477 // This is not strictly fatal to the session, but given the fact that
478 // the value is way to large to be reasonable, let's just tell our peer
479 // to go away.
480 return NS_ERROR_FAILURE;
481 }
482
483 if (mOffset >= mDataLen) {
484 NS_WARNING("Ran out of data to decode integer")NS_DebugBreak(NS_DEBUG_WARNING, "Ran out of data to decode integer"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/Http2Compression.cpp"
, 484)
;
485 // This is session-fatal.
486 return NS_ERROR_FAILURE;
487 }
488 chainBit = mData[mOffset] & 0x80;
489 accum += (mData[mOffset] & 0x7f) * factor;
490 ++mOffset;
491 factor = factor * 128;
492 }
493 return NS_OK;
494}
495
496static bool HasConnectionBasedAuth(const nsACString& headerValue) {
497 for (const nsACString& authMethod :
498 nsCCharSeparatedTokenizer(headerValue, '\n').ToRange()) {
499 if (authMethod.LowerCaseEqualsLiteral("ntlm")) {
500 return true;
501 }
502 if (authMethod.LowerCaseEqualsLiteral("negotiate")) {
503 return true;
504 }
505 }
506
507 return false;
508}
509
510nsresult Http2Decompressor::OutputHeader(const nsACString& name,
511 const nsACString& value) {
512 // exclusions
513 if (!mIsPush &&
514 (name.EqualsLiteral("connection") || name.EqualsLiteral("host") ||
515 name.EqualsLiteral("keep-alive") ||
516 name.EqualsLiteral("proxy-connection") || name.EqualsLiteral("te") ||
517 name.EqualsLiteral("transfer-encoding") ||
518 name.EqualsLiteral("upgrade") || name.Equals(("accept-encoding")))) {
519 nsCString toLog(name);
520 LOG(("HTTP Decompressor illegal response header found, not gatewaying: %s",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "HTTP Decompressor illegal response header found, not gatewaying: %s"
, toLog.get()); } } while (0)
521 toLog.get()))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "HTTP Decompressor illegal response header found, not gatewaying: %s"
, toLog.get()); } } while (0)
;
522 return NS_OK;
523 }
524
525 // Bug 1663836: reject invalid HTTP response header names - RFC7540 Sec 10.3
526 const char* cFirst = name.BeginReading();
527 if (cFirst != nullptr && *cFirst == ':') {
528 ++cFirst;
529 }
530 if (!nsHttp::IsValidToken(cFirst, name.EndReading())) {
531 nsCString toLog(name);
532 LOG(("HTTP Decompressor invalid response header found. [%s]\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "HTTP Decompressor invalid response header found. [%s]\n", toLog
.get()); } } while (0)
533 toLog.get()))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "HTTP Decompressor invalid response header found. [%s]\n", toLog
.get()); } } while (0)
;
534 return NS_ERROR_ILLEGAL_VALUE;
535 }
536
537 // Look for upper case characters in the name.
538 for (const char* cPtr = name.BeginReading(); cPtr && cPtr < name.EndReading();
539 ++cPtr) {
540 if (*cPtr <= 'Z' && *cPtr >= 'A') {
541 nsCString toLog(name);
542 LOG(("HTTP Decompressor upper case response header found. [%s]\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "HTTP Decompressor upper case response header found. [%s]\n"
, toLog.get()); } } while (0)
543 toLog.get()))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "HTTP Decompressor upper case response header found. [%s]\n"
, toLog.get()); } } while (0)
;
544 return NS_ERROR_ILLEGAL_VALUE;
545 }
546 }
547
548 // Look for CR, LF or NUL in value - could be smuggling (RFC7540 Sec 10.3)
549 // treat as malformed
550 if (!nsHttp::IsReasonableHeaderValue(value)) {
551 return NS_ERROR_ILLEGAL_VALUE;
552 }
553
554 // Status comes first
555 if (name.EqualsLiteral(":status")) {
556 nsAutoCString status("HTTP/2 "_ns);
557 status.Append(value);
558 status.AppendLiteral("\r\n");
559 mOutput->Insert(status, 0);
560 mHeaderStatus = value;
561 } else if (name.EqualsLiteral(":authority")) {
562 mHeaderHost = value;
563 } else if (name.EqualsLiteral(":scheme")) {
564 mHeaderScheme = value;
565 } else if (name.EqualsLiteral(":path")) {
566 mHeaderPath = value;
567 } else if (name.EqualsLiteral(":method")) {
568 mHeaderMethod = value;
569 }
570
571 // http/2 transport level headers shouldn't be gatewayed into http/1
572 bool isColonHeader = false;
573 for (const char* cPtr = name.BeginReading(); cPtr && cPtr < name.EndReading();
574 ++cPtr) {
575 if (*cPtr == ':') {
576 isColonHeader = true;
577 break;
578 }
579 if (*cPtr != ' ' && *cPtr != '\t') {
580 isColonHeader = false;
581 break;
582 }
583 }
584
585 if (isColonHeader) {
586 // :status is the only pseudo-header field allowed in received HEADERS
587 // frames, PUSH_PROMISE allows the other pseudo-header fields
588 if (!name.EqualsLiteral(":status") && !mIsPush) {
589 LOG(("HTTP Decompressor found illegal response pseudo-header %s",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "HTTP Decompressor found illegal response pseudo-header %s"
, name.BeginReading()); } } while (0)
590 name.BeginReading()))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "HTTP Decompressor found illegal response pseudo-header %s"
, name.BeginReading()); } } while (0)
;
591 return NS_ERROR_ILLEGAL_VALUE;
592 }
593 if (mSeenNonColonHeader) {
594 LOG(("HTTP Decompressor found illegal : header %s", name.BeginReading()))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "HTTP Decompressor found illegal : header %s", name.BeginReading
()); } } while (0)
;
595 return NS_ERROR_ILLEGAL_VALUE;
596 }
597 LOG(("HTTP Decompressor not gatewaying %s into http/1",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "HTTP Decompressor not gatewaying %s into http/1", name.BeginReading
()); } } while (0)
598 name.BeginReading()))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "HTTP Decompressor not gatewaying %s into http/1", name.BeginReading
()); } } while (0)
;
599 return NS_OK;
600 }
601
602 LOG(("Http2Decompressor::OutputHeader %s %s", name.BeginReading(),do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Http2Decompressor::OutputHeader %s %s", name.BeginReading(
), value.BeginReading()); } } while (0)
603 value.BeginReading()))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Http2Decompressor::OutputHeader %s %s", name.BeginReading(
), value.BeginReading()); } } while (0)
;
604 mSeenNonColonHeader = true;
605 mOutput->Append(name);
606 mOutput->AppendLiteral(": ");
607 mOutput->Append(value);
608 mOutput->AppendLiteral("\r\n");
609
610 // Need to check if the server is going to try to speak connection-based auth
611 // with us. If so, we need to kill this via h2, and dial back with http/1.1.
612 // Technically speaking, the server should've just reset or goaway'd us with
613 // HTTP_1_1_REQUIRED, but there are some busted servers out there, so we need
614 // to check on our own to work around them.
615 if (name.EqualsLiteral("www-authenticate") ||
616 name.EqualsLiteral("proxy-authenticate")) {
617 if (HasConnectionBasedAuth(value)) {
618 LOG3(("Http2Decompressor %p connection-based auth found in %s", this,do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Info)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Info, "Http2Decompressor %p connection-based auth found in %s"
, this, name.BeginReading()); } } while (0)
619 name.BeginReading()))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Info)), 0))) { mozilla::
detail::log_print(moz_real_module, mozilla::LogLevel::Info, "Http2Decompressor %p connection-based auth found in %s"
, this, name.BeginReading()); } } while (0)
;
620 return NS_ERROR_NET_RESET;
621 }
622 }
623 return NS_OK;
624}
625
626nsresult Http2Decompressor::OutputHeader(uint32_t index) {
627 // NWGH - make this < index
628 // bounds check
629 if (mHeaderTable.Length() <= index) {
630 LOG(("Http2Decompressor::OutputHeader index too large %u", index))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Http2Decompressor::OutputHeader index too large %u", index
); } } while (0)
;
631 // This is session-fatal.
632 return NS_ERROR_FAILURE;
633 }
634
635 return OutputHeader(mHeaderTable[index]->mName, mHeaderTable[index]->mValue);
636}
637
638nsresult Http2Decompressor::CopyHeaderString(uint32_t index, nsACString& name) {
639 // NWGH - make this < index
640 // bounds check
641 if (mHeaderTable.Length() <= index) {
642 // This is session-fatal.
643 return NS_ERROR_FAILURE;
644 }
645
646 name = mHeaderTable[index]->mName;
647 return NS_OK;
648}
649
650nsresult Http2Decompressor::CopyStringFromInput(uint32_t bytes,
651 nsACString& val) {
652 if (mOffset + bytes > mDataLen) {
653 // This is session-fatal.
654 return NS_ERROR_FAILURE;
655 }
656
657 val.Assign(reinterpret_cast<const char*>(mData) + mOffset, bytes);
658 mOffset += bytes;
659 return NS_OK;
660}
661
662nsresult Http2Decompressor::DecodeFinalHuffmanCharacter(
663 const HuffmanIncomingTable* table, uint8_t& c, uint8_t& bitsLeft) {
664 MOZ_ASSERT(mOffset <= mDataLen)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mOffset <= mDataLen)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mOffset <= mDataLen))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("mOffset <= mDataLen"
, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/Http2Compression.cpp"
, 664); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mOffset <= mDataLen"
")"); do { *((volatile int*)__null) = 664; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
665 if (mOffset > mDataLen) {
666 NS_WARNING("DecodeFinalHuffmanCharacter would read beyond end of buffer")NS_DebugBreak(NS_DEBUG_WARNING, "DecodeFinalHuffmanCharacter would read beyond end of buffer"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/Http2Compression.cpp"
, 666)
;
667 return NS_ERROR_FAILURE;
668 }
669 uint8_t mask = (1 << bitsLeft) - 1;
670 uint8_t idx = mData[mOffset - 1] & mask;
671 idx <<= (8 - bitsLeft);
672 // Don't update bitsLeft yet, because we need to check that value against the
673 // number of bits used by our encoding later on. We'll update when we are sure
674 // how many bits we've actually used.
675
676 if (table->IndexHasANextTable(idx)) {
677 // Can't chain to another table when we're all out of bits in the encoding
678 LOG(("DecodeFinalHuffmanCharacter trying to chain when we're out of bits"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "DecodeFinalHuffmanCharacter trying to chain when we're out of bits"
); } } while (0)
;
679 return NS_ERROR_FAILURE;
680 }
681
682 const HuffmanIncomingEntry* entry = table->Entry(idx);
683
684 if (bitsLeft < entry->mPrefixLen) {
685 // We don't have enough bits to actually make a match, this is some sort of
686 // invalid coding
687 LOG(("DecodeFinalHuffmanCharacter does't have enough bits to match"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "DecodeFinalHuffmanCharacter does't have enough bits to match"
); } } while (0)
;
688 return NS_ERROR_FAILURE;
689 }
690
691 // This is a character!
692 if (entry->mValue == 256) {
693 // EOS
694 LOG(("DecodeFinalHuffmanCharacter actually decoded an EOS"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "DecodeFinalHuffmanCharacter actually decoded an EOS"); } }
while (0)
;
695 return NS_ERROR_FAILURE;
696 }
697 c = static_cast<uint8_t>(entry->mValue & 0xFF);
698 bitsLeft -= entry->mPrefixLen;
699
700 return NS_OK;
701}
702
703uint8_t Http2Decompressor::ExtractByte(uint8_t bitsLeft,
704 uint32_t& bytesConsumed) {
705 MOZ_DIAGNOSTIC_ASSERT(mOffset < mDataLen)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mOffset < mDataLen)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mOffset < mDataLen))), 0)
)) { do { } while (false); MOZ_ReportAssertionFailure("mOffset < mDataLen"
, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/Http2Compression.cpp"
, 705); AnnotateMozCrashReason("MOZ_DIAGNOSTIC_ASSERT" "(" "mOffset < mDataLen"
")"); do { *((volatile int*)__null) = 705; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
706 uint8_t rv;
707
708 if (bitsLeft) {
709 // Need to extract bitsLeft bits from the previous byte, and 8 - bitsLeft
710 // bits from the current byte
711 uint8_t mask = (1 << bitsLeft) - 1;
712 rv = (mData[mOffset - 1] & mask) << (8 - bitsLeft);
713 rv |= (mData[mOffset] & ~mask) >> bitsLeft;
714 } else {
715 rv = mData[mOffset];
716 }
717
718 // We always update these here, under the assumption that all 8 bits we got
719 // here will be used. These may be re-adjusted later in the case that we don't
720 // use up all 8 bits of the byte.
721 ++mOffset;
722 ++bytesConsumed;
723
724 return rv;
725}
726
727nsresult Http2Decompressor::DecodeHuffmanCharacter(
728 const HuffmanIncomingTable* table, uint8_t& c, uint32_t& bytesConsumed,
729 uint8_t& bitsLeft) {
730 uint8_t idx = ExtractByte(bitsLeft, bytesConsumed);
731
732 if (table->IndexHasANextTable(idx)) {
733 if (mOffset >= mDataLen) {
734 if (!bitsLeft || (mOffset > mDataLen)) {
735 // TODO - does this get me into trouble in the new world?
736 // No info left in input to try to consume, we're done
737 LOG(("DecodeHuffmanCharacter all out of bits to consume, can't chain"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "DecodeHuffmanCharacter all out of bits to consume, can't chain"
); } } while (0)
;
738 return NS_ERROR_FAILURE;
739 }
740
741 // We might get lucky here!
742 return DecodeFinalHuffmanCharacter(table->NextTable(idx), c, bitsLeft);
743 }
744
745 // We're sorry, Mario, but your princess is in another castle
746 return DecodeHuffmanCharacter(table->NextTable(idx), c, bytesConsumed,
747 bitsLeft);
748 }
749
750 const HuffmanIncomingEntry* entry = table->Entry(idx);
751 if (entry->mValue == 256) {
752 LOG(("DecodeHuffmanCharacter found an actual EOS"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "DecodeHuffmanCharacter found an actual EOS"); } } while (0
)
;
753 return NS_ERROR_FAILURE;
754 }
755 c = static_cast<uint8_t>(entry->mValue & 0xFF);
756
757 // Need to adjust bitsLeft (and possibly other values) because we may not have
758 // consumed all of the bits of the byte we extracted.
759 if (entry->mPrefixLen <= bitsLeft) {
760 bitsLeft -= entry->mPrefixLen;
761 --mOffset;
762 --bytesConsumed;
763 } else {
764 bitsLeft = 8 - (entry->mPrefixLen - bitsLeft);
765 }
766 MOZ_ASSERT(bitsLeft < 8)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(bitsLeft < 8)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(bitsLeft < 8))), 0))) { do
{ } while (false); MOZ_ReportAssertionFailure("bitsLeft < 8"
, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/Http2Compression.cpp"
, 766); AnnotateMozCrashReason("MOZ_ASSERT" "(" "bitsLeft < 8"
")"); do { *((volatile int*)__null) = 766; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
767
768 return NS_OK;
769}
770
771nsresult Http2Decompressor::CopyHuffmanStringFromInput(uint32_t bytes,
772 nsACString& val) {
773 if (mOffset + bytes > mDataLen) {
774 LOG(("CopyHuffmanStringFromInput not enough data"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "CopyHuffmanStringFromInput not enough data"); } } while (0
)
;
775 return NS_ERROR_FAILURE;
776 }
777
778 uint32_t bytesRead = 0;
779 uint8_t bitsLeft = 0;
780 nsAutoCString buf;
781 nsresult rv;
782 uint8_t c;
783
784 while (bytesRead < bytes) {
785 uint32_t bytesConsumed = 0;
786 rv = DecodeHuffmanCharacter(&HuffmanIncomingRoot, c, bytesConsumed,
787 bitsLeft);
788 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
789 LOG(("CopyHuffmanStringFromInput failed to decode a character"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "CopyHuffmanStringFromInput failed to decode a character");
} } while (0)
;
790 return rv;
791 }
792
793 bytesRead += bytesConsumed;
794 buf.Append(c);
795 }
796
797 if (bytesRead > bytes) {
798 LOG(("CopyHuffmanStringFromInput read more bytes than was allowed!"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "CopyHuffmanStringFromInput read more bytes than was allowed!"
); } } while (0)
;
799 return NS_ERROR_FAILURE;
800 }
801
802 if (bitsLeft) {
803 // The shortest valid code is 4 bits, so we know there can be at most one
804 // character left that our loop didn't decode. Check to see if that's the
805 // case, and if so, add it to our output.
806 rv = DecodeFinalHuffmanCharacter(&HuffmanIncomingRoot, c, bitsLeft);
807 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
808 buf.Append(c);
809 }
810 }
811
812 if (bitsLeft > 7) {
813 LOG(("CopyHuffmanStringFromInput more than 7 bits of padding"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "CopyHuffmanStringFromInput more than 7 bits of padding"); }
} while (0)
;
814 return NS_ERROR_FAILURE;
815 }
816
817 if (bitsLeft) {
818 // Any bits left at this point must belong to the EOS symbol, so make sure
819 // they make sense (ie, are all ones)
820 uint8_t mask = (1 << bitsLeft) - 1;
821 uint8_t bits = mData[mOffset - 1] & mask;
822 if (bits != mask) {
823 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "CopyHuffmanStringFromInput ran out of data but found possible "
"non-EOS symbol"); } } while (0)
824 ("CopyHuffmanStringFromInput ran out of data but found possible "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "CopyHuffmanStringFromInput ran out of data but found possible "
"non-EOS symbol"); } } while (0)
825 "non-EOS symbol"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "CopyHuffmanStringFromInput ran out of data but found possible "
"non-EOS symbol"); } } while (0)
;
826 return NS_ERROR_FAILURE;
827 }
828 }
829
830 val = buf;
831 LOG(("CopyHuffmanStringFromInput decoded a full string!"))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "CopyHuffmanStringFromInput decoded a full string!"); } } while
(0)
;
832 return NS_OK;
833}
834
835nsresult Http2Decompressor::DoIndexed() {
836 // this starts with a 1 bit pattern
837 MOZ_ASSERT(mData[mOffset] & 0x80)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mData[mOffset] & 0x80)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mData[mOffset] & 0x80)))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("mData[mOffset] & 0x80"
, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/Http2Compression.cpp"
, 837); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mData[mOffset] & 0x80"
")"); do { *((volatile int*)__null) = 837; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
838
839 // This is a 7 bit prefix
840
841 uint32_t index;
842 nsresult rv = DecodeInteger(7, index);
843 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
844 return rv;
845 }
846
847 LOG(("HTTP decompressor indexed entry %u\n", index))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "HTTP decompressor indexed entry %u\n", index); } } while (
0)
;
848
849 if (index == 0) {
850 return NS_ERROR_FAILURE;
851 }
852 // NWGH - remove this line, since we'll keep everything 1-indexed
853 index--; // Internally, we 0-index everything, since this is, y'know, C++
854
855 return OutputHeader(index);
856}
857
858nsresult Http2Decompressor::DoLiteralInternal(nsACString& name,
859 nsACString& value,
860 uint32_t namePrefixLen) {
861 // guts of doliteralwithoutindex and doliteralwithincremental
862 MOZ_ASSERT(((mData[mOffset] & 0xF0) == 0x00) || // withoutindexdo { static_assert( mozilla::detail::AssertionConditionType<
decltype(((mData[mOffset] & 0xF0) == 0x00) || ((mData[mOffset
] & 0xF0) == 0x10) || ((mData[mOffset] & 0xC0) == 0x40
))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(((mData[mOffset] & 0xF0) == 0x00) || ((mData[mOffset
] & 0xF0) == 0x10) || ((mData[mOffset] & 0xC0) == 0x40
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("((mData[mOffset] & 0xF0) == 0x00) || ((mData[mOffset] & 0xF0) == 0x10) || ((mData[mOffset] & 0xC0) == 0x40)"
, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/Http2Compression.cpp"
, 864); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((mData[mOffset] & 0xF0) == 0x00) || ((mData[mOffset] & 0xF0) == 0x10) || ((mData[mOffset] & 0xC0) == 0x40)"
")"); do { *((volatile int*)__null) = 864; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
863 ((mData[mOffset] & 0xF0) == 0x10) || // neverindexeddo { static_assert( mozilla::detail::AssertionConditionType<
decltype(((mData[mOffset] & 0xF0) == 0x00) || ((mData[mOffset
] & 0xF0) == 0x10) || ((mData[mOffset] & 0xC0) == 0x40
))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(((mData[mOffset] & 0xF0) == 0x00) || ((mData[mOffset
] & 0xF0) == 0x10) || ((mData[mOffset] & 0xC0) == 0x40
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("((mData[mOffset] & 0xF0) == 0x00) || ((mData[mOffset] & 0xF0) == 0x10) || ((mData[mOffset] & 0xC0) == 0x40)"
, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/Http2Compression.cpp"
, 864); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((mData[mOffset] & 0xF0) == 0x00) || ((mData[mOffset] & 0xF0) == 0x10) || ((mData[mOffset] & 0xC0) == 0x40)"
")"); do { *((volatile int*)__null) = 864; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
864 ((mData[mOffset] & 0xC0) == 0x40))do { static_assert( mozilla::detail::AssertionConditionType<
decltype(((mData[mOffset] & 0xF0) == 0x00) || ((mData[mOffset
] & 0xF0) == 0x10) || ((mData[mOffset] & 0xC0) == 0x40
))>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(((mData[mOffset] & 0xF0) == 0x00) || ((mData[mOffset
] & 0xF0) == 0x10) || ((mData[mOffset] & 0xC0) == 0x40
)))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("((mData[mOffset] & 0xF0) == 0x00) || ((mData[mOffset] & 0xF0) == 0x10) || ((mData[mOffset] & 0xC0) == 0x40)"
, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/Http2Compression.cpp"
, 864); AnnotateMozCrashReason("MOZ_ASSERT" "(" "((mData[mOffset] & 0xF0) == 0x00) || ((mData[mOffset] & 0xF0) == 0x10) || ((mData[mOffset] & 0xC0) == 0x40)"
")"); do { *((volatile int*)__null) = 864; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
; // withincremental
865
866 // first let's get the name
867 uint32_t index;
868 nsresult rv = DecodeInteger(namePrefixLen, index);
869 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
870 return rv;
871 }
872
873 // sanity check
874 if (mOffset >= mDataLen) {
875 NS_WARNING("Http2 Decompressor ran out of data")NS_DebugBreak(NS_DEBUG_WARNING, "Http2 Decompressor ran out of data"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/Http2Compression.cpp"
, 875)
;
876 // This is session-fatal
877 return NS_ERROR_FAILURE;
878 }
879
880 bool isHuffmanEncoded;
881
882 if (!index) {
883 // name is embedded as a literal
884 uint32_t nameLen;
885 isHuffmanEncoded = mData[mOffset] & (1 << 7);
886 rv = DecodeInteger(7, nameLen);
887 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
888 if (isHuffmanEncoded) {
889 rv = CopyHuffmanStringFromInput(nameLen, name);
890 } else {
891 rv = CopyStringFromInput(nameLen, name);
892 }
893 }
894 LOG(("Http2Decompressor::DoLiteralInternal literal name %s",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Http2Decompressor::DoLiteralInternal literal name %s", name
.BeginReading()); } } while (0)
895 name.BeginReading()))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Http2Decompressor::DoLiteralInternal literal name %s", name
.BeginReading()); } } while (0)
;
896 } else {
897 // NWGH - make this index, not index - 1
898 // name is from headertable
899 rv = CopyHeaderString(index - 1, name);
900 LOG(("Http2Decompressor::DoLiteralInternal indexed name %d %s", index,do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Http2Decompressor::DoLiteralInternal indexed name %d %s", index
, name.BeginReading()); } } while (0)
901 name.BeginReading()))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Http2Decompressor::DoLiteralInternal indexed name %d %s", index
, name.BeginReading()); } } while (0)
;
902 }
903 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
904 return rv;
905 }
906
907 // sanity check
908 if (mOffset >= mDataLen) {
909 NS_WARNING("Http2 Decompressor ran out of data")NS_DebugBreak(NS_DEBUG_WARNING, "Http2 Decompressor ran out of data"
, nullptr, "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/Http2Compression.cpp"
, 909)
;
910 // This is session-fatal
911 return NS_ERROR_FAILURE;
912 }
913
914 // now the value
915 uint32_t valueLen;
916 isHuffmanEncoded = mData[mOffset] & (1 << 7);
917 rv = DecodeInteger(7, valueLen);
918 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
919 if (isHuffmanEncoded) {
920 rv = CopyHuffmanStringFromInput(valueLen, value);
921 } else {
922 rv = CopyStringFromInput(valueLen, value);
923 }
924 }
925 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
926 return rv;
927 }
928
929 int32_t newline = 0;
930 while ((newline = value.FindChar('\n', newline)) != -1) {
931 if (value[newline + 1] == ' ' || value[newline + 1] == '\t') {
932 LOG(("Http2Decompressor::Disallowing folded header value %s",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Http2Decompressor::Disallowing folded header value %s", value
.BeginReading()); } } while (0)
933 value.BeginReading()))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Http2Decompressor::Disallowing folded header value %s", value
.BeginReading()); } } while (0)
;
934 return NS_ERROR_ILLEGAL_VALUE;
935 }
936 // Increment this to avoid always finding the same newline and looping
937 // forever
938 ++newline;
939 }
940
941 LOG(("Http2Decompressor::DoLiteralInternal value %s", value.BeginReading()))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Http2Decompressor::DoLiteralInternal value %s", value.BeginReading
()); } } while (0)
;
942 return NS_OK;
943}
944
945nsresult Http2Decompressor::DoLiteralWithoutIndex() {
946 // this starts with 0000 bit pattern
947 MOZ_ASSERT((mData[mOffset] & 0xF0) == 0x00)do { static_assert( mozilla::detail::AssertionConditionType<
decltype((mData[mOffset] & 0xF0) == 0x00)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!((mData[mOffset] & 0xF0) ==
0x00))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("(mData[mOffset] & 0xF0) == 0x00", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/Http2Compression.cpp"
, 947); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(mData[mOffset] & 0xF0) == 0x00"
")"); do { *((volatile int*)__null) = 947; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
948
949 nsAutoCString name, value;
950 nsresult rv = DoLiteralInternal(name, value, 4);
951
952 LOG(("HTTP decompressor literal without index %s %s\n", name.get(),do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "HTTP decompressor literal without index %s %s\n", name.get
(), value.get()); } } while (0)
953 value.get()))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "HTTP decompressor literal without index %s %s\n", name.get
(), value.get()); } } while (0)
;
954
955 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
956 rv = OutputHeader(name, value);
957 }
958 return rv;
959}
960
961nsresult Http2Decompressor::DoLiteralWithIncremental() {
962 // this starts with 01 bit pattern
963 MOZ_ASSERT((mData[mOffset] & 0xC0) == 0x40)do { static_assert( mozilla::detail::AssertionConditionType<
decltype((mData[mOffset] & 0xC0) == 0x40)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!((mData[mOffset] & 0xC0) ==
0x40))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("(mData[mOffset] & 0xC0) == 0x40", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/Http2Compression.cpp"
, 963); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(mData[mOffset] & 0xC0) == 0x40"
")"); do { *((volatile int*)__null) = 963; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
964
965 nsAutoCString name, value;
966 nsresult rv = DoLiteralInternal(name, value, 6);
967 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
968 rv = OutputHeader(name, value);
969 }
970 // Let NET_RESET continue on so that we don't get out of sync, as it is just
971 // used to kill the stream, not the session.
972 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0))) && rv != NS_ERROR_NET_RESET) {
973 return rv;
974 }
975
976 uint32_t room = nvPair(name, value).Size();
977 if (room > mMaxBuffer) {
978 ClearHeaderTable();
979 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "HTTP decompressor literal with index not inserted due to size %u %s "
"%s\n", room, name.get(), value.get()); } } while (0)
980 ("HTTP decompressor literal with index not inserted due to size %u %s "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "HTTP decompressor literal with index not inserted due to size %u %s "
"%s\n", room, name.get(), value.get()); } } while (0)
981 "%s\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "HTTP decompressor literal with index not inserted due to size %u %s "
"%s\n", room, name.get(), value.get()); } } while (0)
982 room, name.get(), value.get()))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "HTTP decompressor literal with index not inserted due to size %u %s "
"%s\n", room, name.get(), value.get()); } } while (0)
;
983 DumpState("Decompressor state after ClearHeaderTable");
984 return rv;
985 }
986
987 MakeRoom(room, "decompressor");
988
989 // Incremental Indexing implicitly adds a row to the header table.
990 mHeaderTable.AddElement(name, value);
991
992 uint32_t currentSize = mHeaderTable.ByteCount();
993 if (currentSize > mPeakSize) {
994 mPeakSize = currentSize;
995 }
996
997 uint32_t currentCount = mHeaderTable.VariableLength();
998 if (currentCount > mPeakCount) {
999 mPeakCount = currentCount;
1000 }
1001
1002 LOG(("HTTP decompressor literal with index 0 %s %s\n", name.get(),do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "HTTP decompressor literal with index 0 %s %s\n", name.get(
), value.get()); } } while (0)
1003 value.get()))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "HTTP decompressor literal with index 0 %s %s\n", name.get(
), value.get()); } } while (0)
;
1004
1005 return rv;
1006}
1007
1008nsresult Http2Decompressor::DoLiteralNeverIndexed() {
1009 // This starts with 0001 bit pattern
1010 MOZ_ASSERT((mData[mOffset] & 0xF0) == 0x10)do { static_assert( mozilla::detail::AssertionConditionType<
decltype((mData[mOffset] & 0xF0) == 0x10)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!((mData[mOffset] & 0xF0) ==
0x10))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("(mData[mOffset] & 0xF0) == 0x10", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/Http2Compression.cpp"
, 1010); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(mData[mOffset] & 0xF0) == 0x10"
")"); do { *((volatile int*)__null) = 1010; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1011
1012 nsAutoCString name, value;
1013 nsresult rv = DoLiteralInternal(name, value, 4);
1014
1015 LOG(("HTTP decompressor literal never indexed %s %s\n", name.get(),do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "HTTP decompressor literal never indexed %s %s\n", name.get
(), value.get()); } } while (0)
1016 value.get()))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "HTTP decompressor literal never indexed %s %s\n", name.get
(), value.get()); } } while (0)
;
1017
1018 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
1019 rv = OutputHeader(name, value);
1020 }
1021 return rv;
1022}
1023
1024nsresult Http2Decompressor::DoContextUpdate() {
1025 // This starts with 001 bit pattern
1026 MOZ_ASSERT((mData[mOffset] & 0xE0) == 0x20)do { static_assert( mozilla::detail::AssertionConditionType<
decltype((mData[mOffset] & 0xE0) == 0x20)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!((mData[mOffset] & 0xE0) ==
0x20))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("(mData[mOffset] & 0xE0) == 0x20", "/var/lib/jenkins/workspace/firefox-scan-build/netwerk/protocol/http/Http2Compression.cpp"
, 1026); AnnotateMozCrashReason("MOZ_ASSERT" "(" "(mData[mOffset] & 0xE0) == 0x20"
")"); do { *((volatile int*)__null) = 1026; __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1027
1028 // Getting here means we have to adjust the max table size, because the
1029 // compressor on the other end has signaled to us through HPACK (not H2)
1030 // that it's using a size different from the currently-negotiated size.
1031 // This change could either come about because we've sent a
1032 // SETTINGS_HEADER_TABLE_SIZE, or because the encoder has decided that
1033 // the current negotiated size doesn't fit its needs (for whatever reason)
1034 // and so it needs to change it (either up to the max allowed by our SETTING,
1035 // or down to some value below that)
1036 uint32_t newMaxSize;
1037 nsresult rv = DecodeInteger(5, newMaxSize);
1038 LOG(("Http2Decompressor::DoContextUpdate new maximum size %u", newMaxSize))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Http2Decompressor::DoContextUpdate new maximum size %u", newMaxSize
); } } while (0)
;
1039 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
1040 return rv;
1041 }
1042
1043 if (newMaxSize > mMaxBufferSetting) {
1044 // This is fatal to the session - peer is trying to use a table larger
1045 // than we have made available.
1046 return NS_ERROR_FAILURE;
1047 }
1048
1049 SetMaxBufferSizeInternal(newMaxSize);
1050
1051 return NS_OK;
1052}
1053
1054/////////////////////////////////////////////////////////////////
1055
1056nsresult Http2Compressor::EncodeHeaderBlock(
1057 const nsCString& nvInput, const nsACString& method, const nsACString& path,
1058 const nsACString& host, const nsACString& scheme,
1059 const nsACString& protocol, bool simpleConnectForm, nsACString& output) {
1060 mSetInitialMaxBufferSizeAllowed = false;
1061 mOutput = &output;
1062 output.Truncate();
1063 mParsedContentLength = -1;
1064
1065 bool isWebsocket = (!simpleConnectForm && !protocol.IsEmpty());
1066
1067 // first thing's first - context size updates (if necessary)
1068 if (mBufferSizeChangeWaiting) {
1069 if (mLowestBufferSizeWaiting < mMaxBufferSetting) {
1070 EncodeTableSizeChange(mLowestBufferSizeWaiting);
1071 }
1072 EncodeTableSizeChange(mMaxBufferSetting);
1073 mBufferSizeChangeWaiting = false;
1074 }
1075
1076 // colon headers first
1077 if (!simpleConnectForm) {
1078 ProcessHeader(nvPair(":method"_ns, method), false, false);
1079 ProcessHeader(nvPair(":path"_ns, path), true, false);
1080 ProcessHeader(nvPair(":authority"_ns, host), false, false);
1081 ProcessHeader(nvPair(":scheme"_ns, scheme), false, false);
1082 if (isWebsocket) {
1083 ProcessHeader(nvPair(":protocol"_ns, protocol), false, false);
1084 }
1085 } else {
1086 ProcessHeader(nvPair(":method"_ns, method), false, false);
1087 ProcessHeader(nvPair(":authority"_ns, host), false, false);
1088 }
1089
1090 // now the non colon headers
1091 const char* beginBuffer = nvInput.BeginReading();
1092
1093 // This strips off the HTTP/1 method+path+version
1094 int32_t crlfIndex = nvInput.Find("\r\n");
1095 while (true) {
1096 int32_t startIndex = crlfIndex + 2;
1097
1098 crlfIndex = nvInput.Find("\r\n", startIndex);
1099 if (crlfIndex == -1) {
1100 break;
1101 }
1102
1103 int32_t colonIndex = Substring(nvInput, 0, crlfIndex).Find(":", startIndex);
1104 if (colonIndex == -1) {
1105 break;
1106 }
1107
1108 nsDependentCSubstring name =
1109 Substring(beginBuffer + startIndex, beginBuffer + colonIndex);
1110 // all header names are lower case in http/2
1111 ToLowerCase(name);
1112
1113 // exclusions
1114 if (name.EqualsLiteral("connection") || name.EqualsLiteral("host") ||
1115 name.EqualsLiteral("keep-alive") ||
1116 name.EqualsLiteral("proxy-connection") || name.EqualsLiteral("te") ||
1117 name.EqualsLiteral("transfer-encoding") ||
1118 name.EqualsLiteral("upgrade") ||
1119 name.EqualsLiteral("sec-websocket-key")) {
1120 continue;
1121 }
1122
1123 // colon headers are for http/2 and this is http/1 input, so that
1124 // is probably a smuggling attack of some kind
1125 bool isColonHeader = false;
1126 for (const char* cPtr = name.BeginReading();
1127 cPtr && cPtr < name.EndReading(); ++cPtr) {
1128 if (*cPtr == ':') {
1129 isColonHeader = true;
1130 break;
1131 }
1132 if (*cPtr != ' ' && *cPtr != '\t') {
1133 isColonHeader = false;
1134 break;
1135 }
1136 }
1137 if (isColonHeader) {
1138 continue;
1139 }
1140
1141 int32_t valueIndex = colonIndex + 1;
1142
1143 while (valueIndex < crlfIndex && beginBuffer[valueIndex] == ' ') {
1144 ++valueIndex;
1145 }
1146
1147 nsDependentCSubstring value =
1148 Substring(beginBuffer + valueIndex, beginBuffer + crlfIndex);
1149
1150 if (name.EqualsLiteral("content-length")) {
1151 int64_t len;
1152 nsCString tmp(value);
1153 if (nsHttp::ParseInt64(tmp.get(), nullptr, &len)) {
1154 mParsedContentLength = len;
1155 }
1156 }
1157
1158 if (name.EqualsLiteral("cookie")) {
1159 // cookie crumbling
1160 bool haveMoreCookies = true;
1161 int32_t nextCookie = valueIndex;
1162 while (haveMoreCookies) {
1163 int32_t semiSpaceIndex =
1164 Substring(nvInput, 0, crlfIndex).Find("; ", nextCookie);
1165 if (semiSpaceIndex == -1) {
1166 haveMoreCookies = false;
1167 semiSpaceIndex = crlfIndex;
1168 }
1169 nsDependentCSubstring cookie =
1170 Substring(beginBuffer + nextCookie, beginBuffer + semiSpaceIndex);
1171 // cookies less than 20 bytes are not indexed
1172 ProcessHeader(nvPair(name, cookie), false, cookie.Length() < 20);
1173 nextCookie = semiSpaceIndex + 2;
1174 }
1175 } else {
1176 // allow indexing of every non-cookie except authorization
1177 ProcessHeader(nvPair(name, value), false,
1178 name.EqualsLiteral("authorization"));
1179 }
1180 }
1181
1182 // NB: This is a *really* ugly hack, but to do this in the right place (the
1183 // transaction) would require totally reworking how/when the transaction
1184 // creates its request stream, which is not worth the effort and risk of
1185 // breakage just to add one header only to h2 connections.
1186 if (!simpleConnectForm && !isWebsocket) {
1187 // Add in TE: trailers for regular requests
1188 nsAutoCString te("te");
1189 nsAutoCString trailers("trailers");
1190 ProcessHeader(nvPair(te, trailers), false, false);
1191 }
1192
1193 mOutput = nullptr;
1194 DumpState("Compressor state after EncodeHeaderBlock");
1195 return NS_OK;
1196}
1197
1198void Http2Compressor::DoOutput(Http2Compressor::outputCode code,
1199 const class nvPair* pair, uint32_t index) {
1200 // start Byte needs to be calculated from the offset after
1201 // the opcode has been written out in case the output stream
1202 // buffer gets resized/relocated
1203 uint32_t offset = mOutput->Length();
1204 uint8_t* startByte;
1205
1206 switch (code) {
1207 case kNeverIndexedLiteral:
1208 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "HTTP compressor %p neverindex literal with name reference %u %s "
"%s\n", this, index, pair->mName.get(), pair->mValue.get
()); } } while (0)
1209 ("HTTP compressor %p neverindex literal with name reference %u %s "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "HTTP compressor %p neverindex literal with name reference %u %s "
"%s\n", this, index, pair->mName.get(), pair->mValue.get
()); } } while (0)
1210 "%s\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "HTTP compressor %p neverindex literal with name reference %u %s "
"%s\n", this, index, pair->mName.get(), pair->mValue.get
()); } } while (0)
1211 this, index, pair->mName.get(), pair->mValue.get()))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "HTTP compressor %p neverindex literal with name reference %u %s "
"%s\n", this, index, pair->mName.get(), pair->mValue.get
()); } } while (0)
;
1212
1213 // In this case, the index will have already been adjusted to be 1-based
1214 // instead of 0-based.
1215 EncodeInteger(4, index); // 0001 4 bit prefix
1216 startByte =
1217 reinterpret_cast<unsigned char*>(mOutput->BeginWriting()) + offset;
1218 *startByte = (*startByte & 0x0f) | 0x10;
1219
1220 if (!index) {
1221 HuffmanAppend(pair->mName);
1222 }
1223
1224 HuffmanAppend(pair->mValue);
1225 break;
1226
1227 case kPlainLiteral:
1228 LOG(("HTTP compressor %p noindex literal with name reference %u %s %s\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "HTTP compressor %p noindex literal with name reference %u %s %s\n"
, this, index, pair->mName.get(), pair->mValue.get()); }
} while (0)
1229 this, index, pair->mName.get(), pair->mValue.get()))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "HTTP compressor %p noindex literal with name reference %u %s %s\n"
, this, index, pair->mName.get(), pair->mValue.get()); }
} while (0)
;
1230
1231 // In this case, the index will have already been adjusted to be 1-based
1232 // instead of 0-based.
1233 EncodeInteger(4, index); // 0000 4 bit prefix
1234 startByte =
1235 reinterpret_cast<unsigned char*>(mOutput->BeginWriting()) + offset;
1236 *startByte = *startByte & 0x0f;
1237
1238 if (!index) {
1239 HuffmanAppend(pair->mName);
1240 }
1241
1242 HuffmanAppend(pair->mValue);
1243 break;
1244
1245 case kIndexedLiteral:
1246 LOG(("HTTP compressor %p literal with name reference %u %s %s\n", this,do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "HTTP compressor %p literal with name reference %u %s %s\n"
, this, index, pair->mName.get(), pair->mValue.get()); }
} while (0)
1247 index, pair->mName.get(), pair->mValue.get()))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "HTTP compressor %p literal with name reference %u %s %s\n"
, this, index, pair->mName.get(), pair->mValue.get()); }
} while (0)
;
1248
1249 // In this case, the index will have already been adjusted to be 1-based
1250 // instead of 0-based.
1251 EncodeInteger(6, index); // 01 2 bit prefix
1252 startByte =
1253 reinterpret_cast<unsigned char*>(mOutput->BeginWriting()) + offset;
1254 *startByte = (*startByte & 0x3f) | 0x40;
1255
1256 if (!index) {
1257 HuffmanAppend(pair->mName);
1258 }
1259
1260 HuffmanAppend(pair->mValue);
1261 break;
1262
1263 case kIndex:
1264 LOG(("HTTP compressor %p index %u %s %s\n", this, index,do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "HTTP compressor %p index %u %s %s\n", this, index, pair->
mName.get(), pair->mValue.get()); } } while (0)
1265 pair->mName.get(), pair->mValue.get()))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "HTTP compressor %p index %u %s %s\n", this, index, pair->
mName.get(), pair->mValue.get()); } } while (0)
;
1266 // NWGH - make this plain old index instead of index + 1
1267 // In this case, we are passed the raw 0-based C index, and need to
1268 // increment to make it 1-based and comply with the spec
1269 EncodeInteger(7, index + 1);
1270 startByte =
1271 reinterpret_cast<unsigned char*>(mOutput->BeginWriting()) + offset;
1272 *startByte = *startByte | 0x80; // 1 1 bit prefix
1273 break;
1274 }
1275}
1276
1277// writes the encoded integer onto the output
1278void Http2Compressor::EncodeInteger(uint32_t prefixLen, uint32_t val) {
1279 uint32_t mask = (1 << prefixLen) - 1;
1280 uint8_t tmp;
1281
1282 if (val < mask) {
1283 // 1 byte encoding!
1284 tmp = val;
1285 mOutput->Append(reinterpret_cast<char*>(&tmp), 1);
1286 return;
1287 }
1288
1289 if (mask) {
1290 val -= mask;
1291 tmp = mask;
1292 mOutput->Append(reinterpret_cast<char*>(&tmp), 1);
1293 }
1294
1295 uint32_t q, r;
1296 do {
1297 q = val / 128;
1298 r = val % 128;
1299 tmp = r;
1300 if (q) {
1301 tmp |= 0x80; // chain bit
1302 }
1303 val = q;
1304 mOutput->Append(reinterpret_cast<char*>(&tmp), 1);
1305 } while (q);
1306}
1307
1308void Http2Compressor::HuffmanAppend(const nsCString& value) {
1309 nsAutoCString buf;
1310 uint8_t bitsLeft = 8;
1311 uint32_t length = value.Length();
1312 uint32_t offset;
1313 uint8_t* startByte;
1314
1315 for (uint32_t i = 0; i < length; ++i) {
1316 uint8_t idx = static_cast<uint8_t>(value[i]);
1317 uint8_t huffLength = HuffmanOutgoing[idx].mLength;
1318 uint32_t huffValue = HuffmanOutgoing[idx].mValue;
1319
1320 if (bitsLeft < 8) {
1321 // Fill in the least significant <bitsLeft> bits of the previous byte
1322 // first
1323 uint32_t val;
1324 if (huffLength >= bitsLeft) {
1325 val = huffValue & ~((1 << (huffLength - bitsLeft)) - 1);
1326 val >>= (huffLength - bitsLeft);
1327 } else {
1328 val = huffValue << (bitsLeft - huffLength);
1329 }
1330 val &= ((1 << bitsLeft) - 1);
1331 offset = buf.Length() - 1;
1332 startByte = reinterpret_cast<unsigned char*>(buf.BeginWriting()) + offset;
1333 *startByte = *startByte | static_cast<uint8_t>(val & 0xFF);
1334 if (huffLength >= bitsLeft) {
1335 huffLength -= bitsLeft;
1336 bitsLeft = 8;
1337 } else {
1338 bitsLeft -= huffLength;
1339 huffLength = 0;
1340 }
1341 }
1342
1343 while (huffLength >= 8) {
1344 uint32_t mask = ~((1 << (huffLength - 8)) - 1);
1345 uint8_t val = ((huffValue & mask) >> (huffLength - 8)) & 0xFF;
1346 buf.Append(reinterpret_cast<char*>(&val), 1);
1347 huffLength -= 8;
1348 }
1349
1350 if (huffLength) {
1351 // Fill in the most significant <huffLength> bits of the next byte
1352 bitsLeft = 8 - huffLength;
1353 uint8_t val = (huffValue & ((1 << huffLength) - 1)) << bitsLeft;
1354 buf.Append(reinterpret_cast<char*>(&val), 1);
1355 }
1356 }
1357
1358 if (bitsLeft != 8) {
1359 // Pad the last <bitsLeft> bits with ones, which corresponds to the EOS
1360 // encoding
1361 uint8_t val = (1 << bitsLeft) - 1;
1362 offset = buf.Length() - 1;
1363 startByte = reinterpret_cast<unsigned char*>(buf.BeginWriting()) + offset;
1364 *startByte = *startByte | val;
1365 }
1366
1367 // Now we know how long our encoded string is, we can fill in our length
1368 uint32_t bufLength = buf.Length();
1369 offset = mOutput->Length();
1370 EncodeInteger(7, bufLength);
1371 startByte =
1372 reinterpret_cast<unsigned char*>(mOutput->BeginWriting()) + offset;
1373 *startByte = *startByte | 0x80;
1374
1375 // Finally, we can add our REAL data!
1376 mOutput->Append(buf);
1377 LOG(do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Http2Compressor::HuffmanAppend %p encoded %d byte original on %d "
"bytes.\n", this, length, bufLength); } } while (0)
1378 ("Http2Compressor::HuffmanAppend %p encoded %d byte original on %d "do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Http2Compressor::HuffmanAppend %p encoded %d byte original on %d "
"bytes.\n", this, length, bufLength); } } while (0)
1379 "bytes.\n",do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Http2Compressor::HuffmanAppend %p encoded %d byte original on %d "
"bytes.\n", this, length, bufLength); } } while (0)
1380 this, length, bufLength))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Http2Compressor::HuffmanAppend %p encoded %d byte original on %d "
"bytes.\n", this, length, bufLength); } } while (0)
;
1381}
1382
1383void Http2Compressor::ProcessHeader(const nvPair inputPair, bool noLocalIndex,
1384 bool neverIndex) {
1385 uint32_t newSize = inputPair.Size();
1386 uint32_t headerTableSize = mHeaderTable.Length();
1387 uint32_t matchedIndex = 0u;
1388 uint32_t nameReference = 0u;
1389 bool match = false;
1390
1391 LOG(("Http2Compressor::ProcessHeader %s %s", inputPair.mName.get(),do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Http2Compressor::ProcessHeader %s %s", inputPair.mName.get
(), inputPair.mValue.get()); } } while (0)
1392 inputPair.mValue.get()))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "Http2Compressor::ProcessHeader %s %s", inputPair.mName.get
(), inputPair.mValue.get()); } } while (0)
;
1393
1394 // NWGH - make this index = 1; index <= headerTableSize; ++index
1395 for (uint32_t index = 0; index < headerTableSize; ++index) {
1396 if (mHeaderTable[index]->mName.Equals(inputPair.mName)) {
1397 // NWGH - make this nameReference = index
1398 nameReference = index + 1;
1399 if (mHeaderTable[index]->mValue.Equals(inputPair.mValue)) {
1400 match = true;
1401 matchedIndex = index;
1402 break;
1403 }
1404 }
1405 }
1406
1407 // We need to emit a new literal
1408 if (!match || noLocalIndex || neverIndex) {
1409 if (neverIndex) {
1410 DoOutput(kNeverIndexedLiteral, &inputPair, nameReference);
1411 DumpState("Compressor state after literal never index");
1412 return;
1413 }
1414
1415 if (noLocalIndex || (newSize > (mMaxBuffer / 2)) || (mMaxBuffer < 128)) {
1416 DoOutput(kPlainLiteral, &inputPair, nameReference);
1417 DumpState("Compressor state after literal without index");
1418 return;
1419 }
1420
1421 // make sure to makeroom() first so that any implied items
1422 // get preserved.
1423 MakeRoom(newSize, "compressor");
1424 DoOutput(kIndexedLiteral, &inputPair, nameReference);
1425
1426 mHeaderTable.AddElement(inputPair.mName, inputPair.mValue);
1427 LOG(("HTTP compressor %p new literal placed at index 0\n", this))do { const ::mozilla::LogModule* moz_real_module = mozilla::net
::gHttpLog; if ((__builtin_expect(!!(mozilla::detail::log_test
(moz_real_module, mozilla::LogLevel::Verbose)), 0))) { mozilla
::detail::log_print(moz_real_module, mozilla::LogLevel::Verbose
, "HTTP compressor %p new literal placed at index 0\n", this)
; } } while (0)
;
1428 DumpState("Compressor state after literal with index");
1429 return;
1430 }
1431
1432 // emit an index
1433 DoOutput(kIndex, &inputPair, matchedIndex);
1434
1435 DumpState("Compressor state after index");
1436}
1437
1438void Http2Compressor::EncodeTableSizeChange(uint32_t newMaxSize) {
1439 uint32_t offset = mOutput->Length();
1440 EncodeInteger(5, newMaxSize);
1441 uint8_t* startByte =
1442 reinterpret_cast<uint8_t*>(mOutput->BeginWriting()) + offset;
1443 *startByte = *startByte | 0x20;
1444}
1445
1446void Http2Compressor::SetMaxBufferSize(uint32_t maxBufferSize) {
1447 mMaxBufferSetting = maxBufferSize;
1448 SetMaxBufferSizeInternal(maxBufferSize);
1449 if (!mBufferSizeChangeWaiting) {
1450 mBufferSizeChangeWaiting = true;
1451 mLowestBufferSizeWaiting = maxBufferSize;
1452 } else if (maxBufferSize < mLowestBufferSizeWaiting) {
1453 mLowestBufferSizeWaiting = maxBufferSize;
1454 }
1455}
1456
1457} // namespace net
1458} // namespace mozilla