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