Bug Summary

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