Bug Summary

File:root/firefox-clang/obj-x86_64-pc-linux-gnu/toolkit/components/url-classifier/./../../../../toolkit/components/url-classifier/ProtocolParser.cpp
Warning:line 1212, column 7
Value stored to 'rv' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -cc1 -triple x86_64-pc-linux-gnu -O2 -analyze -disable-free -clear-ast-before-backend -disable-llvm-verifier -discard-value-names -main-file-name Unified_cpp_url-classifier0.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -ffp-contract=off -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/toolkit/components/url-classifier -fcoverage-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/toolkit/components/url-classifier -resource-dir /usr/lib/llvm-23/lib/clang/23 -include /root/firefox-clang/config/gcc_hidden.h -include /root/firefox-clang/obj-x86_64-pc-linux-gnu/mozilla-config.h -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/stl_wrappers -D _GLIBCXX_ASSERTIONS=1 -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/system_wrappers -U _FORTIFY_SOURCE -D _FORTIFY_SOURCE=2 -D DEBUG=1 -D GOOGLE_PROTOBUF_NO_RTTI -D GOOGLE_PROTOBUF_NO_STATIC_INITIALIZER -D MOZ_HAS_MOZGLUE -D MOZILLA_INTERNAL_API -D IMPL_LIBXUL -D MOZ_SUPPORT_LEAKCHECKING -D STATIC_EXPORTABLE_JS_API -I /root/firefox-clang/toolkit/components/url-classifier -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/toolkit/components/url-classifier -I /root/firefox-clang/toolkit/components/build -I /root/firefox-clang/xpcom/io -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/ipc/ipdl/_ipdlheaders -I /root/firefox-clang/ipc/chromium/src -I /root/firefox-clang/third_party/abseil-cpp -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nspr -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/include/nss -D MOZILLA_CLIENT -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/c++/16 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/x86_64-linux-gnu/c++/16 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../include/c++/16/backward -internal-isystem /usr/lib/llvm-23/lib/clang/23/include -internal-isystem /usr/local/include -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/16/../../../../x86_64-linux-gnu/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -Wno-error=pessimizing-move -Wno-error=large-by-value-copy=128 -Wno-error=implicit-int-float-conversion -Wno-error=thread-safety-analysis -Wno-error=tautological-type-limit-compare -Wno-invalid-offsetof -Wno-range-loop-analysis -Wno-deprecated-anon-enum-enum-conversion -Wno-deprecated-enum-enum-conversion -Wno-inline-new-delete -Wno-error=deprecated-declarations -Wno-error=array-bounds -Wno-error=free-nonheap-object -Wno-error=atomic-alignment -Wno-error=deprecated-builtins -Wno-psabi -Wno-error=builtin-macro-redefined -Wno-vla-cxx-extension -Wno-unknown-warning-option -Wno-character-conversion -std=gnu++20 -fdeprecated-macro -ferror-limit 19 -fstrict-flex-arrays=1 -stack-protector 2 -fstack-clash-protection -ftrivial-auto-var-init=pattern -fno-rtti -fgnuc-version=4.2.1 -fno-implicit-modules -fskip-odr-check-in-gmf -fno-sized-deallocation -fno-aligned-allocation -fdiagnostics-absolute-paths -vectorize-loops -vectorize-slp -analyzer-checker optin.performance.Padding -analyzer-output=html -analyzer-config stable-report-filename=true -mllvm -dwarf-linkage-names=Abstract -faddrsig -fdwarf2-cfi-asm -o /tmp/scan-build-2026-10-17-231001-351276-1 -x c++ Unified_cpp_url-classifier0.cpp
1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this
3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5#include "ProtocolParser.h"
6#include "Entries.h"
7#include "LookupCache.h"
8#include "nsNetCID.h"
9#include "mozilla/Components.h"
10#include "mozilla/Logging.h"
11#include "prnetdb.h"
12#include "prprf.h"
13#include "Classifier.h"
14
15#include "nsUrlClassifierDBService.h"
16#include "nsUrlClassifierUtils.h"
17#include "nsPrintfCString.h"
18#include "mozilla/Base64.h"
19#include "RiceDeltaDecoder.h"
20#include "mozilla/EndianUtils.h"
21#include "mozilla/ErrorNames.h"
22#include "mozilla/IntegerPrintfMacros.h"
23#include "nsCharSeparatedTokenizer.h"
24
25// MOZ_LOG=UrlClassifierProtocolParser:5
26extern mozilla::LazyLogModule gUrlClassifierDbServiceLog;
27mozilla::LazyLogModule gUrlClassifierProtocolParserLog(
28 "UrlClassifierProtocolParser");
29#define PARSER_LOG(args)do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, MOZ_LOG_EXPAND_ARGS
args); } } while (0)
\
30 MOZ_LOG(gUrlClassifierProtocolParserLog, mozilla::LogLevel::Debug, args)do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, MOZ_LOG_EXPAND_ARGS
args); } } while (0)
31
32#define LOG_ENABLED()(__builtin_expect(!!(mozilla::detail::log_test(gUrlClassifierDbServiceLog
, mozilla::LogLevel::Debug)), 0))
\
33 MOZ_LOG_TEST(gUrlClassifierDbServiceLog, mozilla::LogLevel::Debug)(__builtin_expect(!!(mozilla::detail::log_test(gUrlClassifierDbServiceLog
, mozilla::LogLevel::Debug)), 0))
34
35namespace mozilla {
36namespace safebrowsing {
37
38// Updates will fail if fed chunks larger than this
39const uint32_t MAX_CHUNK_SIZE = (4 * 1024 * 1024);
40// Updates will fail if the total number of tocuhed chunks is larger than this
41const uint32_t MAX_CHUNK_RANGE = 1000000;
42
43const uint32_t DOMAIN_SIZE = 4;
44
45// Parse one stringified range of chunks of the form "n" or "n-m" from a
46// comma-separated list of chunks. Upon return, 'begin' will point to the
47// next range of chunks in the list of chunks.
48static bool ParseChunkRange(const nsAutoCString& string, uint32_t* aFirst,
49 uint32_t* aLast) {
50 uint32_t numRead = PR_sscanf(string.get(), "%u-%u", aFirst, aLast);
51 if (numRead == 2) {
52 if (*aFirst > *aLast) {
53 uint32_t tmp = *aFirst;
54 *aFirst = *aLast;
55 *aLast = tmp;
56 }
57 return true;
58 }
59
60 if (numRead == 1) {
61 *aLast = *aFirst;
62 return true;
63 }
64
65 return false;
66}
67
68///////////////////////////////////////////////////////////////
69// ProtocolParser implementation
70
71ProtocolParser::ProtocolParser() : mUpdateStatus(NS_OK), mUpdateWaitSec(0) {}
72
73ProtocolParser::~ProtocolParser() = default;
74
75nsTArray<TableWaitDuration> ProtocolParser::TakeUpdateWaits() {
76 // V5: the response carries a duration per hash list, so hand over the ones
77 // that were parsed.
78 if (!mUpdateWaits.IsEmpty()) {
79 return std::move(mUpdateWaits);
80 }
81
82 // V2 and V4: the response carries a single duration, which applies to every
83 // table we asked for.
84 nsTArray<TableWaitDuration> waits(mRequestedTables.Length());
85 for (const auto& table : mRequestedTables) {
86 waits.AppendElement(TableWaitDuration{table, mUpdateWaitSec});
87 }
88 return waits;
89}
90
91nsresult ProtocolParser::Begin(const nsACString& aTable,
92 const nsTArray<nsCString>& aUpdateTables) {
93 // ProtocolParser objects should never be reused.
94 MOZ_ASSERT(mPending.IsEmpty())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mPending.IsEmpty())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mPending.IsEmpty()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("mPending.IsEmpty()"
, "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 94); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mPending.IsEmpty()"
")"); do { MOZ_CrashSequence(__null, 94); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
95 MOZ_ASSERT(mTableUpdates.IsEmpty())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mTableUpdates.IsEmpty())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mTableUpdates.IsEmpty()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("mTableUpdates.IsEmpty()"
, "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 95); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mTableUpdates.IsEmpty()"
")"); do { MOZ_CrashSequence(__null, 95); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
96 MOZ_ASSERT(mForwards.IsEmpty())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mForwards.IsEmpty())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mForwards.IsEmpty()))), 0)))
{ do { } while (false); MOZ_ReportAssertionFailure("mForwards.IsEmpty()"
, "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 96); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mForwards.IsEmpty()"
")"); do { MOZ_CrashSequence(__null, 96); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
97 MOZ_ASSERT(mRequestedTables.IsEmpty())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mRequestedTables.IsEmpty())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mRequestedTables.IsEmpty()))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("mRequestedTables.IsEmpty()"
, "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 97); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mRequestedTables.IsEmpty()"
")"); do { MOZ_CrashSequence(__null, 97); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
98 MOZ_ASSERT(mTablesToReset.IsEmpty())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mTablesToReset.IsEmpty())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mTablesToReset.IsEmpty()))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("mTablesToReset.IsEmpty()"
, "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 98); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mTablesToReset.IsEmpty()"
")"); do { MOZ_CrashSequence(__null, 98); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
99 MOZ_ASSERT(mUpdateWaits.IsEmpty())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mUpdateWaits.IsEmpty())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mUpdateWaits.IsEmpty()))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("mUpdateWaits.IsEmpty()"
, "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 99); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mUpdateWaits.IsEmpty()"
")"); do { MOZ_CrashSequence(__null, 99); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
100
101 if (!aTable.IsEmpty()) {
102 SetCurrentTable(aTable);
103 }
104 SetRequestedTables(aUpdateTables);
105
106 return NS_OK;
107}
108
109RefPtr<TableUpdate> ProtocolParser::GetTableUpdate(const nsACString& aTable) {
110 for (uint32_t i = 0; i < mTableUpdates.Length(); i++) {
111 if (aTable.Equals(mTableUpdates[i]->TableName())) {
112 return mTableUpdates[i];
113 }
114 }
115
116 // We free automatically on destruction, ownership of these
117 // updates can be transferred to DBServiceWorker, which passes
118 // them back to Classifier when doing the updates, and that
119 // will free them.
120 RefPtr<TableUpdate> update = CreateTableUpdate(aTable);
121 mTableUpdates.AppendElement(update);
122 return update;
123}
124
125///////////////////////////////////////////////////////////////////////
126// ProtocolParserV2
127
128ProtocolParserV2::ProtocolParserV2()
129 : mState(PROTOCOL_STATE_CONTROL), mTableUpdate(nullptr) {}
130
131ProtocolParserV2::~ProtocolParserV2() = default;
132
133void ProtocolParserV2::SetCurrentTable(const nsACString& aTable) {
134 RefPtr<TableUpdate> update = GetTableUpdate(aTable);
135 mTableUpdate = TableUpdate::Cast<TableUpdateV2>(update);
136}
137
138nsresult ProtocolParserV2::AppendStream(const nsACString& aData) {
139 if (NS_FAILED(mUpdateStatus)((bool)(__builtin_expect(!!(NS_FAILED_impl(mUpdateStatus)), 0
)))
) return mUpdateStatus;
140
141 nsresult rv;
142 if (!mPending.Append(aData, mozilla::fallible)) {
143 return NS_ERROR_OUT_OF_MEMORY;
144 }
145
146 bool done = false;
147 while (!done) {
148 if (nsUrlClassifierDBService::ShutdownHasStarted()) {
149 return NS_ERROR_ABORT;
150 }
151
152 if (mState == PROTOCOL_STATE_CONTROL) {
153 rv = ProcessControl(&done);
154 } else if (mState == PROTOCOL_STATE_CHUNK) {
155 rv = ProcessChunk(&done);
156 } else {
157 NS_ERROR("Unexpected protocol state")do { NS_DebugBreak(NS_DEBUG_ASSERTION, "Unexpected protocol state"
, "Error", "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 157); MOZ_PretendNoReturn(); } while (0)
;
158 rv = NS_ERROR_FAILURE;
159 }
160 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
161 mUpdateStatus = rv;
162 return rv;
163 }
164 }
165 return NS_OK;
166}
167
168void ProtocolParserV2::End() {
169 // Inbound data has already been processed in every AppendStream() call.
170 mTableUpdate = nullptr;
171}
172
173nsresult ProtocolParserV2::ProcessControl(bool* aDone) {
174 nsresult rv;
175
176 nsAutoCString line;
177 *aDone = true;
178 while (NextLine(line)) {
179 PARSER_LOG(("Processing %s\n", line.get()))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Processing %s\n"
, line.get()); } } while (0)
;
180
181 if (StringBeginsWith(line, "i:"_ns)) {
182 // Set the table name from the table header line.
183 SetCurrentTable(Substring(line, 2));
184 } else if (StringBeginsWith(line, "n:"_ns)) {
185 if (PR_sscanf(line.get(), "n:%d", &mUpdateWaitSec) != 1) {
186 PARSER_LOG(("Error parsing n: '%s' (%d)", line.get(), mUpdateWaitSec))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Error parsing n: '%s' (%d)"
, line.get(), mUpdateWaitSec); } } while (0)
;
187 return NS_ERROR_FAILURE;
188 }
189 } else if (line.EqualsLiteral("r:pleasereset")) {
190 PARSER_LOG(("All tables will be reset."))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "All tables will be reset."
); } } while (0)
;
191 mTablesToReset = mRequestedTables.Clone();
192 } else if (StringBeginsWith(line, "u:"_ns)) {
193 rv = ProcessForward(line);
194 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 194); return rv; } } while (false)
;
195 } else if (StringBeginsWith(line, "a:"_ns) ||
196 StringBeginsWith(line, "s:"_ns)) {
197 rv = ProcessChunkControl(line);
198 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 198); return rv; } } while (false)
;
199 *aDone = false;
200 return NS_OK;
201 } else if (StringBeginsWith(line, "ad:"_ns) ||
202 StringBeginsWith(line, "sd:"_ns)) {
203 rv = ProcessExpirations(line);
204 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 204); return rv; } } while (false)
;
205 }
206 }
207
208 *aDone = true;
209 return NS_OK;
210}
211
212nsresult ProtocolParserV2::ProcessExpirations(const nsCString& aLine) {
213 if (!mTableUpdate) {
214 NS_WARNING("Got an expiration without a table.")NS_DebugBreak(NS_DEBUG_WARNING, "Got an expiration without a table."
, nullptr, "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 214)
;
215 return NS_ERROR_FAILURE;
216 }
217 const nsACString& list = Substring(aLine, 3);
218 for (const auto& str : list.Split(',')) {
219 uint32_t first, last;
220 if (ParseChunkRange(nsAutoCString(str), &first, &last)) {
221 if (last < first) return NS_ERROR_FAILURE;
222 if (last - first > MAX_CHUNK_RANGE) return NS_ERROR_FAILURE;
223 for (uint32_t num = first; num <= last; num++) {
224 if (aLine[0] == 'a') {
225 nsresult rv = mTableUpdate->NewAddExpiration(num);
226 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
227 return rv;
228 }
229 } else {
230 nsresult rv = mTableUpdate->NewSubExpiration(num);
231 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
232 return rv;
233 }
234 }
235 }
236 } else {
237 return NS_ERROR_FAILURE;
238 }
239 }
240 return NS_OK;
241}
242
243nsresult ProtocolParserV2::ProcessChunkControl(const nsCString& aLine) {
244 if (!mTableUpdate) {
245 NS_WARNING("Got a chunk before getting a table.")NS_DebugBreak(NS_DEBUG_WARNING, "Got a chunk before getting a table."
, nullptr, "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 245)
;
246 return NS_ERROR_FAILURE;
247 }
248
249 mState = PROTOCOL_STATE_CHUNK;
250 char command;
251
252 mChunkState.Clear();
253
254 if (PR_sscanf(aLine.get(), "%c:%d:%d:%d", &command, &mChunkState.num,
255 &mChunkState.hashSize, &mChunkState.length) != 4) {
256 NS_WARNING(("PR_sscanf failed"))NS_DebugBreak(NS_DEBUG_WARNING, ("PR_sscanf failed"), nullptr
, "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 256)
;
257 return NS_ERROR_FAILURE;
258 }
259
260 if (mChunkState.length > MAX_CHUNK_SIZE) {
261 NS_WARNING("Invalid length specified in update.")NS_DebugBreak(NS_DEBUG_WARNING, "Invalid length specified in update."
, nullptr, "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 261)
;
262 return NS_ERROR_FAILURE;
263 }
264
265 if (!(mChunkState.hashSize == PREFIX_SIZE4 ||
266 mChunkState.hashSize == COMPLETE_SIZE32)) {
267 NS_WARNING("Invalid hash size specified in update.")NS_DebugBreak(NS_DEBUG_WARNING, "Invalid hash size specified in update."
, nullptr, "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 267)
;
268 return NS_ERROR_FAILURE;
269 }
270
271 if (StringEndsWith(mTableUpdate->TableName(), "-shavar"_ns) ||
272 StringEndsWith(mTableUpdate->TableName(), "-simple"_ns)) {
273 // Accommodate test tables ending in -simple for now.
274 mChunkState.type = (command == 'a') ? CHUNK_ADD : CHUNK_SUB;
275 } else if (StringEndsWith(mTableUpdate->TableName(), "-digest256"_ns)) {
276 mChunkState.type = (command == 'a') ? CHUNK_ADD_DIGEST : CHUNK_SUB_DIGEST;
277 }
278 nsresult rv;
279 switch (mChunkState.type) {
280 case CHUNK_ADD:
281 rv = mTableUpdate->NewAddChunk(mChunkState.num);
282 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
283 return rv;
284 }
285 break;
286 case CHUNK_SUB:
287 rv = mTableUpdate->NewSubChunk(mChunkState.num);
288 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
289 return rv;
290 }
291 break;
292 case CHUNK_ADD_DIGEST:
293 rv = mTableUpdate->NewAddChunk(mChunkState.num);
294 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
295 return rv;
296 }
297 break;
298 case CHUNK_SUB_DIGEST:
299 rv = mTableUpdate->NewSubChunk(mChunkState.num);
300 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
301 return rv;
302 }
303 break;
304 }
305
306 return NS_OK;
307}
308
309nsresult ProtocolParserV2::ProcessForward(const nsCString& aLine) {
310 const nsACString& forward = Substring(aLine, 2);
311 return AddForward(forward);
312}
313
314nsresult ProtocolParserV2::AddForward(const nsACString& aUrl) {
315 if (!mTableUpdate) {
316 NS_WARNING("Forward without a table name.")NS_DebugBreak(NS_DEBUG_WARNING, "Forward without a table name."
, nullptr, "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 316)
;
317 return NS_ERROR_FAILURE;
318 }
319
320 ForwardedUpdate* forward = mForwards.AppendElement();
321 forward->table = mTableUpdate->TableName();
322 forward->url.Assign(aUrl);
323
324 return NS_OK;
325}
326
327nsresult ProtocolParserV2::ProcessChunk(bool* aDone) {
328 if (!mTableUpdate) {
329 NS_WARNING("Processing chunk without an active table.")NS_DebugBreak(NS_DEBUG_WARNING, "Processing chunk without an active table."
, nullptr, "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 329)
;
330 return NS_ERROR_FAILURE;
331 }
332
333 NS_ASSERTION(mChunkState.num != 0, "Must have a chunk number.")do { if (!(mChunkState.num != 0)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Must have a chunk number.", "mChunkState.num != 0", "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 333); MOZ_PretendNoReturn(); } } while (0)
;
334
335 if (mPending.Length() < mChunkState.length) {
336 *aDone = true;
337 return NS_OK;
338 }
339
340 // Pull the chunk out of the pending stream data.
341 nsAutoCString chunk;
342 chunk.Assign(Substring(mPending, 0, mChunkState.length));
343 mPending.Cut(0, mChunkState.length);
344
345 *aDone = false;
346 mState = PROTOCOL_STATE_CONTROL;
347
348 if (StringEndsWith(mTableUpdate->TableName(), "-shavar"_ns)) {
349 return ProcessShaChunk(chunk);
350 }
351 if (StringEndsWith(mTableUpdate->TableName(), "-digest256"_ns)) {
352 return ProcessDigestChunk(chunk);
353 }
354 return ProcessPlaintextChunk(chunk);
355}
356
357/**
358 * Process a plaintext chunk (currently only used in unit tests).
359 */
360nsresult ProtocolParserV2::ProcessPlaintextChunk(const nsACString& aChunk) {
361 if (!mTableUpdate) {
362 NS_WARNING("Chunk received with no table.")NS_DebugBreak(NS_DEBUG_WARNING, "Chunk received with no table."
, nullptr, "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 362)
;
363 return NS_ERROR_FAILURE;
364 }
365
366 PARSER_LOG(("Handling a %zd-byte simple chunk", aChunk.Length()))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Handling a %zd-byte simple chunk"
, aChunk.Length()); } } while (0)
;
367
368 nsTArray<nsCString> lines;
369 ParseString(PromiseFlatCStringTPromiseFlatString<char>(aChunk), '\n', lines);
370
371 // non-hashed tables need to be hashed
372 for (uint32_t i = 0; i < lines.Length(); i++) {
373 nsCString& line = lines[i];
374
375 if (mChunkState.type == CHUNK_ADD) {
376 if (mChunkState.hashSize == COMPLETE_SIZE32) {
377 Completion hash;
378 hash.FromPlaintext(line);
379 nsresult rv = mTableUpdate->NewAddComplete(mChunkState.num, hash);
380 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
381 return rv;
382 }
383 } else {
384 NS_ASSERTION(mChunkState.hashSize == 4,do { if (!(mChunkState.hashSize == 4)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Only 32- or 4-byte hashes can be used for add chunks.", "mChunkState.hashSize == 4"
, "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 385); MOZ_PretendNoReturn(); } } while (0)
385 "Only 32- or 4-byte hashes can be used for add chunks.")do { if (!(mChunkState.hashSize == 4)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Only 32- or 4-byte hashes can be used for add chunks.", "mChunkState.hashSize == 4"
, "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 385); MOZ_PretendNoReturn(); } } while (0)
;
386 Prefix hash;
387 hash.FromPlaintext(line);
388 nsresult rv = mTableUpdate->NewAddPrefix(mChunkState.num, hash);
389 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
390 return rv;
391 }
392 }
393 } else {
394 nsCString::const_iterator begin, iter, end;
395 line.BeginReading(begin);
396 line.EndReading(end);
397 iter = begin;
398 uint32_t addChunk;
399 if (!FindCharInReadable(':', iter, end) ||
400 PR_sscanf(lines[i].get(), "%d:", &addChunk) != 1) {
401 NS_WARNING("Received sub chunk without associated add chunk.")NS_DebugBreak(NS_DEBUG_WARNING, "Received sub chunk without associated add chunk."
, nullptr, "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 401)
;
402 return NS_ERROR_FAILURE;
403 }
404 iter++;
405
406 if (mChunkState.hashSize == COMPLETE_SIZE32) {
407 Completion hash;
408 hash.FromPlaintext(Substring(iter, end));
409 nsresult rv =
410 mTableUpdate->NewSubComplete(addChunk, hash, mChunkState.num);
411 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
412 return rv;
413 }
414 } else {
415 NS_ASSERTION(mChunkState.hashSize == 4,do { if (!(mChunkState.hashSize == 4)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Only 32- or 4-byte hashes can be used for add chunks.", "mChunkState.hashSize == 4"
, "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 416); MOZ_PretendNoReturn(); } } while (0)
416 "Only 32- or 4-byte hashes can be used for add chunks.")do { if (!(mChunkState.hashSize == 4)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "Only 32- or 4-byte hashes can be used for add chunks.", "mChunkState.hashSize == 4"
, "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 416); MOZ_PretendNoReturn(); } } while (0)
;
417 Prefix hash;
418 hash.FromPlaintext(Substring(iter, end));
419 nsresult rv =
420 mTableUpdate->NewSubPrefix(addChunk, hash, mChunkState.num);
421 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
422 return rv;
423 }
424 }
425 }
426 }
427
428 return NS_OK;
429}
430
431nsresult ProtocolParserV2::ProcessShaChunk(const nsACString& aChunk) {
432 uint32_t start = 0;
433 while (start < aChunk.Length()) {
434 // Each chunk must be at least 5 bytes (domain + count))
435 if (aChunk.Length() - start < DOMAIN_SIZE + 1) {
436 NS_WARNING("Chunk is not long enough to contain the record header.")NS_DebugBreak(NS_DEBUG_WARNING, "Chunk is not long enough to contain the record header."
, nullptr, "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 436)
;
437 return NS_ERROR_FAILURE;
438 }
439
440 // First four bytes are the domain key.
441 Prefix domain;
442 domain.Assign(Substring(aChunk, start, DOMAIN_SIZE));
443 start += DOMAIN_SIZE;
444
445 // Then a count of entries.
446 uint8_t numEntries = static_cast<uint8_t>(aChunk[start]);
447 start++;
448
449 PARSER_LOG(do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Handling a %zd-byte shavar chunk containing %u entries"
" for domain %X", aChunk.Length(), numEntries, domain.ToUint32
()); } } while (0)
450 ("Handling a %zd-byte shavar chunk containing %u entries"do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Handling a %zd-byte shavar chunk containing %u entries"
" for domain %X", aChunk.Length(), numEntries, domain.ToUint32
()); } } while (0)
451 " for domain %X",do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Handling a %zd-byte shavar chunk containing %u entries"
" for domain %X", aChunk.Length(), numEntries, domain.ToUint32
()); } } while (0)
452 aChunk.Length(), numEntries, domain.ToUint32()))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Handling a %zd-byte shavar chunk containing %u entries"
" for domain %X", aChunk.Length(), numEntries, domain.ToUint32
()); } } while (0)
;
453
454 nsresult rv;
455 if (mChunkState.type == CHUNK_ADD && mChunkState.hashSize == PREFIX_SIZE4) {
456 rv = ProcessHostAdd(domain, numEntries, aChunk, &start);
457 } else if (mChunkState.type == CHUNK_ADD &&
458 mChunkState.hashSize == COMPLETE_SIZE32) {
459 rv = ProcessHostAddComplete(numEntries, aChunk, &start);
460 } else if (mChunkState.type == CHUNK_SUB &&
461 mChunkState.hashSize == PREFIX_SIZE4) {
462 rv = ProcessHostSub(domain, numEntries, aChunk, &start);
463 } else if (mChunkState.type == CHUNK_SUB &&
464 mChunkState.hashSize == COMPLETE_SIZE32) {
465 rv = ProcessHostSubComplete(numEntries, aChunk, &start);
466 } else {
467 NS_WARNING("Unexpected chunk type/hash size!")NS_DebugBreak(NS_DEBUG_WARNING, "Unexpected chunk type/hash size!"
, nullptr, "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 467)
;
468 PARSER_LOG(("Got an unexpected chunk type/hash size: %s:%d",do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Got an unexpected chunk type/hash size: %s:%d"
, mChunkState.type == CHUNK_ADD ? "add" : "sub", mChunkState.
hashSize); } } while (0)
469 mChunkState.type == CHUNK_ADD ? "add" : "sub",do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Got an unexpected chunk type/hash size: %s:%d"
, mChunkState.type == CHUNK_ADD ? "add" : "sub", mChunkState.
hashSize); } } while (0)
470 mChunkState.hashSize))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Got an unexpected chunk type/hash size: %s:%d"
, mChunkState.type == CHUNK_ADD ? "add" : "sub", mChunkState.
hashSize); } } while (0)
;
471 return NS_ERROR_FAILURE;
472 }
473 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 473); return rv; } } while (false)
;
474 }
475
476 return NS_OK;
477}
478
479nsresult ProtocolParserV2::ProcessDigestChunk(const nsACString& aChunk) {
480 PARSER_LOG(("Handling a %zd-byte digest256 chunk", aChunk.Length()))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Handling a %zd-byte digest256 chunk"
, aChunk.Length()); } } while (0)
;
481
482 if (mChunkState.type == CHUNK_ADD_DIGEST) {
483 return ProcessDigestAdd(aChunk);
484 }
485 if (mChunkState.type == CHUNK_SUB_DIGEST) {
486 return ProcessDigestSub(aChunk);
487 }
488 return NS_ERROR_UNEXPECTED;
489}
490
491nsresult ProtocolParserV2::ProcessDigestAdd(const nsACString& aChunk) {
492 MOZ_ASSERT(mTableUpdate)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mTableUpdate)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mTableUpdate))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("mTableUpdate", "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 492); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mTableUpdate"
")"); do { MOZ_CrashSequence(__null, 492); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
493 // The ABNF format for add chunks is (HASH)+, where HASH is 32 bytes.
494 if (aChunk.Length() % COMPLETE_SIZE32 != 0) {
495 NS_WARNING("Chunk length in bytes must be divisible by 32")NS_DebugBreak(NS_DEBUG_WARNING, "Chunk length in bytes must be divisible by 32"
, nullptr, "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 495)
;
496 return NS_ERROR_FAILURE;
497 }
498 uint32_t start = 0;
499 while (start < aChunk.Length()) {
500 Completion hash;
501 hash.Assign(Substring(aChunk, start, COMPLETE_SIZE32));
502 start += COMPLETE_SIZE32;
503 nsresult rv = mTableUpdate->NewAddComplete(mChunkState.num, hash);
504 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
505 return rv;
506 }
507 }
508 return NS_OK;
509}
510
511nsresult ProtocolParserV2::ProcessDigestSub(const nsACString& aChunk) {
512 MOZ_ASSERT(mTableUpdate)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mTableUpdate)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mTableUpdate))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("mTableUpdate", "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 512); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mTableUpdate"
")"); do { MOZ_CrashSequence(__null, 512); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
513 // The ABNF format for sub chunks is (ADDCHUNKNUM HASH)+, where ADDCHUNKNUM
514 // is a 4 byte chunk number, and HASH is 32 bytes.
515 if (aChunk.Length() % (4 + COMPLETE_SIZE32) != 0) {
516 NS_WARNING("Chunk length in bytes must be divisible by 36")NS_DebugBreak(NS_DEBUG_WARNING, "Chunk length in bytes must be divisible by 36"
, nullptr, "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 516)
;
517 return NS_ERROR_FAILURE;
518 }
519 uint32_t start = 0;
520 while (start < aChunk.Length()) {
521 // Read ADDCHUNKNUM
522 const nsACString& addChunkStr = Substring(aChunk, start, 4);
523 start += 4;
524
525 uint32_t addChunk;
526 memcpy(&addChunk, addChunkStr.BeginReading(), 4);
527 addChunk = PR_ntohl(addChunk);
528
529 // Read the hash
530 Completion hash;
531 hash.Assign(Substring(aChunk, start, COMPLETE_SIZE32));
532 start += COMPLETE_SIZE32;
533
534 nsresult rv = mTableUpdate->NewSubComplete(addChunk, hash, mChunkState.num);
535 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
536 return rv;
537 }
538 }
539 return NS_OK;
540}
541
542nsresult ProtocolParserV2::ProcessHostAdd(const Prefix& aDomain,
543 uint8_t aNumEntries,
544 const nsACString& aChunk,
545 uint32_t* aStart) {
546 MOZ_ASSERT(mTableUpdate)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mTableUpdate)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mTableUpdate))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("mTableUpdate", "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 546); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mTableUpdate"
")"); do { MOZ_CrashSequence(__null, 546); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
547 NS_ASSERTION(mChunkState.hashSize == PREFIX_SIZE,do { if (!(mChunkState.hashSize == 4)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "ProcessHostAdd should only be called for prefix hashes.", "mChunkState.hashSize == PREFIX_SIZE"
, "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 548); MOZ_PretendNoReturn(); } } while (0)
548 "ProcessHostAdd should only be called for prefix hashes.")do { if (!(mChunkState.hashSize == 4)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "ProcessHostAdd should only be called for prefix hashes.", "mChunkState.hashSize == PREFIX_SIZE"
, "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 548); MOZ_PretendNoReturn(); } } while (0)
;
549
550 if (aNumEntries == 0) {
551 nsresult rv = mTableUpdate->NewAddPrefix(mChunkState.num, aDomain);
552 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
553 return rv;
554 }
555 return NS_OK;
556 }
557
558 if (*aStart + (PREFIX_SIZE4 * aNumEntries) > aChunk.Length()) {
559 NS_WARNING("Chunk is not long enough to contain the expected entries.")NS_DebugBreak(NS_DEBUG_WARNING, "Chunk is not long enough to contain the expected entries."
, nullptr, "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 559)
;
560 return NS_ERROR_FAILURE;
561 }
562
563 for (uint8_t i = 0; i < aNumEntries; i++) {
564 Prefix hash;
565 hash.Assign(Substring(aChunk, *aStart, PREFIX_SIZE4));
566 PARSER_LOG(("Add prefix %X", hash.ToUint32()))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Add prefix %X", hash
.ToUint32()); } } while (0)
;
567 nsresult rv = mTableUpdate->NewAddPrefix(mChunkState.num, hash);
568 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
569 return rv;
570 }
571 *aStart += PREFIX_SIZE4;
572 }
573
574 return NS_OK;
575}
576
577nsresult ProtocolParserV2::ProcessHostSub(const Prefix& aDomain,
578 uint8_t aNumEntries,
579 const nsACString& aChunk,
580 uint32_t* aStart) {
581 MOZ_ASSERT(mTableUpdate)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mTableUpdate)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mTableUpdate))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("mTableUpdate", "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 581); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mTableUpdate"
")"); do { MOZ_CrashSequence(__null, 581); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
582 NS_ASSERTION(mChunkState.hashSize == PREFIX_SIZE,do { if (!(mChunkState.hashSize == 4)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "ProcessHostSub should only be called for prefix hashes.", "mChunkState.hashSize == PREFIX_SIZE"
, "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 583); MOZ_PretendNoReturn(); } } while (0)
583 "ProcessHostSub should only be called for prefix hashes.")do { if (!(mChunkState.hashSize == 4)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "ProcessHostSub should only be called for prefix hashes.", "mChunkState.hashSize == PREFIX_SIZE"
, "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 583); MOZ_PretendNoReturn(); } } while (0)
;
584
585 if (aNumEntries == 0) {
586 if ((*aStart) + 4 > aChunk.Length()) {
587 NS_WARNING("Received a zero-entry sub chunk without an associated add.")NS_DebugBreak(NS_DEBUG_WARNING, "Received a zero-entry sub chunk without an associated add."
, nullptr, "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 587)
;
588 return NS_ERROR_FAILURE;
589 }
590
591 const nsACString& addChunkStr = Substring(aChunk, *aStart, 4);
592 *aStart += 4;
593
594 uint32_t addChunk;
595 memcpy(&addChunk, addChunkStr.BeginReading(), 4);
596 addChunk = PR_ntohl(addChunk);
597
598 PARSER_LOG(("Sub prefix (addchunk=%u)", addChunk))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Sub prefix (addchunk=%u)"
, addChunk); } } while (0)
;
599 nsresult rv =
600 mTableUpdate->NewSubPrefix(addChunk, aDomain, mChunkState.num);
601 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
602 return rv;
603 }
604 return NS_OK;
605 }
606
607 if (*aStart + ((PREFIX_SIZE4 + 4) * aNumEntries) > aChunk.Length()) {
608 NS_WARNING("Chunk is not long enough to contain the expected entries.")NS_DebugBreak(NS_DEBUG_WARNING, "Chunk is not long enough to contain the expected entries."
, nullptr, "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 608)
;
609 return NS_ERROR_FAILURE;
610 }
611
612 for (uint8_t i = 0; i < aNumEntries; i++) {
613 const nsACString& addChunkStr = Substring(aChunk, *aStart, 4);
614 *aStart += 4;
615
616 uint32_t addChunk;
617 memcpy(&addChunk, addChunkStr.BeginReading(), 4);
618 addChunk = PR_ntohl(addChunk);
619
620 Prefix prefix;
621 prefix.Assign(Substring(aChunk, *aStart, PREFIX_SIZE4));
622 *aStart += PREFIX_SIZE4;
623
624 PARSER_LOG(("Sub prefix %X (addchunk=%u)", prefix.ToUint32(), addChunk))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Sub prefix %X (addchunk=%u)"
, prefix.ToUint32(), addChunk); } } while (0)
;
625 nsresult rv = mTableUpdate->NewSubPrefix(addChunk, prefix, mChunkState.num);
626 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
627 return rv;
628 }
629 }
630
631 return NS_OK;
632}
633
634nsresult ProtocolParserV2::ProcessHostAddComplete(uint8_t aNumEntries,
635 const nsACString& aChunk,
636 uint32_t* aStart) {
637 MOZ_ASSERT(mTableUpdate)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mTableUpdate)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mTableUpdate))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("mTableUpdate", "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 637); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mTableUpdate"
")"); do { MOZ_CrashSequence(__null, 637); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
638 NS_ASSERTION(do { if (!(mChunkState.hashSize == 32)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "ProcessHostAddComplete should only be called for complete hashes."
, "mChunkState.hashSize == COMPLETE_SIZE", "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 640); MOZ_PretendNoReturn(); } } while (0)
639 mChunkState.hashSize == COMPLETE_SIZE,do { if (!(mChunkState.hashSize == 32)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "ProcessHostAddComplete should only be called for complete hashes."
, "mChunkState.hashSize == COMPLETE_SIZE", "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 640); MOZ_PretendNoReturn(); } } while (0)
640 "ProcessHostAddComplete should only be called for complete hashes.")do { if (!(mChunkState.hashSize == 32)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "ProcessHostAddComplete should only be called for complete hashes."
, "mChunkState.hashSize == COMPLETE_SIZE", "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 640); MOZ_PretendNoReturn(); } } while (0)
;
641
642 if (aNumEntries == 0) {
643 // this is totally comprehensible.
644 // My sarcasm detector is going off!
645 NS_WARNING("Expected > 0 entries for a 32-byte hash add.")NS_DebugBreak(NS_DEBUG_WARNING, "Expected > 0 entries for a 32-byte hash add."
, nullptr, "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 645)
;
646 return NS_OK;
647 }
648
649 if (*aStart + (COMPLETE_SIZE32 * aNumEntries) > aChunk.Length()) {
650 NS_WARNING("Chunk is not long enough to contain the expected entries.")NS_DebugBreak(NS_DEBUG_WARNING, "Chunk is not long enough to contain the expected entries."
, nullptr, "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 650)
;
651 return NS_ERROR_FAILURE;
652 }
653
654 for (uint8_t i = 0; i < aNumEntries; i++) {
655 Completion hash;
656 hash.Assign(Substring(aChunk, *aStart, COMPLETE_SIZE32));
657 nsresult rv = mTableUpdate->NewAddComplete(mChunkState.num, hash);
658 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
659 return rv;
660 }
661 *aStart += COMPLETE_SIZE32;
662 }
663
664 return NS_OK;
665}
666
667nsresult ProtocolParserV2::ProcessHostSubComplete(uint8_t aNumEntries,
668 const nsACString& aChunk,
669 uint32_t* aStart) {
670 MOZ_ASSERT(mTableUpdate)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mTableUpdate)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mTableUpdate))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("mTableUpdate", "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 670); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mTableUpdate"
")"); do { MOZ_CrashSequence(__null, 670); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
671 NS_ASSERTION(do { if (!(mChunkState.hashSize == 32)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "ProcessHostSubComplete should only be called for complete hashes."
, "mChunkState.hashSize == COMPLETE_SIZE", "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 673); MOZ_PretendNoReturn(); } } while (0)
672 mChunkState.hashSize == COMPLETE_SIZE,do { if (!(mChunkState.hashSize == 32)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "ProcessHostSubComplete should only be called for complete hashes."
, "mChunkState.hashSize == COMPLETE_SIZE", "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 673); MOZ_PretendNoReturn(); } } while (0)
673 "ProcessHostSubComplete should only be called for complete hashes.")do { if (!(mChunkState.hashSize == 32)) { NS_DebugBreak(NS_DEBUG_ASSERTION
, "ProcessHostSubComplete should only be called for complete hashes."
, "mChunkState.hashSize == COMPLETE_SIZE", "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 673); MOZ_PretendNoReturn(); } } while (0)
;
674
675 if (aNumEntries == 0) {
676 // this is totally comprehensible.
677 NS_WARNING("Expected > 0 entries for a 32-byte hash sub.")NS_DebugBreak(NS_DEBUG_WARNING, "Expected > 0 entries for a 32-byte hash sub."
, nullptr, "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 677)
;
678 return NS_OK;
679 }
680
681 if (*aStart + ((COMPLETE_SIZE32 + 4) * aNumEntries) > aChunk.Length()) {
682 NS_WARNING("Chunk is not long enough to contain the expected entries.")NS_DebugBreak(NS_DEBUG_WARNING, "Chunk is not long enough to contain the expected entries."
, nullptr, "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 682)
;
683 return NS_ERROR_FAILURE;
684 }
685
686 for (uint8_t i = 0; i < aNumEntries; i++) {
687 const nsACString& addChunkStr = Substring(aChunk, *aStart, 4);
688 *aStart += 4;
689
690 uint32_t addChunk;
691 memcpy(&addChunk, addChunkStr.BeginReading(), 4);
692 addChunk = PR_ntohl(addChunk);
693
694 Completion hash;
695 hash.Assign(Substring(aChunk, *aStart, COMPLETE_SIZE32));
696 *aStart += COMPLETE_SIZE32;
697
698 nsresult rv = mTableUpdate->NewSubComplete(addChunk, hash, mChunkState.num);
699 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
700 return rv;
701 }
702 }
703
704 return NS_OK;
705}
706
707bool ProtocolParserV2::NextLine(nsACString& aLine) {
708 int32_t newline = mPending.FindChar('\n');
709 if (newline == kNotFound) {
710 return false;
711 }
712 aLine.Assign(Substring(mPending, 0, newline));
713 mPending.Cut(0, newline + 1);
714 return true;
715}
716
717RefPtr<TableUpdate> ProtocolParserV2::CreateTableUpdate(
718 const nsACString& aTableName) const {
719 return new TableUpdateV2(aTableName);
720}
721
722///////////////////////////////////////////////////////////////////////
723// ProtocolParserProtobuf
724
725ProtocolParserProtobuf::ProtocolParserProtobuf() = default;
726
727ProtocolParserProtobuf::~ProtocolParserProtobuf() = default;
728
729void ProtocolParserProtobuf::SetCurrentTable(const nsACString& aTable) {
730 // Should never occur.
731 MOZ_ASSERT_UNREACHABLE("SetCurrentTable shouldn't be called")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: "
"SetCurrentTable shouldn't be called" ")", "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 731); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "SetCurrentTable shouldn't be called"
")"); do { MOZ_CrashSequence(__null, 731); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
732}
733
734RefPtr<TableUpdate> ProtocolParserProtobuf::CreateTableUpdate(
735 const nsACString& aTableName) const {
736 return new TableUpdateV4(aTableName);
737}
738
739nsresult ProtocolParserProtobuf::AppendStream(const nsACString& aData) {
740 // Protobuf data cannot be parsed progressively. Just save the incoming data.
741 if (!mPending.Append(aData, mozilla::fallible)) {
742 return NS_ERROR_OUT_OF_MEMORY;
743 }
744 return NS_OK;
745}
746
747void ProtocolParserProtobuf::End() {
748 // mUpdateStatus will be updated to success as long as not all
749 // the responses are invalid.
750 mUpdateStatus = NS_ERROR_FAILURE;
751
752 FetchThreatListUpdatesResponse response;
753 if (!response.ParseFromArray(mPending.get(), mPending.Length())) {
754 NS_WARNING("ProtocolParserProtobuf failed parsing data.")NS_DebugBreak(NS_DEBUG_WARNING, "ProtocolParserProtobuf failed parsing data."
, nullptr, "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 754)
;
755 return;
756 }
757
758 auto minWaitDuration = response.minimum_wait_duration();
759 mUpdateWaitSec =
760 minWaitDuration.seconds() + minWaitDuration.nanos() / 1000000000;
761
762 for (int i = 0; i < response.list_update_responses_size(); i++) {
763 const auto& r = response.list_update_responses(i);
764 nsAutoCString listName;
765 nsresult rv = ProcessOneResponse(r, listName);
766 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
767 mUpdateStatus = rv;
768 } else {
769 nsAutoCString errorName;
770 mozilla::GetErrorName(rv, errorName);
771 NS_WARNING(nsPrintfCString("Failed to process one response for '%s': %s",NS_DebugBreak(NS_DEBUG_WARNING, nsPrintfCString("Failed to process one response for '%s': %s"
, listName.get(), errorName.get()) .get(), nullptr, "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 773)
772 listName.get(), errorName.get())NS_DebugBreak(NS_DEBUG_WARNING, nsPrintfCString("Failed to process one response for '%s': %s"
, listName.get(), errorName.get()) .get(), nullptr, "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 773)
773 .get())NS_DebugBreak(NS_DEBUG_WARNING, nsPrintfCString("Failed to process one response for '%s': %s"
, listName.get(), errorName.get()) .get(), nullptr, "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 773)
;
774 if (!listName.IsEmpty()) {
775 PARSER_LOG(("Table %s will be reset.", listName.get()))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Table %s will be reset."
, listName.get()); } } while (0)
;
776 mTablesToReset.AppendElement(listName);
777 }
778 }
779 }
780}
781
782nsresult ProtocolParserProtobuf::ProcessOneResponse(
783 const ListUpdateResponse& aResponse, nsACString& aListName) {
784 MOZ_ASSERT(aListName.IsEmpty())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aListName.IsEmpty())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aListName.IsEmpty()))), 0)))
{ do { } while (false); MOZ_ReportAssertionFailure("aListName.IsEmpty()"
, "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 784); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aListName.IsEmpty()"
")"); do { MOZ_CrashSequence(__null, 784); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
785
786 // A response must have a threat type.
787 if (!aResponse.has_threat_type()) {
788 NS_WARNING(NS_DebugBreak(NS_DEBUG_WARNING, "Threat type not initialized. This seems to be an invalid response."
, nullptr, "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 789)
789 "Threat type not initialized. This seems to be an invalid response.")NS_DebugBreak(NS_DEBUG_WARNING, "Threat type not initialized. This seems to be an invalid response."
, nullptr, "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 789)
;
790 return NS_ERROR_UC_PARSER_MISSING_PARAM;
791 }
792
793 nsUrlClassifierUtils* urlUtil = nsUrlClassifierUtils::GetInstance();
794 if (NS_WARN_IF(!urlUtil)NS_warn_if_impl(!urlUtil, "!urlUtil", "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 794)
) {
795 return NS_ERROR_FAILURE;
796 }
797
798 // Convert threat type to list name.
799 nsCString possibleListNames;
800 nsresult rv = urlUtil->ConvertThreatTypeToListNames(aResponse.threat_type(),
801 possibleListNames);
802 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
803 PARSER_LOG(("Threat type to list name conversion error: %d",do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Threat type to list name conversion error: %d"
, aResponse.threat_type()); } } while (0)
804 aResponse.threat_type()))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Threat type to list name conversion error: %d"
, aResponse.threat_type()); } } while (0)
;
805 return NS_ERROR_UC_PARSER_UNKNOWN_THREAT;
806 }
807
808 // Match the table name we received with one of the ones we requested.
809 // We ignore the case where a threat type matches more than one list
810 // per provider and return the first one. See bug 1287059."
811 nsTArray<nsCString> possibleListNameArray;
812 Classifier::SplitTables(possibleListNames, possibleListNameArray);
813 for (const auto& possibleName : possibleListNameArray) {
814 if (mRequestedTables.Contains(possibleName)) {
815 aListName = possibleName;
816 break;
817 }
818 }
819
820 if (aListName.IsEmpty()) {
821 PARSER_LOG(do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "We received an update for a list we didn't ask for. Ignoring it."
); } } while (0)
822 ("We received an update for a list we didn't ask for. Ignoring it."))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "We received an update for a list we didn't ask for. Ignoring it."
); } } while (0)
;
823 return NS_ERROR_FAILURE;
824 }
825
826 // Test if this is a full update.
827 bool isFullUpdate = false;
828 if (aResponse.has_response_type()) {
829 isFullUpdate = aResponse.response_type() == ListUpdateResponse::FULL_UPDATE;
830 } else {
831 NS_WARNING("Response type not initialized.")NS_DebugBreak(NS_DEBUG_WARNING, "Response type not initialized."
, nullptr, "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 831)
;
832 return NS_ERROR_UC_PARSER_MISSING_PARAM;
833 }
834
835 // Warn if there's no new state.
836 if (!aResponse.has_new_client_state()) {
837 NS_WARNING("New state not initialized.")NS_DebugBreak(NS_DEBUG_WARNING, "New state not initialized.",
nullptr, "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 837)
;
838 return NS_ERROR_UC_PARSER_MISSING_PARAM;
839 }
840
841 auto tu = GetTableUpdate(aListName);
842 auto tuV4 = TableUpdate::Cast<TableUpdateV4>(tu);
843 NS_ENSURE_TRUE(tuV4, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(tuV4)), 0))) { NS_DebugBreak(
NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "tuV4" ") failed", nullptr
, "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 843); return NS_ERROR_FAILURE; } } while (false)
;
844
845 nsCString state(aResponse.new_client_state().c_str(),
846 aResponse.new_client_state().size());
847 tuV4->SetNewClientState(state);
848
849 if (aResponse.has_checksum()) {
850 tuV4->SetSHA256(aResponse.checksum().sha256());
851 }
852
853 PARSER_LOG(do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "==== Update for threat type '%d' ===="
, aResponse.threat_type()); } } while (0)
854 ("==== Update for threat type '%d' ====", aResponse.threat_type()))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "==== Update for threat type '%d' ===="
, aResponse.threat_type()); } } while (0)
;
855 PARSER_LOG(("* aListName: %s\n", PromiseFlatCString(aListName).get()))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "* aListName: %s\n"
, TPromiseFlatString<char>(aListName).get()); } } while
(0)
;
856 PARSER_LOG(("* newState: %s\n", aResponse.new_client_state().c_str()))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "* newState: %s\n"
, aResponse.new_client_state().c_str()); } } while (0)
;
857 PARSER_LOG(("* isFullUpdate: %s\n", (isFullUpdate ? "yes" : "no")))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "* isFullUpdate: %s\n"
, (isFullUpdate ? "yes" : "no")); } } while (0)
;
858 PARSER_LOG(do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "* hasChecksum: %s\n"
, (aResponse.has_checksum() ? "yes" : "no")); } } while (0)
859 ("* hasChecksum: %s\n", (aResponse.has_checksum() ? "yes" : "no")))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "* hasChecksum: %s\n"
, (aResponse.has_checksum() ? "yes" : "no")); } } while (0)
;
860 PARSER_LOG(("* additions: %d\n", aResponse.additions().size()))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "* additions: %d\n"
, aResponse.additions().size()); } } while (0)
;
861 PARSER_LOG(("* removals: %d\n", aResponse.removals().size()))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "* removals: %d\n"
, aResponse.removals().size()); } } while (0)
;
862
863 tuV4->SetFullUpdate(isFullUpdate);
864
865 rv = ProcessAdditionOrRemoval(*tuV4, aResponse.additions(),
866 true /*aIsAddition*/);
867 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 867); return rv; } } while (false)
;
868 rv = ProcessAdditionOrRemoval(*tuV4, aResponse.removals(), false);
869 NS_ENSURE_SUCCESS(rv, rv)do { nsresult __rv = rv; if (((bool)(__builtin_expect(!!(NS_FAILED_impl
(__rv)), 0)))) { const char* name = mozilla::GetStaticErrorName
(__rv); mozilla::SmprintfPointer msg = mozilla::Smprintf( "NS_ENSURE_SUCCESS(%s, %s) failed with "
"result 0x%" "X" "%s%s%s", "rv", "rv", static_cast<uint32_t
>(__rv), name ? " (" : "", name ? name : "", name ? ")" : ""
); NS_DebugBreak(NS_DEBUG_WARNING, msg.get(), nullptr, "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 869); return rv; } } while (false)
;
870
871 PARSER_LOG(("\n\n"))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "\n\n"); } } while
(0)
;
872
873 return NS_OK;
874}
875
876nsresult ProtocolParserProtobuf::ProcessAdditionOrRemoval(
877 TableUpdateV4& aTableUpdate, const ThreatEntrySetList& aUpdate,
878 bool aIsAddition) {
879 nsresult ret = NS_OK;
880
881 for (int i = 0; i < aUpdate.size(); i++) {
882 const auto& update = aUpdate.Get(i);
883 if (!update.has_compression_type()) {
884 NS_WARNING(nsPrintfCString("%s with no compression type.",NS_DebugBreak(NS_DEBUG_WARNING, nsPrintfCString("%s with no compression type."
, aIsAddition ? "Addition" : "Removal") .get(), nullptr, "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 886)
885 aIsAddition ? "Addition" : "Removal")NS_DebugBreak(NS_DEBUG_WARNING, nsPrintfCString("%s with no compression type."
, aIsAddition ? "Addition" : "Removal") .get(), nullptr, "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 886)
886 .get())NS_DebugBreak(NS_DEBUG_WARNING, nsPrintfCString("%s with no compression type."
, aIsAddition ? "Addition" : "Removal") .get(), nullptr, "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 886)
;
887 continue;
888 }
889
890 switch (update.compression_type()) {
891 case COMPRESSION_TYPE_UNSPECIFIED:
892 NS_WARNING("Unspecified compression type.")NS_DebugBreak(NS_DEBUG_WARNING, "Unspecified compression type."
, nullptr, "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 892)
;
893 break;
894
895 case RAW:
896 ret = (aIsAddition ? ProcessRawAddition(aTableUpdate, update)
897 : ProcessRawRemoval(aTableUpdate, update));
898 break;
899
900 case RICE:
901 ret = (aIsAddition ? ProcessEncodedAddition(aTableUpdate, update)
902 : ProcessEncodedRemoval(aTableUpdate, update));
903 break;
904 }
905 }
906
907 return ret;
908}
909
910nsresult ProtocolParserProtobuf::ProcessRawAddition(
911 TableUpdateV4& aTableUpdate, const ThreatEntrySet& aAddition) {
912 if (!aAddition.has_raw_hashes()) {
913 PARSER_LOG(("* No raw addition."))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "* No raw addition."
); } } while (0)
;
914 return NS_OK;
915 }
916
917 const auto& rawHashes = aAddition.raw_hashes();
918 if (!rawHashes.has_prefix_size()) {
919 NS_WARNING("Raw hash has no prefix size")NS_DebugBreak(NS_DEBUG_WARNING, "Raw hash has no prefix size"
, nullptr, "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 919)
;
920 return NS_OK;
921 }
922
923 uint32_t prefixSize = rawHashes.prefix_size();
924 MOZ_ASSERT(prefixSize >= PREFIX_SIZE && prefixSize <= COMPLETE_SIZE)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(prefixSize >= 4 && prefixSize <= 32)>
::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(prefixSize >= 4 && prefixSize <= 32)))
, 0))) { do { } while (false); MOZ_ReportAssertionFailure("prefixSize >= 4 && prefixSize <= 32"
, "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 924); AnnotateMozCrashReason("MOZ_ASSERT" "(" "prefixSize >= 4 && prefixSize <= 32"
")"); do { MOZ_CrashSequence(__null, 924); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
925
926 nsCString prefixes;
927 if (!prefixes.Assign(rawHashes.raw_hashes().c_str(),
928 rawHashes.raw_hashes().size(), mozilla::fallible)) {
929 return NS_ERROR_OUT_OF_MEMORY;
930 }
931 MOZ_ASSERT(prefixes.Length() % prefixSize == 0,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(prefixes.Length() % prefixSize == 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(prefixes.Length() % prefixSize
== 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("prefixes.Length() % prefixSize == 0" " (" "PrefixString length must be a multiple of the prefix size."
")", "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 932); AnnotateMozCrashReason("MOZ_ASSERT" "(" "prefixes.Length() % prefixSize == 0"
") (" "PrefixString length must be a multiple of the prefix size."
")"); do { MOZ_CrashSequence(__null, 932); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
932 "PrefixString length must be a multiple of the prefix size.")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(prefixes.Length() % prefixSize == 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(prefixes.Length() % prefixSize
== 0))), 0))) { do { } while (false); MOZ_ReportAssertionFailure
("prefixes.Length() % prefixSize == 0" " (" "PrefixString length must be a multiple of the prefix size."
")", "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 932); AnnotateMozCrashReason("MOZ_ASSERT" "(" "prefixes.Length() % prefixSize == 0"
") (" "PrefixString length must be a multiple of the prefix size."
")"); do { MOZ_CrashSequence(__null, 932); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
933
934 if (LOG_ENABLED()(__builtin_expect(!!(mozilla::detail::log_test(gUrlClassifierDbServiceLog
, mozilla::LogLevel::Debug)), 0))
) {
935 PARSER_LOG((" Raw addition (%d-byte prefixes)", prefixSize))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " Raw addition (%d-byte prefixes)"
, prefixSize); } } while (0)
;
936 PARSER_LOG((" - # of prefixes: %zu", prefixes.Length() / prefixSize))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " - # of prefixes: %zu"
, prefixes.Length() / prefixSize); } } while (0)
;
937 if (4 == prefixSize) {
938 uint32_t* fixedLengthPrefixes = (uint32_t*)prefixes.get();
939 PARSER_LOG((" - Memory address: 0x%p", fixedLengthPrefixes))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " - Memory address: 0x%p"
, fixedLengthPrefixes); } } while (0)
;
940 }
941 }
942
943 aTableUpdate.NewPrefixes(prefixSize, prefixes);
944 return NS_OK;
945}
946
947nsresult ProtocolParserProtobuf::ProcessRawRemoval(
948 TableUpdateV4& aTableUpdate, const ThreatEntrySet& aRemoval) {
949 if (!aRemoval.has_raw_indices()) {
950 NS_WARNING("A removal has no indices.")NS_DebugBreak(NS_DEBUG_WARNING, "A removal has no indices.", nullptr
, "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 950)
;
951 return NS_OK;
952 }
953
954 // indices is an array of int32.
955 auto indices = aRemoval.raw_indices().indices();
956 PARSER_LOG(("* Raw removal"))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "* Raw removal");
} } while (0)
;
957 PARSER_LOG((" - # of removal: %d", indices.size()))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " - # of removal: %d"
, indices.size()); } } while (0)
;
958
959 nsresult rv = aTableUpdate.NewRemovalIndices((const uint32_t*)indices.data(),
960 indices.size());
961 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
962 PARSER_LOG(("Failed to create new removal indices."))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Failed to create new removal indices."
); } } while (0)
;
963 return rv;
964 }
965
966 return NS_OK;
967}
968
969static nsresult DoRiceDeltaDecode(const RiceDeltaEncoding& aEncoding,
970 nsTArray<uint32_t>& aDecoded) {
971 if (aEncoding.num_entries() > 0 &&
972 (!aEncoding.has_rice_parameter() || !aEncoding.has_encoded_data())) {
973 PARSER_LOG(("Rice parameter or encoded data is missing."))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Rice parameter or encoded data is missing."
); } } while (0)
;
974 return NS_ERROR_UC_PARSER_MISSING_PARAM;
975 } else if (aEncoding.num_entries() == 0 && !aEncoding.has_first_value()) {
976 PARSER_LOG(("Missing first_value for an single-integer Rice encoding."))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Missing first_value for an single-integer Rice encoding."
); } } while (0)
;
977 return NS_ERROR_UC_PARSER_MISSING_VALUE;
978 }
979
980 auto first_value = aEncoding.has_first_value() ? aEncoding.first_value() : 0;
981
982 PARSER_LOG(("* Encoding info:"))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "* Encoding info:"
); } } while (0)
;
983 PARSER_LOG((" - First value: %" PRId64, first_value))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " - First value: %"
"l" "d", first_value); } } while (0)
;
984 PARSER_LOG((" - Num of entries: %d", aEncoding.num_entries()))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " - Num of entries: %d"
, aEncoding.num_entries()); } } while (0)
;
985 PARSER_LOG((" - Rice parameter: %d", aEncoding.rice_parameter()))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " - Rice parameter: %d"
, aEncoding.rice_parameter()); } } while (0)
;
986
987 // Set up the input buffer. Note that the bits should be read
988 // from LSB to MSB so that we in-place reverse the bits before
989 // feeding to the decoder.
990 auto encoded =
991 const_cast<RiceDeltaEncoding&>(aEncoding).mutable_encoded_data();
992 RiceDeltaDecoder decoder((uint8_t*)encoded->c_str(), encoded->size());
993
994 // Setup the output buffer. The "first value" is included in
995 // the output buffer.
996 if (!aDecoded.SetLength(aEncoding.num_entries() + 1, mozilla::fallible)) {
997 NS_WARNING("Not enough memory to decode the RiceDelta input.")NS_DebugBreak(NS_DEBUG_WARNING, "Not enough memory to decode the RiceDelta input."
, nullptr, "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 997)
;
998 return NS_ERROR_OUT_OF_MEMORY;
999 }
1000
1001 // Decode!
1002 bool rv = decoder.Decode(
1003 aEncoding.rice_parameter(), first_value,
1004 aEncoding.num_entries(), // # of entries (first value not included).
1005 &aDecoded[0]);
1006
1007 NS_ENSURE_TRUE(rv, NS_ERROR_UC_PARSER_DECODE_FAILURE)do { if ((__builtin_expect(!!(!(rv)), 0))) { NS_DebugBreak(NS_DEBUG_WARNING
, "NS_ENSURE_TRUE(" "rv" ") failed", nullptr, "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 1007); return NS_ERROR_UC_PARSER_DECODE_FAILURE; } } while (
false)
;
1008
1009 return NS_OK;
1010}
1011
1012nsresult ProtocolParserProtobuf::ProcessEncodedAddition(
1013 TableUpdateV4& aTableUpdate, const ThreatEntrySet& aAddition) {
1014 if (!aAddition.has_rice_hashes()) {
1015 PARSER_LOG(("* No rice encoded addition."))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "* No rice encoded addition."
); } } while (0)
;
1016 return NS_OK;
1017 }
1018
1019 nsTArray<uint32_t> decoded;
1020 nsresult rv = DoRiceDeltaDecode(aAddition.rice_hashes(), decoded);
1021 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
1022 PARSER_LOG(("Failed to parse encoded prefixes."))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Failed to parse encoded prefixes."
); } } while (0)
;
1023 return rv;
1024 }
1025
1026 // Say we have the following raw prefixes
1027 // BE LE
1028 // 00 00 00 01 1 16777216
1029 // 00 00 02 00 512 131072
1030 // 00 03 00 00 196608 768
1031 // 04 00 00 00 67108864 4
1032 //
1033 // which can be treated as uint32 (big-endian) sorted in increasing order:
1034 //
1035 // [1, 512, 196608, 67108864]
1036 //
1037 // According to https://developers.google.com/safe-browsing/v4/compression,
1038 // the following should be done prior to compression:
1039 //
1040 // 1) re-interpret in little-endian ==> [16777216, 131072, 768, 4]
1041 // 2) sort in increasing order ==> [4, 768, 131072, 16777216]
1042 //
1043 // In order to get the original byte stream from |decoded|
1044 // ([4, 768, 131072, 16777216] in this case), we have to:
1045 //
1046 // 1) sort in big-endian order ==> [16777216, 131072, 768, 4]
1047 // 2) copy each uint32 in little-endian to the result string
1048 //
1049
1050 // The 4-byte prefixes have to be re-sorted in Big-endian increasing order.
1051 struct CompareBigEndian {
1052 bool Equals(const uint32_t& aA, const uint32_t& aB) const {
1053 return aA == aB;
1054 }
1055
1056 bool LessThan(const uint32_t& aA, const uint32_t& aB) const {
1057 return NativeEndian::swapToBigEndian(aA) <
1058 NativeEndian::swapToBigEndian(aB);
1059 }
1060 };
1061 decoded.Sort(CompareBigEndian());
1062
1063 // The encoded prefixes are always 4 bytes.
1064 nsCString prefixes;
1065 if (!prefixes.SetCapacity(decoded.Length() * 4, mozilla::fallible)) {
1066 return NS_ERROR_OUT_OF_MEMORY;
1067 }
1068 for (size_t i = 0; i < decoded.Length(); i++) {
1069 // Note that the third argument is the number of elements we want
1070 // to copy (and swap) but not the number of bytes we want to copy.
1071 char p[4];
1072 NativeEndian::copyAndSwapToLittleEndian(p, &decoded[i], 1);
1073 prefixes.Append(p, 4);
1074 }
1075
1076 aTableUpdate.NewPrefixes(4, prefixes);
1077 return NS_OK;
1078}
1079
1080nsresult ProtocolParserProtobuf::ProcessEncodedRemoval(
1081 TableUpdateV4& aTableUpdate, const ThreatEntrySet& aRemoval) {
1082 if (!aRemoval.has_rice_indices()) {
1083 PARSER_LOG(("* No rice encoded removal."))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "* No rice encoded removal."
); } } while (0)
;
1084 return NS_OK;
1085 }
1086
1087 nsTArray<uint32_t> decoded;
1088 nsresult rv = DoRiceDeltaDecode(aRemoval.rice_indices(), decoded);
1089 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
1090 PARSER_LOG(("Failed to decode encoded removal indices."))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Failed to decode encoded removal indices."
); } } while (0)
;
1091 return rv;
1092 }
1093
1094 // The encoded prefixes are always 4 bytes.
1095 rv = aTableUpdate.NewRemovalIndices(&decoded[0], decoded.Length());
1096 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
1097 PARSER_LOG(("Failed to create new removal indices."))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Failed to create new removal indices."
); } } while (0)
;
1098 return rv;
1099 }
1100
1101 return NS_OK;
1102}
1103
1104///////////////////////////////////////////////////////////////////////
1105// ProtocolParserProtobufV5
1106
1107ProtocolParserProtobufV5::ProtocolParserProtobufV5() = default;
1108
1109ProtocolParserProtobufV5::~ProtocolParserProtobufV5() = default;
1110
1111void ProtocolParserProtobufV5::SetCurrentTable(const nsACString& aTable) {
1112 // Should never occur.
1113 MOZ_ASSERT_UNREACHABLE("SetCurrentTable shouldn't be called")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "MOZ_ASSERT_UNREACHABLE: "
"SetCurrentTable shouldn't be called" ")", "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 1113); AnnotateMozCrashReason("MOZ_ASSERT" "(" "false" ") ("
"MOZ_ASSERT_UNREACHABLE: " "SetCurrentTable shouldn't be called"
")"); do { MOZ_CrashSequence(__null, 1113); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1114}
1115
1116RefPtr<TableUpdate> ProtocolParserProtobufV5::CreateTableUpdate(
1117 const nsACString& aTableName) const {
1118 // For v5, we still use the same V4 table because the table format is the
1119 // same.
1120 return new TableUpdateV4(aTableName);
1121}
1122
1123nsresult ProtocolParserProtobufV5::AppendStream(const nsACString& aData) {
1124 // Protobuf data cannot be parsed progressively. Just save the incoming data.
1125 if (!mPending.Append(aData, mozilla::fallible)) {
1126 return NS_ERROR_OUT_OF_MEMORY;
1127 }
1128 return NS_OK;
1129}
1130
1131void ProtocolParserProtobufV5::End() {
1132 mUpdateStatus = NS_ERROR_FAILURE;
1133
1134 v5::BatchGetHashListsResponse response;
1135
1136 if (!response.ParseFromArray(mPending.get(), mPending.Length())) {
1137 NS_WARNING("ProtocolParserProtobufV5 failed parsing data.")NS_DebugBreak(NS_DEBUG_WARNING, "ProtocolParserProtobufV5 failed parsing data."
, nullptr, "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 1137)
;
1138 return;
1139 }
1140
1141 // Iterate over all the hash lists in the response.
1142 for (int i = 0; i < response.hash_lists_size(); i++) {
1143 const v5::HashList& hashList = response.hash_lists(i);
1144 nsAutoCString listName;
1145 nsresult rv = ProcessOneResponse(hashList, listName);
1146 if (NS_SUCCEEDED(rv)((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1)))) {
1147 mUpdateStatus = rv;
1148 } else {
1149 nsAutoCString errorName;
1150 mozilla::GetErrorName(rv, errorName);
1151 NS_WARNING(NS_DebugBreak(NS_DEBUG_WARNING, nsPrintfCString("Failed to process one V5 response for '%s': %s"
, listName.get(), errorName.get()) .get(), nullptr, "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 1154)
1152 nsPrintfCString("Failed to process one V5 response for '%s': %s",NS_DebugBreak(NS_DEBUG_WARNING, nsPrintfCString("Failed to process one V5 response for '%s': %s"
, listName.get(), errorName.get()) .get(), nullptr, "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 1154)
1153 listName.get(), errorName.get())NS_DebugBreak(NS_DEBUG_WARNING, nsPrintfCString("Failed to process one V5 response for '%s': %s"
, listName.get(), errorName.get()) .get(), nullptr, "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 1154)
1154 .get())NS_DebugBreak(NS_DEBUG_WARNING, nsPrintfCString("Failed to process one V5 response for '%s': %s"
, listName.get(), errorName.get()) .get(), nullptr, "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 1154)
;
1155 if (!listName.IsEmpty()) {
1156 PARSER_LOG(("Table %s will be reset.", listName.get()))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Table %s will be reset."
, listName.get()); } } while (0)
;
1157 mTablesToReset.AppendElement(listName);
1158 }
1159 }
1160 }
1161}
1162
1163nsresult ProtocolParserProtobufV5::ProcessOneResponse(
1164 const v5::HashList& aHashList, nsACString& aListName) {
1165 MOZ_ASSERT(aListName.IsEmpty())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(aListName.IsEmpty())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(aListName.IsEmpty()))), 0)))
{ do { } while (false); MOZ_ReportAssertionFailure("aListName.IsEmpty()"
, "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 1165); AnnotateMozCrashReason("MOZ_ASSERT" "(" "aListName.IsEmpty()"
")"); do { MOZ_CrashSequence(__null, 1165); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1166
1167 nsUrlClassifierUtils* urlUtil = nsUrlClassifierUtils::GetInstance();
1168 if (NS_WARN_IF(!urlUtil)NS_warn_if_impl(!urlUtil, "!urlUtil", "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 1168)
) {
1169 return NS_ERROR_FAILURE;
1170 }
1171
1172 auto& name = aHashList.name();
1173 nsAutoCString serverListName;
1174 serverListName.Assign(name.c_str(), name.size());
1175
1176 nsresult rv = urlUtil->ConvertServerListNameToLocalListNameV5(serverListName,
1177 aListName);
1178 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
1179 PARSER_LOG(("Failed to convert v5 server list name to local list name: %s",do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Failed to convert v5 server list name to local list name: %s"
, serverListName.get()); } } while (0)
1180 serverListName.get()))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Failed to convert v5 server list name to local list name: %s"
, serverListName.get()); } } while (0)
;
1181 return rv;
1182 }
1183 MOZ_ASSERT(!aListName.IsEmpty())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(!aListName.IsEmpty())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(!aListName.IsEmpty()))), 0))
) { do { } while (false); MOZ_ReportAssertionFailure("!aListName.IsEmpty()"
, "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 1183); AnnotateMozCrashReason("MOZ_ASSERT" "(" "!aListName.IsEmpty()"
")"); do { MOZ_CrashSequence(__null, 1183); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1184
1185 bool isPartialUpdate = aHashList.partial_update();
1186
1187 // We use the V4 table for the V5 update because the table format is the same.
1188 auto tu = GetTableUpdate(aListName);
1189 auto tuV4 = TableUpdate::Cast<TableUpdateV4>(tu);
1190 NS_ENSURE_TRUE(tuV4, NS_ERROR_FAILURE)do { if ((__builtin_expect(!!(!(tuV4)), 0))) { NS_DebugBreak(
NS_DEBUG_WARNING, "NS_ENSURE_TRUE(" "tuV4" ") failed", nullptr
, "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 1190); return NS_ERROR_FAILURE; } } while (false)
;
1191
1192 // The V5 response has a version field which is compatible with the V4 state
1193 // field.
1194 nsCString version(aHashList.version().c_str(), aHashList.version().size());
1195 tuV4->SetNewClientState(version);
1196
1197 tuV4->SetFullUpdate(!isPartialUpdate);
1198
1199 const std::string& sha256Checksum = aHashList.sha256_checksum();
1200 if (sha256Checksum.size() != 0) {
1201 tuV4->SetSHA256(sha256Checksum);
1202 }
1203
1204 switch (aHashList.compressed_additions_case()) {
1205 case v5::HashList::kAdditionsFourBytes:
1206 rv = ProcessAddition4Bytes(*tuV4, aHashList.additions_four_bytes());
1207 break;
1208 case v5::HashList::kAdditionsEightBytes:
1209 rv = ProcessAddition8Bytes(*tuV4, aHashList.additions_eight_bytes());
1210 break;
1211 case v5::HashList::kAdditionsSixteenBytes:
1212 rv = ProcessAddition16Bytes(*tuV4, aHashList.additions_sixteen_bytes());
Value stored to 'rv' is never read
1213 break;
1214 case v5::HashList::kAdditionsThirtyTwoBytes:
1215 rv =
1216 ProcessAddition32Bytes(*tuV4, aHashList.additions_thirty_two_bytes());
1217 break;
1218 case v5::HashList::COMPRESSED_ADDITIONS_NOT_SET:
1219 break;
1220 }
1221
1222 if (aHashList.has_compressed_removals()) {
1223 rv = ProcessRemoval(*tuV4, aHashList.compressed_removals());
1224 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
1225 PARSER_LOG(("Failed to parse encoded removal indices."))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Failed to parse encoded removal indices."
); } } while (0)
;
1226 return rv;
1227 }
1228 }
1229
1230 const auto& minWaitDuration = aHashList.minimum_wait_duration();
1231 uint32_t waitSec =
1232 minWaitDuration.seconds() + minWaitDuration.nanos() / 1000000000;
1233 mUpdateWaits.AppendElement(TableWaitDuration{nsCString(aListName), waitSec});
1234
1235 PARSER_LOG(("==== V5 Update for list '%s' ====",do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "==== V5 Update for list '%s' ===="
, TPromiseFlatString<char>(aListName).get()); } } while
(0)
1236 PromiseFlatCString(aListName).get()))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "==== V5 Update for list '%s' ===="
, TPromiseFlatString<char>(aListName).get()); } } while
(0)
;
1237 PARSER_LOG(("* newVersion: %s\n", version.get()))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "* newVersion: %s\n"
, version.get()); } } while (0)
;
1238 PARSER_LOG(("* isFullUpdate: %s\n", (!isPartialUpdate ? "yes" : "no")))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "* isFullUpdate: %s\n"
, (!isPartialUpdate ? "yes" : "no")); } } while (0)
;
1239 PARSER_LOG(("* minimumWaitDuration: %u sec\n", waitSec))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "* minimumWaitDuration: %u sec\n"
, waitSec); } } while (0)
;
1240
1241 return NS_OK;
1242}
1243
1244static nsresult DoRiceDeltaDecode4Bytes(
1245 const v5::RiceDeltaEncoded32Bit& aEncoding, nsTArray<uint32_t>& aDecoded) {
1246 auto first_value = aEncoding.first_value();
1247
1248 PARSER_LOG(("* Encoding info for V5 4bytes encoding:"))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "* Encoding info for V5 4bytes encoding:"
); } } while (0)
;
1249 PARSER_LOG((" - First value: %u", first_value))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " - First value: %u"
, first_value); } } while (0)
;
1250 PARSER_LOG((" - Num of entries: %d", aEncoding.entries_count()))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " - Num of entries: %d"
, aEncoding.entries_count()); } } while (0)
;
1251 PARSER_LOG((" - Rice parameter: %d", aEncoding.rice_parameter()))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " - Rice parameter: %d"
, aEncoding.rice_parameter()); } } while (0)
;
1252
1253 // Set up the input buffer. Note that the bits should be read
1254 // from LSB to MSB so that we in-place reverse the bits before
1255 // feeding to the decoder.
1256 auto encoded =
1257 const_cast<v5::RiceDeltaEncoded32Bit&>(aEncoding).mutable_encoded_data();
1258 RiceDeltaDecoder decoder((uint8_t*)encoded->c_str(), encoded->size());
1259
1260 // Setup the output buffer. The "first value" is included in
1261 // the output buffer.
1262 if (!aDecoded.SetLength(aEncoding.entries_count() + 1, mozilla::fallible)) {
1263 NS_WARNING("Not enough memory to decode the RiceDelta input.")NS_DebugBreak(NS_DEBUG_WARNING, "Not enough memory to decode the RiceDelta input."
, nullptr, "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 1263)
;
1264 return NS_ERROR_OUT_OF_MEMORY;
1265 }
1266
1267 // Decode!
1268 bool rv = decoder.Decode(
1269 aEncoding.rice_parameter(), first_value,
1270 aEncoding.entries_count(), // # of entries (first value not included).
1271 &aDecoded[0], /* aIsV5 */ true);
1272
1273 NS_ENSURE_TRUE(rv, NS_ERROR_UC_PARSER_DECODE_FAILURE)do { if ((__builtin_expect(!!(!(rv)), 0))) { NS_DebugBreak(NS_DEBUG_WARNING
, "NS_ENSURE_TRUE(" "rv" ") failed", nullptr, "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 1273); return NS_ERROR_UC_PARSER_DECODE_FAILURE; } } while (
false)
;
1274
1275 return NS_OK;
1276}
1277
1278static nsresult DoRiceDeltaDecode8Bytes(
1279 const v5::RiceDeltaEncoded64Bit& aEncoding, nsTArray<uint64_t>& aDecoded) {
1280 auto first_value = aEncoding.first_value();
1281
1282 PARSER_LOG(("* Encoding info for V5 8bytes encoding:"))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "* Encoding info for V5 8bytes encoding:"
); } } while (0)
;
1283 PARSER_LOG((" - First value: %" PRIu64, first_value))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " - First value: %"
"l" "u", first_value); } } while (0)
;
1284 PARSER_LOG((" - Num of entries: %d", aEncoding.entries_count()))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " - Num of entries: %d"
, aEncoding.entries_count()); } } while (0)
;
1285 PARSER_LOG((" - Rice parameter: %d", aEncoding.rice_parameter()))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " - Rice parameter: %d"
, aEncoding.rice_parameter()); } } while (0)
;
1286
1287 // Set up the input buffer. Note that the bits should be read
1288 // from LSB to MSB so that we in-place reverse the bits before
1289 // feeding to the decoder.
1290 auto encoded =
1291 const_cast<v5::RiceDeltaEncoded64Bit&>(aEncoding).mutable_encoded_data();
1292 RiceDeltaDecoder decoder((uint8_t*)encoded->c_str(), encoded->size());
1293
1294 // Setup the output buffer. The "first value" is included in
1295 // the output buffer.
1296 if (!aDecoded.SetLength(aEncoding.entries_count() + 1, mozilla::fallible)) {
1297 NS_WARNING("Not enough memory to decode the RiceDelta input.")NS_DebugBreak(NS_DEBUG_WARNING, "Not enough memory to decode the RiceDelta input."
, nullptr, "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 1297)
;
1298 return NS_ERROR_OUT_OF_MEMORY;
1299 }
1300
1301 // Decode!
1302 bool rv = decoder.Decode64(
1303 aEncoding.rice_parameter(), first_value,
1304 aEncoding.entries_count(), // # of entries (first value not included).
1305 &aDecoded[0]);
1306
1307 NS_ENSURE_TRUE(rv, NS_ERROR_UC_PARSER_DECODE_FAILURE)do { if ((__builtin_expect(!!(!(rv)), 0))) { NS_DebugBreak(NS_DEBUG_WARNING
, "NS_ENSURE_TRUE(" "rv" ") failed", nullptr, "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 1307); return NS_ERROR_UC_PARSER_DECODE_FAILURE; } } while (
false)
;
1308
1309 return NS_OK;
1310}
1311
1312static nsresult DoRiceDeltaDecode16Bytes(
1313 const v5::RiceDeltaEncoded128Bit& aEncoding, nsACString& aDecoded) {
1314 auto first_value_hi = aEncoding.first_value_hi();
1315 auto first_value_lo = aEncoding.first_value_lo();
1316
1317 PARSER_LOG(("* Encoding info for V5 16bytes encoding:"))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "* Encoding info for V5 16bytes encoding:"
); } } while (0)
;
1318 PARSER_LOG((" - First value hi: %" PRIu64, first_value_hi))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " - First value hi: %"
"l" "u", first_value_hi); } } while (0)
;
1319 PARSER_LOG((" - First value lo: %" PRIu64, first_value_lo))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " - First value lo: %"
"l" "u", first_value_lo); } } while (0)
;
1320 PARSER_LOG((" - Num of entries: %d", aEncoding.entries_count()))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " - Num of entries: %d"
, aEncoding.entries_count()); } } while (0)
;
1321 PARSER_LOG((" - Rice parameter: %d", aEncoding.rice_parameter()))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " - Rice parameter: %d"
, aEncoding.rice_parameter()); } } while (0)
;
1322
1323 // Set up the input buffer. Note that the bits should be read
1324 // from LSB to MSB so that we in-place reverse the bits before
1325 // feeding to the decoder.
1326 auto encoded =
1327 const_cast<v5::RiceDeltaEncoded128Bit&>(aEncoding).mutable_encoded_data();
1328 RiceDeltaDecoder decoder((uint8_t*)encoded->c_str(), encoded->size());
1329
1330 // Setup the output buffer. The "first value" is included in
1331 // the output buffer.
1332 if (!aDecoded.SetCapacity(aEncoding.entries_count() * 16,
1333 mozilla::fallible)) {
1334 NS_WARNING("Not enough memory to decode the RiceDelta input.")NS_DebugBreak(NS_DEBUG_WARNING, "Not enough memory to decode the RiceDelta input."
, nullptr, "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 1334)
;
1335 return NS_ERROR_OUT_OF_MEMORY;
1336 }
1337
1338 // Decode!
1339 bool rv = decoder.Decode128(
1340 aEncoding.rice_parameter(), first_value_hi, first_value_lo,
1341 aEncoding.entries_count(), // # of entries (first value not included).
1342 aDecoded);
1343
1344 NS_ENSURE_TRUE(rv, NS_ERROR_UC_PARSER_DECODE_FAILURE)do { if ((__builtin_expect(!!(!(rv)), 0))) { NS_DebugBreak(NS_DEBUG_WARNING
, "NS_ENSURE_TRUE(" "rv" ") failed", nullptr, "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 1344); return NS_ERROR_UC_PARSER_DECODE_FAILURE; } } while (
false)
;
1345
1346 return NS_OK;
1347}
1348
1349static nsresult DoRiceDeltaDecode32Bytes(
1350 const v5::RiceDeltaEncoded256Bit& aEncoding, nsACString& aDecoded) {
1351 auto first_value_first_part = aEncoding.first_value_first_part();
1352 auto first_value_second_part = aEncoding.first_value_second_part();
1353 auto first_value_third_part = aEncoding.first_value_third_part();
1354 auto first_value_fourth_part = aEncoding.first_value_fourth_part();
1355
1356 PARSER_LOG(("* Encoding info for V5 32bytes encoding:"))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "* Encoding info for V5 32bytes encoding:"
); } } while (0)
;
1357 PARSER_LOG((" - First value first part: %" PRIu64, first_value_first_part))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " - First value first part: %"
"l" "u", first_value_first_part); } } while (0)
;
1358 PARSER_LOG(do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " - First value second part: %"
"l" "u", first_value_second_part); } } while (0)
1359 (" - First value second part: %" PRIu64, first_value_second_part))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " - First value second part: %"
"l" "u", first_value_second_part); } } while (0)
;
1360 PARSER_LOG((" - First value third part: %" PRIu64, first_value_third_part))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " - First value third part: %"
"l" "u", first_value_third_part); } } while (0)
;
1361 PARSER_LOG(do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " - First value fourth part: %"
"l" "u", first_value_fourth_part); } } while (0)
1362 (" - First value fourth part: %" PRIu64, first_value_fourth_part))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " - First value fourth part: %"
"l" "u", first_value_fourth_part); } } while (0)
;
1363 PARSER_LOG((" - Num of entries: %d", aEncoding.entries_count()))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " - Num of entries: %d"
, aEncoding.entries_count()); } } while (0)
;
1364 PARSER_LOG((" - Rice parameter: %d", aEncoding.rice_parameter()))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, " - Rice parameter: %d"
, aEncoding.rice_parameter()); } } while (0)
;
1365
1366 // Set up the input buffer. Note that the bits should be read
1367 // from LSB to MSB so that we in-place reverse the bits before
1368 // feeding to the decoder.
1369 auto encoded =
1370 const_cast<v5::RiceDeltaEncoded256Bit&>(aEncoding).mutable_encoded_data();
1371 RiceDeltaDecoder decoder((uint8_t*)encoded->c_str(), encoded->size());
1372
1373 // Setup the output buffer. The "first value" is included in
1374 // the output buffer.
1375 if (!aDecoded.SetCapacity((aEncoding.entries_count() + 1) * 32,
1376 mozilla::fallible)) {
1377 NS_WARNING("Not enough memory to decode the RiceDelta input.")NS_DebugBreak(NS_DEBUG_WARNING, "Not enough memory to decode the RiceDelta input."
, nullptr, "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 1377)
;
1378 return NS_ERROR_OUT_OF_MEMORY;
1379 }
1380
1381 // Decode!
1382 bool rv = decoder.Decode256(
1383 aEncoding.rice_parameter(), first_value_first_part,
1384 first_value_second_part, first_value_third_part, first_value_fourth_part,
1385 aEncoding.entries_count(), // # of entries (first value not included).
1386 aDecoded);
1387
1388 NS_ENSURE_TRUE(rv, NS_ERROR_UC_PARSER_DECODE_FAILURE)do { if ((__builtin_expect(!!(!(rv)), 0))) { NS_DebugBreak(NS_DEBUG_WARNING
, "NS_ENSURE_TRUE(" "rv" ") failed", nullptr, "./../../../../toolkit/components/url-classifier/ProtocolParser.cpp"
, 1388); return NS_ERROR_UC_PARSER_DECODE_FAILURE; } } while (
false)
;
1389
1390 return NS_OK;
1391}
1392
1393nsresult ProtocolParserProtobufV5::ProcessAddition4Bytes(
1394 TableUpdateV4& aTableUpdate, const v5::RiceDeltaEncoded32Bit& aAddition) {
1395 nsTArray<uint32_t> decoded;
1396
1397 nsresult rv = DoRiceDeltaDecode4Bytes(aAddition, decoded);
1398 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
1399 PARSER_LOG(("Failed to parse encoded prefixes."))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Failed to parse encoded prefixes."
); } } while (0)
;
1400 return rv;
1401 }
1402
1403 nsCString prefixes;
1404 if (!prefixes.SetCapacity(decoded.Length() * 4, mozilla::fallible)) {
1405 return NS_ERROR_OUT_OF_MEMORY;
1406 }
1407
1408 for (size_t i = 0; i < decoded.Length(); i++) {
1409 // This is the main difference between V4 and V5 for the RiceDeltaDecoder.
1410 // V4 uses little-endian to encode the prefixes, while V5 uses big-endian.
1411 // We need to swap the bytes to get the correct prefix.
1412 char p[4];
1413 NativeEndian::copyAndSwapToBigEndian(p, &decoded[i], 1);
1414
1415 prefixes.Append(p, 4);
1416 }
1417
1418 aTableUpdate.NewPrefixes(4, prefixes);
1419 return NS_OK;
1420}
1421
1422nsresult ProtocolParserProtobufV5::ProcessAddition8Bytes(
1423 TableUpdateV4& aTableUpdate, const v5::RiceDeltaEncoded64Bit& aAddition) {
1424 nsTArray<uint64_t> decoded;
1425
1426 nsresult rv = DoRiceDeltaDecode8Bytes(aAddition, decoded);
1427 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
1428 PARSER_LOG(("Failed to parse encoded prefixes."))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Failed to parse encoded prefixes."
); } } while (0)
;
1429 return rv;
1430 }
1431
1432 nsCString prefixes;
1433 if (!prefixes.SetCapacity(decoded.Length() * 8, mozilla::fallible)) {
1434 return NS_ERROR_OUT_OF_MEMORY;
1435 }
1436
1437 for (size_t i = 0; i < decoded.Length(); i++) {
1438 char p[8];
1439 NativeEndian::copyAndSwapToBigEndian(p, &decoded[i], 1);
1440 prefixes.Append(p, 8);
1441 }
1442
1443 aTableUpdate.NewPrefixes(8, prefixes);
1444 return NS_OK;
1445}
1446
1447nsresult ProtocolParserProtobufV5::ProcessAddition16Bytes(
1448 TableUpdateV4& aTableUpdate, const v5::RiceDeltaEncoded128Bit& aAddition) {
1449 nsAutoCString decoded;
1450
1451 nsresult rv = DoRiceDeltaDecode16Bytes(aAddition, decoded);
1452 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
1453 PARSER_LOG(("Failed to parse encoded prefixes."))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Failed to parse encoded prefixes."
); } } while (0)
;
1454 return rv;
1455 }
1456
1457 nsCString prefixes;
1458 if (!prefixes.SetCapacity(decoded.Length(), mozilla::fallible)) {
1459 return NS_ERROR_OUT_OF_MEMORY;
1460 }
1461
1462 for (size_t i = 0; i < decoded.Length() / 16; i++) {
1463 // Swap the bytes to the correct endianness, the data is 128-bits long.
1464 char p[16];
1465 for (size_t j = 0; j < 16; j++) {
1466 p[j] = decoded[i * 16 + (15 - j)];
1467 }
1468 prefixes.Append(p, 16);
1469 }
1470
1471 aTableUpdate.NewPrefixes(16, prefixes);
1472 return NS_OK;
1473}
1474
1475nsresult ProtocolParserProtobufV5::ProcessAddition32Bytes(
1476 TableUpdateV4& aTableUpdate, const v5::RiceDeltaEncoded256Bit& aAddition) {
1477 nsAutoCString decoded;
1478
1479 nsresult rv = DoRiceDeltaDecode32Bytes(aAddition, decoded);
1480 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
1481 PARSER_LOG(("Failed to parse encoded prefixes."))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Failed to parse encoded prefixes."
); } } while (0)
;
1482 return rv;
1483 }
1484
1485 nsCString prefixes;
1486 if (!prefixes.SetCapacity(decoded.Length(), mozilla::fallible)) {
1487 return NS_ERROR_OUT_OF_MEMORY;
1488 }
1489
1490 for (size_t i = 0; i < decoded.Length() / 32; i++) {
1491 // Swap the bytes to the correct endianness, the data is 256-bits long.
1492 char p[32];
1493 for (size_t j = 0; j < 32; j++) {
1494 p[j] = decoded[i * 32 + (31 - j)];
1495 }
1496 prefixes.Append(p, 32);
1497 }
1498
1499 aTableUpdate.NewPrefixes(32, prefixes);
1500 return NS_OK;
1501}
1502
1503nsresult ProtocolParserProtobufV5::ProcessRemoval(
1504 TableUpdateV4& aTableUpdate, const v5::RiceDeltaEncoded32Bit& aRemoval) {
1505 nsTArray<uint32_t> decoded;
1506 nsresult rv = DoRiceDeltaDecode4Bytes(aRemoval, decoded);
1507 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
1508 PARSER_LOG(("Failed to parse encoded removal indices."))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Failed to parse encoded removal indices."
); } } while (0)
;
1509 return rv;
1510 }
1511
1512 // The encoded prefixes are always 4 bytes.
1513 rv = aTableUpdate.NewRemovalIndices(&decoded[0], decoded.Length());
1514 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
1515 PARSER_LOG(("Failed to create new removal indices."))do { const ::mozilla::LogModule* moz_real_module = gUrlClassifierProtocolParserLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Failed to create new removal indices."
); } } while (0)
;
1516 return rv;
1517 }
1518
1519 return NS_OK;
1520}
1521
1522} // namespace safebrowsing
1523} // namespace mozilla