Bug Summary

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