Bug Summary

File:root/firefox-clang/obj-x86_64-pc-linux-gnu/netwerk/cache2/./../../../netwerk/cache2/Dictionary.cpp
Warning:line 601, column 3
Value stored to 'aSrc' 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_netwerk_cache21.cpp -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -analyzer-config-compatibility-mode=true -mrelocation-model pic -pic-level 2 -fhalf-no-semantic-interposition -mframe-pointer=all -relaxed-aliasing -ffp-contract=off -fno-rounding-math -mconstructor-aliases -funwind-tables=2 -target-cpu x86-64 -tune-cpu generic -debugger-tuning=gdb -fdebug-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/netwerk/cache2 -fcoverage-compilation-dir=/root/firefox-clang/obj-x86_64-pc-linux-gnu/netwerk/cache2 -resource-dir /usr/lib/llvm-23/lib/clang/23 -include /root/firefox-clang/config/gcc_hidden.h -include /root/firefox-clang/obj-x86_64-pc-linux-gnu/mozilla-config.h -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/stl_wrappers -D _GLIBCXX_ASSERTIONS=1 -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/dist/system_wrappers -U _FORTIFY_SOURCE -D _FORTIFY_SOURCE=2 -D DEBUG=1 -D MOZ_HAS_MOZGLUE -D MOZILLA_INTERNAL_API -D IMPL_LIBXUL -D MOZ_SUPPORT_LEAKCHECKING -D STATIC_EXPORTABLE_JS_API -I /root/firefox-clang/netwerk/cache2 -I /root/firefox-clang/obj-x86_64-pc-linux-gnu/netwerk/cache2 -I /root/firefox-clang/netwerk/base -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_netwerk_cache21.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 "Dictionary.h"
6
7#include <stdlib.h>
8
9#include "CacheFileUtils.h"
10#include "LoadContextInfo.h"
11#include "ReferrerInfo.h"
12#include "SerializedLoadContext.h"
13#include "mozilla/ClearOnShutdown.h"
14#include "mozilla/Components.h"
15#include "mozilla/FlowMarkers.h"
16#include "mozilla/Logging.h"
17#include "mozilla/OriginAttributes.h"
18#include "mozilla/Preferences.h"
19#include "mozilla/SchedulerGroup.h"
20#include "mozilla/Services.h"
21#include "mozilla/StaticPrefs_network.h"
22#include "mozilla/dom/ContentParent.h"
23#include "mozilla/dom/Document.h"
24#include "mozilla/dom/InternalRequest.h"
25#include "mozilla/glean/GleanPings.h"
26#include "mozilla/glean/NetwerkMetrics.h"
27#include "mozilla/ipc/URIUtils.h"
28#include "mozilla/net/NeckoChild.h"
29#include "mozilla/net/NeckoCommon.h"
30#include "mozilla/net/NeckoParent.h"
31#include "mozilla/net/URLPatternGlue.h"
32#include "mozilla/net/urlpattern_glue.h"
33#include "nsAppDirectoryServiceDefs.h"
34#include "nsAttrValue.h"
35#include "nsContentPolicyUtils.h"
36#include "nsContentUtils.h"
37#include "nsHTTPCompressConv.h"
38#include "nsIAsyncInputStream.h"
39#include "nsICacheEntry.h"
40#include "nsICacheStorage.h"
41#include "nsICacheStorageService.h"
42#include "nsICachingChannel.h"
43#include "nsICancelable.h"
44#include "nsIChannel.h"
45#include "nsIEffectiveTLDService.h"
46#include "nsIFile.h"
47#include "nsIInputStream.h"
48#include "nsILoadContext.h"
49#include "nsILoadContextInfo.h"
50#include "nsILoadGroup.h"
51#include "nsIOService.h"
52#include "nsIObserverService.h"
53#include "nsIURI.h"
54#include "nsIURIMutator.h"
55#include "nsInputStreamPump.h"
56#include "nsNetCID.h"
57#include "nsNetUtil.h"
58#include "nsServiceManagerUtils.h"
59#include "nsSimpleURI.h"
60#include "nsStandardURL.h"
61#include "nsStreamUtils.h"
62#include "nsString.h"
63#include "nsThreadUtils.h"
64
65using namespace mozilla;
66
67namespace mozilla {
68namespace net {
69
70// Access to all these classes is from MainThread unless otherwise specified
71
72LazyLogModule gDictionaryLog("CompressionDictionaries");
73
74#define DICTIONARY_LOG(args)do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; 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)
\
75 MOZ_LOG(gDictionaryLog, mozilla::LogLevel::Debug, args)do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; 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)
76
77/**
78 * Reference to the DictionaryCache singleton. May be null.
79 */
80StaticRefPtr<DictionaryCache> gDictionaryCache;
81StaticRefPtr<nsICacheStorage> DictionaryCache::sCacheStorage;
82Atomic<bool, Relaxed> DictionaryCache::sShutdown{false};
83
84// about:cache gets upset about entries that don't fit URL specs, so we need
85// to add the trailing '/' to GetPrePath()
86static nsresult GetDictPath(nsIURI* aURI, nsACString& aPrePath) {
87 if (NS_FAILED(aURI->GetPrePath(aPrePath))((bool)(__builtin_expect(!!(NS_FAILED_impl(aURI->GetPrePath
(aPrePath))), 0)))
) {
88 return NS_ERROR_FAILURE;
89 }
90 aPrePath += '/';
91 return NS_OK;
92}
93
94DictionaryCacheEntry::DictionaryCacheEntry(const char* aKey) {
95 mURI = aKey;
96 DICTIONARY_LOG(("Created DictionaryCacheEntry %p, uri=%s", this, aKey))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Created DictionaryCacheEntry %p, uri=%s"
, this, aKey); } } while (0)
;
97}
98
99DictionaryCacheEntry::~DictionaryCacheEntry() {
100 MOZ_ASSERT(mUsers == 0)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mUsers == 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mUsers == 0))), 0))) { do { }
while (false); MOZ_ReportAssertionFailure("mUsers == 0", "./../../../netwerk/cache2/Dictionary.cpp"
, 100); AnnotateMozCrashReason("MOZ_ASSERT" "(" "mUsers == 0"
")"); do { MOZ_CrashSequence(__null, 100); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
101 DICTIONARY_LOG(do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Destroyed DictionaryCacheEntry %p, uri=%s, pattern=%s, id=%s"
, this, mURI.get(), mPattern.get(), mId.get()); } } while (0)
102 ("Destroyed DictionaryCacheEntry %p, uri=%s, pattern=%s, id=%s", this,do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Destroyed DictionaryCacheEntry %p, uri=%s, pattern=%s, id=%s"
, this, mURI.get(), mPattern.get(), mId.get()); } } while (0)
103 mURI.get(), mPattern.get(), mId.get()))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Destroyed DictionaryCacheEntry %p, uri=%s, pattern=%s, id=%s"
, this, mURI.get(), mPattern.get(), mId.get()); } } while (0)
;
104 if (mCachedPattern.isSome()) {
105 if (NS_IsMainThread()) {
106 urlpattern_pattern_free(mCachedPattern.ref());
107 } else {
108 UrlPatternGlue pattern = mCachedPattern.ref();
109 NS_DispatchToMainThread(NS_NewRunnableFunction(
110 "DictionaryCacheEntry::FreeCachedPattern",
111 [pattern]() { urlpattern_pattern_free(pattern); }));
112 }
113 }
114}
115
116DictionaryCacheEntry::DictionaryCacheEntry(const nsACString& aURI,
117 const nsACString& aPattern,
118 nsTArray<nsCString>& aMatchDest,
119 const nsACString& aId,
120 uint32_t aExpiration,
121 const Maybe<nsCString>& aHash)
122 : mURI(aURI), mExpiration(aExpiration), mPattern(aPattern), mId(aId) {
123 ConvertMatchDestToEnumArray(aMatchDest, mMatchDest);
124 DICTIONARY_LOG(do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Created DictionaryCacheEntry %p, uri=%s, pattern=%s, id=%s, "
"expiration=%u", this, TPromiseFlatString<char>(aURI).
get(), TPromiseFlatString<char>(aPattern).get(), TPromiseFlatString
<char>(aId).get(), aExpiration); } } while (0)
125 ("Created DictionaryCacheEntry %p, uri=%s, pattern=%s, id=%s, "do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Created DictionaryCacheEntry %p, uri=%s, pattern=%s, id=%s, "
"expiration=%u", this, TPromiseFlatString<char>(aURI).
get(), TPromiseFlatString<char>(aPattern).get(), TPromiseFlatString
<char>(aId).get(), aExpiration); } } while (0)
126 "expiration=%u",do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Created DictionaryCacheEntry %p, uri=%s, pattern=%s, id=%s, "
"expiration=%u", this, TPromiseFlatString<char>(aURI).
get(), TPromiseFlatString<char>(aPattern).get(), TPromiseFlatString
<char>(aId).get(), aExpiration); } } while (0)
127 this, PromiseFlatCString(aURI).get(), PromiseFlatCString(aPattern).get(),do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Created DictionaryCacheEntry %p, uri=%s, pattern=%s, id=%s, "
"expiration=%u", this, TPromiseFlatString<char>(aURI).
get(), TPromiseFlatString<char>(aPattern).get(), TPromiseFlatString
<char>(aId).get(), aExpiration); } } while (0)
128 PromiseFlatCString(aId).get(), aExpiration))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Created DictionaryCacheEntry %p, uri=%s, pattern=%s, id=%s, "
"expiration=%u", this, TPromiseFlatString<char>(aURI).
get(), TPromiseFlatString<char>(aPattern).get(), TPromiseFlatString
<char>(aId).get(), aExpiration); } } while (0)
;
129 if (aHash) {
130 mHash = aHash.value();
131 }
132}
133
134NS_IMPL_ISUPPORTS(DictionaryCacheEntry, nsICacheEntryOpenCallback,MozExternalRefCountType DictionaryCacheEntry::AddRef(void) { static_assert
(!std::is_destructible_v<DictionaryCacheEntry>, "Reference-counted class "
"DictionaryCacheEntry" " should not have a public destructor. "
"Make this class's destructor non-public"); do { static_assert
( mozilla::detail::AssertionConditionType<decltype(int32_t
(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "./../../../netwerk/cache2/Dictionary.cpp"
, 135); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { MOZ_CrashSequence(__null, 135
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("DictionaryCacheEntry" != nullptr)>::isValid,
"invalid assertion condition"); if ((__builtin_expect(!!(!(!
!("DictionaryCacheEntry" != nullptr))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("\"DictionaryCacheEntry\" != nullptr"
" (" "Must specify a name" ")", "./../../../netwerk/cache2/Dictionary.cpp"
, 135); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"DictionaryCacheEntry\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 135); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); if (!mRefCnt.isThreadSafe) _mOwningThread.AssertOwnership
("DictionaryCacheEntry" " not thread-safe"); nsrefcnt count =
++mRefCnt; NS_LogAddRef((this), (count), ("DictionaryCacheEntry"
), (uint32_t)(sizeof(*this))); return count; } MozExternalRefCountType
DictionaryCacheEntry::Release(void) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(int32_t(mRefCnt)
> 0)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(int32_t(mRefCnt) > 0))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0" " (" "dup release"
")", "./../../../netwerk/cache2/Dictionary.cpp", 135); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0" ") (" "dup release"
")"); do { MOZ_CrashSequence(__null, 135); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); do { static_assert
( mozilla::detail::AssertionConditionType<decltype("DictionaryCacheEntry"
!= nullptr)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!("DictionaryCacheEntry" != nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"\"DictionaryCacheEntry\" != nullptr" " (" "Must specify a name"
")", "./../../../netwerk/cache2/Dictionary.cpp", 135); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "\"DictionaryCacheEntry\" != nullptr" ") ("
"Must specify a name" ")"); do { MOZ_CrashSequence(__null, 135
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); if (!mRefCnt.isThreadSafe) _mOwningThread.AssertOwnership
("DictionaryCacheEntry" " not thread-safe"); const char* const
nametmp = "DictionaryCacheEntry"; nsrefcnt count = --mRefCnt
; NS_LogRelease((this), (count), (nametmp)); if (count == 0) {
mRefCnt = 1; delete (this); return 0; } return count; } nsresult
DictionaryCacheEntry::QueryInterface(const nsIID& aIID, void
** aInstancePtr) { do { if (!(aInstancePtr)) { NS_DebugBreak(
NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!"
, "aInstancePtr", "./../../../netwerk/cache2/Dictionary.cpp",
135); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE
; static_assert(2 > 0, "Need more arguments to NS_INTERFACE_TABLE"
); static const QITableEntry table[] = { {&mozilla::detail
::kImplementedIID<DictionaryCacheEntry, nsICacheEntryOpenCallback
>, int32_t( reinterpret_cast<char*>(static_cast<nsICacheEntryOpenCallback
*>((DictionaryCacheEntry*)0x1000)) - reinterpret_cast<char
*>((DictionaryCacheEntry*)0x1000))}, {&mozilla::detail
::kImplementedIID<DictionaryCacheEntry, nsIStreamListener>
, int32_t( reinterpret_cast<char*>(static_cast<nsIStreamListener
*>((DictionaryCacheEntry*)0x1000)) - reinterpret_cast<char
*>((DictionaryCacheEntry*)0x1000))}, {&mozilla::detail
::kImplementedIID<DictionaryCacheEntry, nsISupports>, int32_t
(reinterpret_cast<char*>(static_cast<nsISupports*>
( static_cast<nsICacheEntryOpenCallback*>((DictionaryCacheEntry
*)0x1000))) - reinterpret_cast<char*>((DictionaryCacheEntry
*)0x1000))}, { nullptr, 0 } } ; static_assert(std::size(table
) > 1, "need at least 1 interface"); rv = NS_TableDrivenQI
(static_cast<void*>(this), aIID, aInstancePtr, table); return
rv; }
135 nsIStreamListener)MozExternalRefCountType DictionaryCacheEntry::AddRef(void) { static_assert
(!std::is_destructible_v<DictionaryCacheEntry>, "Reference-counted class "
"DictionaryCacheEntry" " should not have a public destructor. "
"Make this class's destructor non-public"); do { static_assert
( mozilla::detail::AssertionConditionType<decltype(int32_t
(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "./../../../netwerk/cache2/Dictionary.cpp"
, 135); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { MOZ_CrashSequence(__null, 135
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("DictionaryCacheEntry" != nullptr)>::isValid,
"invalid assertion condition"); if ((__builtin_expect(!!(!(!
!("DictionaryCacheEntry" != nullptr))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("\"DictionaryCacheEntry\" != nullptr"
" (" "Must specify a name" ")", "./../../../netwerk/cache2/Dictionary.cpp"
, 135); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"DictionaryCacheEntry\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 135); __attribute__((nomerge)) ::abort(); } while (false); }
} while (false); if (!mRefCnt.isThreadSafe) _mOwningThread.AssertOwnership
("DictionaryCacheEntry" " not thread-safe"); nsrefcnt count =
++mRefCnt; NS_LogAddRef((this), (count), ("DictionaryCacheEntry"
), (uint32_t)(sizeof(*this))); return count; } MozExternalRefCountType
DictionaryCacheEntry::Release(void) { do { static_assert( mozilla
::detail::AssertionConditionType<decltype(int32_t(mRefCnt)
> 0)>::isValid, "invalid assertion condition"); if ((__builtin_expect
(!!(!(!!(int32_t(mRefCnt) > 0))), 0))) { do { } while (false
); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0" " (" "dup release"
")", "./../../../netwerk/cache2/Dictionary.cpp", 135); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0" ") (" "dup release"
")"); do { MOZ_CrashSequence(__null, 135); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); do { static_assert
( mozilla::detail::AssertionConditionType<decltype("DictionaryCacheEntry"
!= nullptr)>::isValid, "invalid assertion condition"); if
((__builtin_expect(!!(!(!!("DictionaryCacheEntry" != nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"\"DictionaryCacheEntry\" != nullptr" " (" "Must specify a name"
")", "./../../../netwerk/cache2/Dictionary.cpp", 135); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "\"DictionaryCacheEntry\" != nullptr" ") ("
"Must specify a name" ")"); do { MOZ_CrashSequence(__null, 135
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); if (!mRefCnt.isThreadSafe) _mOwningThread.AssertOwnership
("DictionaryCacheEntry" " not thread-safe"); const char* const
nametmp = "DictionaryCacheEntry"; nsrefcnt count = --mRefCnt
; NS_LogRelease((this), (count), (nametmp)); if (count == 0) {
mRefCnt = 1; delete (this); return 0; } return count; } nsresult
DictionaryCacheEntry::QueryInterface(const nsIID& aIID, void
** aInstancePtr) { do { if (!(aInstancePtr)) { NS_DebugBreak(
NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!"
, "aInstancePtr", "./../../../netwerk/cache2/Dictionary.cpp",
135); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE
; static_assert(2 > 0, "Need more arguments to NS_INTERFACE_TABLE"
); static const QITableEntry table[] = { {&mozilla::detail
::kImplementedIID<DictionaryCacheEntry, nsICacheEntryOpenCallback
>, int32_t( reinterpret_cast<char*>(static_cast<nsICacheEntryOpenCallback
*>((DictionaryCacheEntry*)0x1000)) - reinterpret_cast<char
*>((DictionaryCacheEntry*)0x1000))}, {&mozilla::detail
::kImplementedIID<DictionaryCacheEntry, nsIStreamListener>
, int32_t( reinterpret_cast<char*>(static_cast<nsIStreamListener
*>((DictionaryCacheEntry*)0x1000)) - reinterpret_cast<char
*>((DictionaryCacheEntry*)0x1000))}, {&mozilla::detail
::kImplementedIID<DictionaryCacheEntry, nsISupports>, int32_t
(reinterpret_cast<char*>(static_cast<nsISupports*>
( static_cast<nsICacheEntryOpenCallback*>((DictionaryCacheEntry
*)0x1000))) - reinterpret_cast<char*>((DictionaryCacheEntry
*)0x1000))}, { nullptr, 0 } } ; static_assert(std::size(table
) > 1, "need at least 1 interface"); rv = NS_TableDrivenQI
(static_cast<void*>(this), aIID, aInstancePtr, table); return
rv; }
136
137// Convert string MatchDest array to enum array
138// static
139void DictionaryCacheEntry::ConvertMatchDestToEnumArray(
140 const nsTArray<nsCString>& aMatchDest,
141 nsTArray<dom::RequestDestination>& aMatchEnums) {
142 AutoTArray<dom::RequestDestination, 3> temp;
143 for (auto& string : aMatchDest) {
144 dom::RequestDestination dest =
145 dom::StringToEnum<dom::RequestDestination>(string).valueOr(
146 dom::RequestDestination::_empty);
147 if (dest != dom::RequestDestination::_empty) {
148 temp.AppendElement(dest);
149 }
150 }
151 aMatchEnums.SwapElements(temp);
152}
153
154// Returns true if the pattern for the dictionary matches the path given.
155// Note: we need to verify that this entry has not expired due to 2.2.1 of
156// https://datatracker.ietf.org/doc/draft-ietf-httpbis-compression-dictionary/
157bool DictionaryCacheEntry::Match(const nsACString& aFilePath,
158 ExtContentPolicyType aType, uint32_t aNow,
159 uint32_t& aLongest) {
160 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "./../../../netwerk/cache2/Dictionary.cpp", 160); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { MOZ_CrashSequence
(__null, 160); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
161 if (mHash.IsEmpty()) {
162 // We don't have the file yet
163 return false;
164 }
165 if (mNotCached) {
166 // Not actually in the cache
167 // May not actually be necessary, but good safety valve.
168 return false;
169 }
170 // Not worth checking if we wouldn't use it
171 if ((mExpiration == 0 || aNow < mExpiration) &&
172 mPattern.Length() > aLongest) {
173 // Need to match using match-dest, if it exists
174 if (mMatchDest.IsEmpty() ||
175 mMatchDest.IndexOf(
176 dom::InternalRequest::MapContentPolicyTypeToRequestDestination(
177 aType)) != mMatchDest.NoIndex) {
178 // Check if we have a cached pattern, otherwise parse and cache it
179 if (mCachedPattern.isNothing()) {
180 UrlPatternGlue pattern;
181 UrlPatternOptions options{};
182 const nsCString base(mURI);
183 if (!urlpattern_parse_pattern_from_string(&mPattern, &base, options,
184 &pattern)) {
185 DICTIONARY_LOG(do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; 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 dictionary pattern %s"
, mPattern.get()); } } while (0)
186 ("Failed to parse dictionary pattern %s", mPattern.get()))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; 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 dictionary pattern %s"
, mPattern.get()); } } while (0)
;
187 return false;
188 }
189 mCachedPattern.emplace(pattern);
190 }
191
192 UrlPatternInput input = net::CreateUrlPatternInput(aFilePath);
193 const nsCString base(mURI);
194 bool result =
195 net::UrlPatternTest(mCachedPattern.ref(), input, Some(base));
196 if (result) {
197 aLongest = mPattern.Length();
198 DICTIONARY_LOG(("Match: %p %s to %s, %s (now=%u, expiration=%u)",do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Match: %p %s to %s, %s (now=%u, expiration=%u)"
, this, TPromiseFlatString<char>(aFilePath).get(), mPattern
.get(), NS_CP_ContentTypeName(aType), aNow, mExpiration); } }
while (0)
199 this, PromiseFlatCString(aFilePath).get(),do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Match: %p %s to %s, %s (now=%u, expiration=%u)"
, this, TPromiseFlatString<char>(aFilePath).get(), mPattern
.get(), NS_CP_ContentTypeName(aType), aNow, mExpiration); } }
while (0)
200 mPattern.get(), NS_CP_ContentTypeName(aType), aNow,do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Match: %p %s to %s, %s (now=%u, expiration=%u)"
, this, TPromiseFlatString<char>(aFilePath).get(), mPattern
.get(), NS_CP_ContentTypeName(aType), aNow, mExpiration); } }
while (0)
201 mExpiration))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Match: %p %s to %s, %s (now=%u, expiration=%u)"
, this, TPromiseFlatString<char>(aFilePath).get(), mPattern
.get(), NS_CP_ContentTypeName(aType), aNow, mExpiration); } }
while (0)
;
202 DICTIONARY_LOG(("Match: %s (longest %u)", mURI.get(), aLongest))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Match: %s (longest %u)"
, mURI.get(), aLongest); } } while (0)
;
203 }
204 return result;
205 } // else failed on match-dest
206 } // else failed on expiration
207 return false;
208}
209
210void DictionaryCacheEntry::InUse() {
211 mUsers++;
212 DICTIONARY_LOG(("Dictionary users for %s -- %u Users", mURI.get(), mUsers))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Dictionary users for %s -- %u Users"
, mURI.get(), mUsers); } } while (0)
;
213}
214
215void DictionaryCacheEntry::UseCompleted() {
216 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "./../../../netwerk/cache2/Dictionary.cpp", 216); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { MOZ_CrashSequence
(__null, 216); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
217 MOZ_ASSERT(mUsers > 0)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mUsers > 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mUsers > 0))), 0))) { do {
} while (false); MOZ_ReportAssertionFailure("mUsers > 0",
"./../../../netwerk/cache2/Dictionary.cpp", 217); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "mUsers > 0" ")"); do { MOZ_CrashSequence
(__null, 217); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
218 mUsers--;
219 // Purge mDictionaryData
220 if (mUsers == 0) { // XXX perhaps we should hold it for a bit longer?
221 DICTIONARY_LOG(("Clearing Dictionary data for %s", mURI.get()))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Clearing Dictionary data for %s"
, mURI.get()); } } while (0)
;
222 mDictionaryData.clear();
223 mDictionaryDataComplete = false;
224 } else {
225 DICTIONARY_LOG(("Not clearing Dictionary data for %s -- %u Users",do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Not clearing Dictionary data for %s -- %u Users"
, mURI.get(), mUsers); } } while (0)
226 mURI.get(), mUsers))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Not clearing Dictionary data for %s -- %u Users"
, mURI.get(), mUsers); } } while (0)
;
227 }
228}
229
230nsCString DictionaryCacheEntry::GetHash() const {
231 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "./../../../netwerk/cache2/Dictionary.cpp", 231); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { MOZ_CrashSequence
(__null, 231); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
232 return mHash;
233}
234
235bool DictionaryCacheEntry::HasHash() {
236 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "./../../../netwerk/cache2/Dictionary.cpp", 236); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { MOZ_CrashSequence
(__null, 236); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
237 return !mHash.IsEmpty();
238}
239
240void DictionaryCacheEntry::SetHash(const nsACString& aHash) {
241 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "./../../../netwerk/cache2/Dictionary.cpp", 241); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { MOZ_CrashSequence
(__null, 241); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
242 mHash = aHash;
243}
244
245bool DictionaryCacheEntry::IsReading() const {
246 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "./../../../netwerk/cache2/Dictionary.cpp", 246); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { MOZ_CrashSequence
(__null, 246); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
247 return mUsers > 0 && !mWaitingPrefetch.empty();
248}
249
250void DictionaryCacheEntry::CallbackOnCacheRead(
251 const std::function<void(nsresult)>& aFunc) {
252 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "./../../../netwerk/cache2/Dictionary.cpp", 252); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { MOZ_CrashSequence
(__null, 252); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
253 // CallbackOnCacheRead is used for dictionary saving, not validation,
254 // so private browsing doesn't apply here
255 mWaitingPrefetch.push_back(PrefetchRequest{aFunc, false});
256}
257
258const Vector<uint8_t>& DictionaryCacheEntry::GetDictionary() const
259 MOZ_NO_THREAD_SAFETY_ANALYSIS__attribute__((no_thread_safety_analysis)) {
260 // May be called off main thread when the channel has been retargeted.
261 // Safe because mDictionaryData is immutable after mDictionaryDataComplete.
262 MOZ_ASSERT(mDictionaryDataComplete)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mDictionaryDataComplete)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mDictionaryDataComplete))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("mDictionaryDataComplete"
, "./../../../netwerk/cache2/Dictionary.cpp", 262); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "mDictionaryDataComplete" ")"); do { MOZ_CrashSequence
(__null, 262); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
263 return mDictionaryData;
264}
265
266void DictionaryCacheEntry::ClearDataForTesting() {
267 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "./../../../netwerk/cache2/Dictionary.cpp", 267); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { MOZ_CrashSequence
(__null, 267); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
268 mDictionaryData.clear();
269 mDictionaryDataComplete = false;
270}
271
272uint8_t* DictionaryCacheEntry::DictionaryData(size_t* aLength) const {
273 MOZ_ASSERT(mDictionaryDataComplete)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(mDictionaryDataComplete)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(mDictionaryDataComplete))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("mDictionaryDataComplete"
, "./../../../netwerk/cache2/Dictionary.cpp", 273); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "mDictionaryDataComplete" ")"); do { MOZ_CrashSequence
(__null, 273); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
274 *aLength = mDictionaryData.length();
275 return (uint8_t*)mDictionaryData.begin();
276}
277
278bool DictionaryCacheEntry::DictionaryReady() const {
279 return mDictionaryDataComplete;
280}
281
282// returns aShouldSuspend=true if we should suspend to wait for the prefetch
283nsresult DictionaryCacheEntry::Prefetch(
284 nsILoadContextInfo* aLoadContextInfo, bool& aShouldSuspend,
285 const std::function<void(nsresult)>& aFunc) {
286 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "./../../../netwerk/cache2/Dictionary.cpp", 286); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { MOZ_CrashSequence
(__null, 286); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
287
288 DICTIONARY_LOG(("Prefetch for %s", mURI.get()))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Prefetch for %s"
, mURI.get()); } } while (0)
;
289
290 // Determine private browsing status for this request
291 bool isPrivateBrowsing = aLoadContextInfo && aLoadContextInfo->IsPrivate();
292
293 // Start reading the cache entry into memory and call completion
294 // function when done
295 if (!mWaitingPrefetch.empty()) {
296 DICTIONARY_LOG(("Prefetch for %s - already waiting", mURI.get()))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Prefetch for %s - already waiting"
, mURI.get()); } } while (0)
;
297 mWaitingPrefetch.push_back(PrefetchRequest{aFunc, isPrivateBrowsing});
298 aShouldSuspend = true;
299 return NS_OK;
300 }
301
302 // Note that if the cache entry has been cleared, and we still have active
303 // users of it, we'll hold onto that data since we have outstanding requests
304 // for it. Probably we shouldn't allow new requests to use this data (and
305 // the WPTs assume we shouldn't).
306 if (mDictionaryDataComplete) {
307 DICTIONARY_LOG(("Prefetch for %s - already have data in memory (%u users)",do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Prefetch for %s - already have data in memory (%u users)"
, mURI.get(), mUsers); } } while (0)
308 mURI.get(), mUsers))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Prefetch for %s - already have data in memory (%u users)"
, mURI.get(), mUsers); } } while (0)
;
309 aShouldSuspend = false;
310 return NS_OK;
311 }
312
313 // We haven't requested it yet from the Cache and don't have it in memory
314 // already. Add to waiting list.
315 mWaitingPrefetch.push_back(PrefetchRequest{aFunc, isPrivateBrowsing});
316
317 // We can't use sCacheStorage because we need the correct LoadContextInfo
318 nsCOMPtr<nsICacheStorageService> cacheStorageService(
319 components::CacheStorage::Service());
320 if (!cacheStorageService) {
321 mWaitingPrefetch.clear();
322 aShouldSuspend = false;
323 return NS_ERROR_FAILURE;
324 }
325 nsCOMPtr<nsICacheStorage> cacheStorage;
326 nsresult rv = cacheStorageService->DiskCacheStorage(
327 aLoadContextInfo, getter_AddRefs(cacheStorage));
328 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
329 mWaitingPrefetch.clear();
330 aShouldSuspend = false;
331 return NS_ERROR_FAILURE;
332 }
333 // If the file isn't available in the cache, AsyncOpenURIString()
334 // will synchronously make a callback to OnCacheEntryAvailable() with
335 // nullptr. We can key off that to fail Prefetch(), and also to
336 // remove ourselves from the origin.
337 // Use OPEN_ALWAYS to ensure we don't get stalled if this is for some
338 // reason a revalidation
339 if (NS_FAILED(cacheStorage->AsyncOpenURIString(((bool)(__builtin_expect(!!(NS_FAILED_impl(cacheStorage->AsyncOpenURIString
( mURI, ""_ns, nsICacheStorage::OPEN_READONLY | nsICacheStorage
::OPEN_COMPLETE_ONLY | nsICacheStorage::OPEN_ALWAYS | nsICacheStorage
::CHECK_MULTITHREADED, this))), 0)))
340 mURI, ""_ns,((bool)(__builtin_expect(!!(NS_FAILED_impl(cacheStorage->AsyncOpenURIString
( mURI, ""_ns, nsICacheStorage::OPEN_READONLY | nsICacheStorage
::OPEN_COMPLETE_ONLY | nsICacheStorage::OPEN_ALWAYS | nsICacheStorage
::CHECK_MULTITHREADED, this))), 0)))
341 nsICacheStorage::OPEN_READONLY | nsICacheStorage::OPEN_COMPLETE_ONLY |((bool)(__builtin_expect(!!(NS_FAILED_impl(cacheStorage->AsyncOpenURIString
( mURI, ""_ns, nsICacheStorage::OPEN_READONLY | nsICacheStorage
::OPEN_COMPLETE_ONLY | nsICacheStorage::OPEN_ALWAYS | nsICacheStorage
::CHECK_MULTITHREADED, this))), 0)))
342 nsICacheStorage::OPEN_ALWAYS |((bool)(__builtin_expect(!!(NS_FAILED_impl(cacheStorage->AsyncOpenURIString
( mURI, ""_ns, nsICacheStorage::OPEN_READONLY | nsICacheStorage
::OPEN_COMPLETE_ONLY | nsICacheStorage::OPEN_ALWAYS | nsICacheStorage
::CHECK_MULTITHREADED, this))), 0)))
343 nsICacheStorage::CHECK_MULTITHREADED,((bool)(__builtin_expect(!!(NS_FAILED_impl(cacheStorage->AsyncOpenURIString
( mURI, ""_ns, nsICacheStorage::OPEN_READONLY | nsICacheStorage
::OPEN_COMPLETE_ONLY | nsICacheStorage::OPEN_ALWAYS | nsICacheStorage
::CHECK_MULTITHREADED, this))), 0)))
344 this))((bool)(__builtin_expect(!!(NS_FAILED_impl(cacheStorage->AsyncOpenURIString
( mURI, ""_ns, nsICacheStorage::OPEN_READONLY | nsICacheStorage
::OPEN_COMPLETE_ONLY | nsICacheStorage::OPEN_ALWAYS | nsICacheStorage
::CHECK_MULTITHREADED, this))), 0)))
||
345 mNotCached) {
346 DICTIONARY_LOG(("AsyncOpenURIString failed for %s", mURI.get()))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "AsyncOpenURIString failed for %s"
, mURI.get()); } } while (0)
;
347 // For some reason the cache no longer has this entry; fail Prefetch
348 // and also remove this from our origin
349 mWaitingPrefetch.clear();
350 aShouldSuspend = false;
351 // Remove from origin
352 if (mOrigin) {
353 mOrigin->RemoveEntry(this);
354 mOrigin = nullptr;
355 }
356 return NS_ERROR_FAILURE;
357 }
358 DICTIONARY_LOG(("Started Prefetch for %s, anonymous=%d", mURI.get(),do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Started Prefetch for %s, anonymous=%d"
, mURI.get(), aLoadContextInfo->IsAnonymous()); } } while (
0)
359 aLoadContextInfo->IsAnonymous()))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Started Prefetch for %s, anonymous=%d"
, mURI.get(), aLoadContextInfo->IsAnonymous()); } } while (
0)
;
360 aShouldSuspend = true;
361 return NS_OK;
362}
363
364void DictionaryCacheEntry::AccumulateHash(const char* aBuf, int32_t aCount) {
365 // Called from CacheFileOutputStream::Write, which may run on a non-main
366 // thread when the channel's delivery has been retargeted (e.g. by
367 // FetchDriver). Safe because during the save phase, mCrypto, mHash, and
368 // mDictionaryData are only accessed sequentially from the write path.
369 // No concurrent access occurs: mHash is empty (not yet computed),
370 // mDictionaryData is empty (not yet loaded), and mCrypto is only used
371 // by AccumulateHash/FinishHash which are called sequentially.
372 if (!mHash.IsEmpty()) {
373 if (!mDictionaryData.empty()) {
374 // We have data from the cache.... but if we change the hash there will
375 // be problems
376 // XXX dragons here
377 MOZ_DIAGNOSTIC_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "Accumulate Dictionary hash when we already have a hash and data"
")", "./../../../netwerk/cache2/Dictionary.cpp", 379); AnnotateMozCrashReason
("MOZ_DIAGNOSTIC_ASSERT" "(" "false" ") (" "Accumulate Dictionary hash when we already have a hash and data"
")"); do { MOZ_CrashSequence(__null, 379); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
378 false,do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "Accumulate Dictionary hash when we already have a hash and data"
")", "./../../../netwerk/cache2/Dictionary.cpp", 379); AnnotateMozCrashReason
("MOZ_DIAGNOSTIC_ASSERT" "(" "false" ") (" "Accumulate Dictionary hash when we already have a hash and data"
")"); do { MOZ_CrashSequence(__null, 379); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
379 "Accumulate Dictionary hash when we already have a hash and data")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "Accumulate Dictionary hash when we already have a hash and data"
")", "./../../../netwerk/cache2/Dictionary.cpp", 379); AnnotateMozCrashReason
("MOZ_DIAGNOSTIC_ASSERT" "(" "false" ") (" "Accumulate Dictionary hash when we already have a hash and data"
")"); do { MOZ_CrashSequence(__null, 379); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
380 return;
381 }
382 // accumulating a new hash when we have an existing?
383 // XXX probably kill the hash when we get an overwrite; tricky, need to
384 // handle loading the old one into ram to decompress the new one. Also,
385 // what if the old one is being used for multiple requests, one of which
386 // is an overwrite? This is an edge case not discussed in the spec - we
387 // could separate out a structure for in-flight requests where the data
388 // would be used from, so the Entry could be overwritten as needed
389 MOZ_DIAGNOSTIC_ASSERT(do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "Accumulate Dictionary hash when we already have a hash"
")", "./../../../netwerk/cache2/Dictionary.cpp", 390); AnnotateMozCrashReason
("MOZ_DIAGNOSTIC_ASSERT" "(" "false" ") (" "Accumulate Dictionary hash when we already have a hash"
")"); do { MOZ_CrashSequence(__null, 390); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
390 false, "Accumulate Dictionary hash when we already have a hash")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(false)>::isValid, "invalid assertion condition");
if ((__builtin_expect(!!(!(!!(false))), 0))) { do { } while (
false); MOZ_ReportAssertionFailure("false" " (" "Accumulate Dictionary hash when we already have a hash"
")", "./../../../netwerk/cache2/Dictionary.cpp", 390); AnnotateMozCrashReason
("MOZ_DIAGNOSTIC_ASSERT" "(" "false" ") (" "Accumulate Dictionary hash when we already have a hash"
")"); do { MOZ_CrashSequence(__null, 390); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
391 return; // XXX
392 }
393 size_t dataLen = mDictionaryData.length();
394 if (!mCrypto) {
395 DICTIONARY_LOG(("Calculating new hash for %s", mURI.get()))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Calculating new hash for %s"
, mURI.get()); } } while (0)
;
396 // If mCrypto is null, and mDictionaryData is set, we've already got the
397 // data for this dictionary.
398 nsresult rv;
399 mCrypto = do_CreateInstance(NS_CRYPTO_HASH_CONTRACTID"@mozilla.org/security/hash;1", &rv);
400 if (NS_WARN_IF(NS_FAILED(rv))NS_warn_if_impl(((bool)(__builtin_expect(!!(NS_FAILED_impl(rv
)), 0))), "NS_FAILED(rv)", "./../../../netwerk/cache2/Dictionary.cpp"
, 400)
) {
401 return;
402 }
403 rv = mCrypto->Init(nsICryptoHash::SHA256);
404 NS_WARNING_ASSERTION(NS_SUCCEEDED(rv), "Cache InitCrypto failed")do { if (!(((bool)(__builtin_expect(!!(!NS_FAILED_impl(rv)), 1
))))) { NS_DebugBreak(NS_DEBUG_WARNING, "Cache InitCrypto failed"
, "NS_SUCCEEDED(rv)", "./../../../netwerk/cache2/Dictionary.cpp"
, 404); } } while (false)
;
405 }
406 // Detect if we're hashing compressed data — the cache should store
407 // decompressed dictionary bytes.
408 if (MOZ_UNLIKELY(MOZ_LOG_TEST(gDictionaryLog, mozilla::LogLevel::Debug))(__builtin_expect(!!((__builtin_expect(!!(mozilla::detail::log_test
(gDictionaryLog, mozilla::LogLevel::Debug)), 0))), 0))
) {
409 if (dataLen == 0 && aCount >= 2) {
410 const uint8_t* bytes = reinterpret_cast<const uint8_t*>(aBuf);
411 if (bytes[0] == GZIP_MAGIC_00x1f && bytes[1] == GZIP_MAGIC_10x8b) {
412 DICTIONARY_LOG((do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "**** WARNING: AccumulateHash for %s starts with gzip magic bytes! "
"Data may be stored compressed instead of decompressed.", mURI
.get()); } } while (0)
413 "**** WARNING: AccumulateHash for %s starts with gzip magic bytes! "do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "**** WARNING: AccumulateHash for %s starts with gzip magic bytes! "
"Data may be stored compressed instead of decompressed.", mURI
.get()); } } while (0)
414 "Data may be stored compressed instead of decompressed.",do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "**** WARNING: AccumulateHash for %s starts with gzip magic bytes! "
"Data may be stored compressed instead of decompressed.", mURI
.get()); } } while (0)
415 mURI.get()))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "**** WARNING: AccumulateHash for %s starts with gzip magic bytes! "
"Data may be stored compressed instead of decompressed.", mURI
.get()); } } while (0)
;
416 } else if (bytes[0] == BROTLI_BYTE_00xce && bytes[1] == BROTLI_BYTE_10xb2) {
417 // brotli has no fixed magic, but 0xceb2 is common for shared brotli
418 // dict
419 DICTIONARY_LOG(do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "*** NOTE: AccumulateHash likely brotli for %s"
, mURI.get()); } } while (0)
420 ("*** NOTE: AccumulateHash likely brotli for %s", mURI.get()))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "*** NOTE: AccumulateHash likely brotli for %s"
, mURI.get()); } } while (0)
;
421 }
422 }
423 }
424 mCrypto->Update(reinterpret_cast<const uint8_t*>(aBuf), aCount);
425 DICTIONARY_LOG(do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Accumulate Hash %p: %d bytes, total %zu"
, this, aCount, dataLen); } } while (0)
426 ("Accumulate Hash %p: %d bytes, total %zu", this, aCount, dataLen))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Accumulate Hash %p: %d bytes, total %zu"
, this, aCount, dataLen); } } while (0)
;
427}
428
429void DictionaryCacheEntry::FinishHash() {
430 // May be called off main thread when channel delivery is retargeted.
431 // Hash computation is safe off-thread; origin operations are dispatched.
432 if (mCrypto) {
433 mCrypto->Finish(true, mHash);
434 mCrypto = nullptr;
435 DICTIONARY_LOG(("Hash for %p (%s) is %s", this, mURI.get(), mHash.get()))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Hash for %p (%s) is %s"
, this, mURI.get(), mHash.get()); } } while (0)
;
436 if (mOrigin) {
437 if (NS_IsMainThread()) {
438 FinishHashOnMainThread();
439 } else {
440 NS_DispatchToMainThread(NewRunnableMethod(
441 "DictionaryCacheEntry::FinishHashOnMainThread", this,
442 &DictionaryCacheEntry::FinishHashOnMainThread));
443 }
444 }
445 }
446}
447
448void DictionaryCacheEntry::FinishHashOnMainThread() {
449 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "./../../../netwerk/cache2/Dictionary.cpp", 449); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { MOZ_CrashSequence
(__null, 449); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
450 RefPtr<DictionaryOrigin> origin = std::move(mOrigin);
451 if (!origin) {
452 return;
453 }
454 DICTIONARY_LOG(("Write on hash"))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Write on hash");
} } while (0)
;
455 if (NS_FAILED(origin->Write(this))((bool)(__builtin_expect(!!(NS_FAILED_impl(origin->Write(this
))), 0)))
) {
456 origin->RemoveEntry(this);
457 return;
458 }
459 if (!mBlocked) {
460 origin->FinishAddEntry(this);
461 }
462}
463
464// Version of metadata entries we expect
465static const uint32_t METADATA_VERSION = 1;
466
467// Metadata format:
468// |version|hash|pattern|[matchdest|]*||id|expiration|type
469//
470// * Entries:
471// ** CString: URI -- the key, not in the entry
472// ** CString: Version (1)
473// ** CString: Hash
474// ** CString: Pattern
475// ** match-dest CString list, terminated by empty string
476// *** CString: Match-dest
477// ** CString: Id
478// ** uint32 as a CString: expiration. If missing, 0 (none)
479// ** CString: type -- defaults to 'raw' if missing
480// We store strings with a delimiter, and use escapes for delimiters or escape
481// characters in the source strings.
482//
483
484// Escape the string and append to aOutput
485static void EscapeMetadataString(const nsACString& aInput, nsCString& aOutput) {
486 // First calculate how much we'll need to append. Means we'll walk the source
487 // twice, but avoids any potential multiple reallocations
488 size_t len = 1; // for initial |
489 for (size_t i = 0; i < aInput.Length(); ++i) {
490 if (aInput[i] == '|' || aInput[i] == '\\') {
491 len += 2;
492 } else {
493 len++;
494 }
495 }
496 aOutput.SetCapacity(aOutput.Length() + len);
497
498 aOutput.AppendLiteral("|");
499 for (size_t i = 0; i < aInput.Length(); ++i) {
500 if (aInput[i] == '|' || aInput[i] == '\\') {
501 aOutput.Append('\\');
502 }
503 aOutput.Append(aInput[i]);
504 }
505}
506
507void DictionaryCacheEntry::MakeMetadataEntry(nsCString& aNewValue) {
508 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "./../../../netwerk/cache2/Dictionary.cpp", 508); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { MOZ_CrashSequence
(__null, 508); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
509 aNewValue.AppendLiteral("|"), aNewValue.AppendInt(METADATA_VERSION),
510 EscapeMetadataString(mHash, aNewValue);
511 EscapeMetadataString(mPattern, aNewValue);
512 EscapeMetadataString(mId, aNewValue);
513 for (auto& dest : mMatchDest) {
514 EscapeMetadataString(dom::GetEnumString(dest), aNewValue);
515 }
516 // List of match-dest values is terminated by an empty string
517 EscapeMetadataString(""_ns, aNewValue);
518 // Expiration time, as a CString
519 nsAutoCStringN<12> expiration;
520 expiration = nsPrintfCString("%u", mExpiration);
521 EscapeMetadataString(expiration, aNewValue);
522 // We don't store type, since we only support type 'raw' We can support
523 // type in the future by considering missing type as raw without changing the
524 // format
525}
526
527nsresult DictionaryCacheEntry::Write(nsICacheEntry* aCacheEntry) {
528 nsAutoCStringN<2048> metadata;
529 MakeMetadataEntry(metadata);
530 DICTIONARY_LOG(do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "DictionaryCacheEntry::Write %s %s"
, mURI.get(), metadata.get()); } } while (0)
531 ("DictionaryCacheEntry::Write %s %s", mURI.get(), metadata.get()))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "DictionaryCacheEntry::Write %s %s"
, mURI.get(), metadata.get()); } } while (0)
;
532 nsresult rv = aCacheEntry->SetMetaDataElement(mURI.get(), metadata.get());
533 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
534 return rv;
535 }
536 return aCacheEntry->MetaDataReady();
537}
538
539nsresult DictionaryCacheEntry::RemoveEntry(nsICacheEntry* aCacheEntry) {
540 DICTIONARY_LOG(("RemoveEntry from metadata for %s", mURI.get()))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "RemoveEntry from metadata for %s"
, mURI.get()); } } while (0)
;
541 nsresult rv = aCacheEntry->SetMetaDataElement(mURI.get(), nullptr);
542 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
543 return rv;
544 }
545 return aCacheEntry->MetaDataReady();
546}
547
548// Parse - | for field seperator; \ for escape of | or \ .
549static const char* GetEncodedString(const char* aSrc, nsACString& aOutput) {
550 // scan the input string and build the output, handling escapes
551 aOutput.Truncate();
552 MOZ_ASSERT(*aSrc == '|' || *aSrc == 0)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(*aSrc == '|' || *aSrc == 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(*aSrc == '|' || *aSrc == 0))
), 0))) { do { } while (false); MOZ_ReportAssertionFailure("*aSrc == '|' || *aSrc == 0"
, "./../../../netwerk/cache2/Dictionary.cpp", 552); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "*aSrc == '|' || *aSrc == 0" ")"); do { MOZ_CrashSequence
(__null, 552); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
553 if (!aSrc || *aSrc != '|') {
554 return aSrc;
555 }
556 aSrc++;
557 while (*aSrc) {
558 if (*aSrc == '|') {
559 break;
560 }
561 if (*aSrc == '\\') {
562 aSrc++;
563 }
564 aOutput.Append(*aSrc++);
565 }
566 return aSrc;
567}
568
569// Parse metadata from DictionaryOrigin
570bool DictionaryCacheEntry::ParseMetadata(const char* aSrc) {
571 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "./../../../netwerk/cache2/Dictionary.cpp", 571); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { MOZ_CrashSequence
(__null, 571); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
572 // Using mHash as a temp for version
573 aSrc = GetEncodedString(aSrc, mHash);
574 const char* tmp = mHash.get();
575 uint32_t version = atoi(tmp);
576 if (version != METADATA_VERSION) {
577 return false;
578 }
579 aSrc = GetEncodedString(aSrc, mHash);
580 aSrc = GetEncodedString(aSrc, mPattern);
581 aSrc = GetEncodedString(aSrc, mId);
582 nsAutoCString temp;
583 // get match-dest values (list ended with empty string)
584 do {
585 aSrc = GetEncodedString(aSrc, temp);
586 if (!temp.IsEmpty()) {
587 dom::RequestDestination dest =
588 dom::StringToEnum<dom::RequestDestination>(temp).valueOr(
589 dom::RequestDestination::_empty);
590 if (dest != dom::RequestDestination::_empty) {
591 mMatchDest.AppendElement(dest);
592 }
593 }
594 } while (!temp.IsEmpty());
595 if (*aSrc == '|') {
596 char* newSrc;
597 mExpiration = strtoul(++aSrc, &newSrc, 10);
598 aSrc = newSrc;
599 } // else leave default of 0
600 // XXX type - we assume and only support 'raw', may be missing
601 aSrc = GetEncodedString(aSrc, temp);
Value stored to 'aSrc' is never read
602
603 DICTIONARY_LOG(do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Parse entry %s: |%s| %s match-dest[0]=%s id=%s"
, mURI.get(), mHash.get(), mPattern.get(), mMatchDest.Length(
) > 0 ? dom::GetEnumString(mMatchDest[0]).get() : "", mId.
get()); } } while (0)
604 ("Parse entry %s: |%s| %s match-dest[0]=%s id=%s", mURI.get(),do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Parse entry %s: |%s| %s match-dest[0]=%s id=%s"
, mURI.get(), mHash.get(), mPattern.get(), mMatchDest.Length(
) > 0 ? dom::GetEnumString(mMatchDest[0]).get() : "", mId.
get()); } } while (0)
605 mHash.get(), mPattern.get(),do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Parse entry %s: |%s| %s match-dest[0]=%s id=%s"
, mURI.get(), mHash.get(), mPattern.get(), mMatchDest.Length(
) > 0 ? dom::GetEnumString(mMatchDest[0]).get() : "", mId.
get()); } } while (0)
606 mMatchDest.Length() > 0 ? dom::GetEnumString(mMatchDest[0]).get() : "",do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Parse entry %s: |%s| %s match-dest[0]=%s id=%s"
, mURI.get(), mHash.get(), mPattern.get(), mMatchDest.Length(
) > 0 ? dom::GetEnumString(mMatchDest[0]).get() : "", mId.
get()); } } while (0)
607 mId.get()))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Parse entry %s: |%s| %s match-dest[0]=%s id=%s"
, mURI.get(), mHash.get(), mPattern.get(), mMatchDest.Length(
) > 0 ? dom::GetEnumString(mMatchDest[0]).get() : "", mId.
get()); } } while (0)
;
608 return true;
609}
610
611void DictionaryCacheEntry::AppendMatchDest(nsACString& aDest) const {
612 for (auto& dest : mMatchDest) {
613 aDest.Append(dom::GetEnumString(dest));
614 aDest.Append(" ");
615 }
616}
617
618//-----------------------------------------------------------------------------
619// nsIStreamListener implementation
620//-----------------------------------------------------------------------------
621
622NS_IMETHODIMPnsresult
623DictionaryCacheEntry::OnStartRequest(nsIRequest* request) {
624 DICTIONARY_LOG(("DictionaryCacheEntry %s OnStartRequest", mURI.get()))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "DictionaryCacheEntry %s OnStartRequest"
, mURI.get()); } } while (0)
;
625 return NS_OK;
626}
627
628NS_IMETHODIMPnsresult
629DictionaryCacheEntry::OnDataAvailable(nsIRequest* request,
630 nsIInputStream* aInputStream,
631 uint64_t aOffset, uint32_t aCount) {
632 uint32_t n;
633 DICTIONARY_LOG(do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "DictionaryCacheEntry %s OnDataAvailable %u"
, mURI.get(), aCount); } } while (0)
634 ("DictionaryCacheEntry %s OnDataAvailable %u", mURI.get(), aCount))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "DictionaryCacheEntry %s OnDataAvailable %u"
, mURI.get(), aCount); } } while (0)
;
635 return aInputStream->ReadSegments(&DictionaryCacheEntry::ReadCacheData, this,
636 aCount, &n);
637}
638
639/* static */
640nsresult DictionaryCacheEntry::ReadCacheData(
641 nsIInputStream* aInStream, void* aClosure, const char* aFromSegment,
642 uint32_t aToOffset, uint32_t aCount, uint32_t* aWriteCount) {
643 DictionaryCacheEntry* self = static_cast<DictionaryCacheEntry*>(aClosure);
644
645 (void)self->mPendingDictionaryData.append(aFromSegment, aCount);
646 DICTIONARY_LOG(("Accumulate %p (%s): %d bytes, total %zu", self,do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Accumulate %p (%s): %d bytes, total %zu"
, self, self->mURI.get(), aCount, self->mPendingDictionaryData
.length()); } } while (0)
647 self->mURI.get(), aCount,do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Accumulate %p (%s): %d bytes, total %zu"
, self, self->mURI.get(), aCount, self->mPendingDictionaryData
.length()); } } while (0)
648 self->mPendingDictionaryData.length()))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Accumulate %p (%s): %d bytes, total %zu"
, self, self->mURI.get(), aCount, self->mPendingDictionaryData
.length()); } } while (0)
;
649 *aWriteCount = aCount;
650 return NS_OK;
651}
652
653void DictionaryCacheEntry::CleanupOnCacheData(nsresult result) {
654 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "./../../../netwerk/cache2/Dictionary.cpp", 654); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { MOZ_CrashSequence
(__null, 654); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
655
656 DICTIONARY_LOG(("Unsuspending %zu channels", mWaitingPrefetch.size()))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Unsuspending %zu channels"
, mWaitingPrefetch.size()); } } while (0)
;
657
658 // if we suspended, un-suspend the channel(s)
659 std::vector<PrefetchRequest> callbacks = std::move(mWaitingPrefetch);
660
661 for (auto& request : callbacks) {
662 (request.callback)(result);
663 }
664
665 // If we have a replacement entry waiting, unsuspend its channels too
666 if (mReplacement) {
667 DICTIONARY_LOG(("Unsuspending %zu replacement channels",do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Unsuspending %zu replacement channels"
, mReplacement->mWaitingPrefetch.size()); } } while (0)
668 mReplacement->mWaitingPrefetch.size()))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Unsuspending %zu replacement channels"
, mReplacement->mWaitingPrefetch.size()); } } while (0)
;
669 std::vector<PrefetchRequest> replacementCallbacks =
670 std::move(mReplacement->mWaitingPrefetch);
671
672 for (auto& request : replacementCallbacks) {
673 (request.callback)(result);
674 }
675 }
676
677 // If we're being replaced by a new entry, swap now
678 RefPtr<DictionaryCacheEntry> self;
679 if (mReplacement) {
680 DICTIONARY_LOG(("*** Replacing entry %p with %p for %s", this,do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "*** Replacing entry %p with %p for %s"
, this, mReplacement.get(), mURI.get()); } } while (0)
681 mReplacement.get(), mURI.get()))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "*** Replacing entry %p with %p for %s"
, this, mReplacement.get(), mURI.get()); } } while (0)
;
682 // Make sure we don't destroy ourselves
683 self = this;
684 mReplacement->mShouldSuspend = false;
685 mOrigin->RemoveEntry(this);
686 // When mReplacement gets all it's data, it will be added to mEntries
687 mReplacement->UnblockAddEntry(mOrigin);
688 mOrigin = nullptr;
689 }
690}
691
692NS_IMETHODIMPnsresult
693DictionaryCacheEntry::OnStopRequest(nsIRequest* request, nsresult result) {
694 DICTIONARY_LOG(("DictionaryCacheEntry %s OnStopRequest", mURI.get()))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "DictionaryCacheEntry %s OnStopRequest"
, mURI.get()); } } while (0)
;
695
696 Vector<uint8_t> pendingData;
697 nsCString computedHash;
698
699 if (NS_SUCCEEDED(result)((bool)(__builtin_expect(!!(!NS_FAILED_impl(result)), 1)))) {
700 // Move pending data for validation
701 pendingData = std::move(mPendingDictionaryData);
702 }
703
704 // Check if loaded data looks compressed (gzip/zstd magic bytes)
705 if (MOZ_UNLIKELY(MOZ_LOG_TEST(gDictionaryLog, mozilla::LogLevel::Debug))(__builtin_expect(!!((__builtin_expect(!!(mozilla::detail::log_test
(gDictionaryLog, mozilla::LogLevel::Debug)), 0))), 0))
) {
706 if (NS_SUCCEEDED(result)((bool)(__builtin_expect(!!(!NS_FAILED_impl(result)), 1))) && pendingData.length() >= 4) {
707 const uint8_t* b = pendingData.begin();
708 if (b[0] == GZIP_MAGIC_00x1f && b[1] == GZIP_MAGIC_10x8b) {
709 DICTIONARY_LOG(do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "WARNING: Prefetched dictionary data for %s starts with gzip "
"magic! length=%zu. Cache stored compressed data.", mURI.get
(), pendingData.length()); } } while (0)
710 ("WARNING: Prefetched dictionary data for %s starts with gzip "do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "WARNING: Prefetched dictionary data for %s starts with gzip "
"magic! length=%zu. Cache stored compressed data.", mURI.get
(), pendingData.length()); } } while (0)
711 "magic! length=%zu. Cache stored compressed data.",do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "WARNING: Prefetched dictionary data for %s starts with gzip "
"magic! length=%zu. Cache stored compressed data.", mURI.get
(), pendingData.length()); } } while (0)
712 mURI.get(), pendingData.length()))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "WARNING: Prefetched dictionary data for %s starts with gzip "
"magic! length=%zu. Cache stored compressed data.", mURI.get
(), pendingData.length()); } } while (0)
;
713 } else if (b[0] == ZSTD_MAGIC_00x28 && b[1] == ZSTD_MAGIC_10xb5 &&
714 b[2] == ZSTD_MAGIC_20x2f && b[3] == ZSTD_MAGIC_30xfd) {
715 DICTIONARY_LOG(do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "WARNING: Prefetched dictionary data for %s starts with zstd "
"magic! length=%zu. Cache stored compressed data.", mURI.get
(), pendingData.length()); } } while (0)
716 ("WARNING: Prefetched dictionary data for %s starts with zstd "do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "WARNING: Prefetched dictionary data for %s starts with zstd "
"magic! length=%zu. Cache stored compressed data.", mURI.get
(), pendingData.length()); } } while (0)
717 "magic! length=%zu. Cache stored compressed data.",do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "WARNING: Prefetched dictionary data for %s starts with zstd "
"magic! length=%zu. Cache stored compressed data.", mURI.get
(), pendingData.length()); } } while (0)
718 mURI.get(), pendingData.length()))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "WARNING: Prefetched dictionary data for %s starts with zstd "
"magic! length=%zu. Cache stored compressed data.", mURI.get
(), pendingData.length()); } } while (0)
;
719 }
720 }
721 }
722
723 // Calculate hash of loaded data (can be done off-thread)
724 if (NS_SUCCEEDED(result)((bool)(__builtin_expect(!!(!NS_FAILED_impl(result)), 1))) && !pendingData.empty()) {
725 nsCOMPtr<nsICryptoHash> hasher =
726 do_CreateInstance(NS_CRYPTO_HASH_CONTRACTID"@mozilla.org/security/hash;1");
727 if (hasher) {
728 hasher->Init(nsICryptoHash::SHA256);
729 hasher->Update(pendingData.begin(),
730 static_cast<uint32_t>(pendingData.length()));
731 MOZ_ALWAYS_SUCCEEDS(hasher->Finish(true, computedHash))do { if ((__builtin_expect(!!(((bool)(__builtin_expect(!!(!NS_FAILED_impl
(hasher->Finish(true, computedHash))), 1)))), 1))) { } else
{ do { do { } while (false); MOZ_ReportCrash("" "NS_SUCCEEDED(hasher->Finish(true, computedHash))"
, "./../../../netwerk/cache2/Dictionary.cpp", 731); AnnotateMozCrashReason
("MOZ_CRASH(" "NS_SUCCEEDED(hasher->Finish(true, computedHash))"
")"); do { MOZ_CrashSequence(__null, 731); __attribute__((nomerge
)) ::abort(); } while (false); } while (false); } } while (false
)
;
732 }
733 }
734
735 // Dispatch to main thread to compare hash and install validated data
736 nsCOMPtr<nsIRunnable> runnable = NS_NewRunnableFunction(
737 "DictionaryCacheEntry::OnStopRequest",
738 [self = RefPtr{this}, result, computedHash = std::move(computedHash),
739 pendingData = std::move(pendingData)]() mutable {
740 nsresult finalResult = result;
741 bool shouldRemoveDictionary = false;
742
743 // Compare computed hash with stored hash on MainThread
744 if (NS_SUCCEEDED(finalResult)((bool)(__builtin_expect(!!(!NS_FAILED_impl(finalResult)), 1)
))
&& !pendingData.empty()) {
745 if (!self->mHash.IsEmpty() && !computedHash.Equals(self->mHash)) {
746 DICTIONARY_LOG(("Hash mismatch for %s: expected %s, computed %s",do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Hash mismatch for %s: expected %s, computed %s"
, self->mURI.get(), self->mHash.get(), computedHash.get
()); } } while (0)
747 self->mURI.get(), self->mHash.get(),do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Hash mismatch for %s: expected %s, computed %s"
, self->mURI.get(), self->mHash.get(), computedHash.get
()); } } while (0)
748 computedHash.get()))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Hash mismatch for %s: expected %s, computed %s"
, self->mURI.get(), self->mHash.get(), computedHash.get
()); } } while (0)
;
749 // Log stored Content-Encoding from cache metadata — if non-empty,
750 // the dictionary was stored compressed (decompressor not applied)
751 if (MOZ_UNLIKELY((__builtin_expect(!!((__builtin_expect(!!(mozilla::detail::log_test
(gDictionaryLog, mozilla::LogLevel::Debug)), 0))), 0))
752 MOZ_LOG_TEST(gDictionaryLog, mozilla::LogLevel::Debug))(__builtin_expect(!!((__builtin_expect(!!(mozilla::detail::log_test
(gDictionaryLog, mozilla::LogLevel::Debug)), 0))), 0))
) {
753 if (!self->mStoredContentEncoding.IsEmpty()) {
754 DICTIONARY_LOG(do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Hash mismatch: stored Content-Encoding was '%s' — "
"data is compressed!", self->mStoredContentEncoding.get()
); } } while (0)
755 ("Hash mismatch: stored Content-Encoding was '%s' — "do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Hash mismatch: stored Content-Encoding was '%s' — "
"data is compressed!", self->mStoredContentEncoding.get()
); } } while (0)
756 "data is compressed!",do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Hash mismatch: stored Content-Encoding was '%s' — "
"data is compressed!", self->mStoredContentEncoding.get()
); } } while (0)
757 self->mStoredContentEncoding.get()))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Hash mismatch: stored Content-Encoding was '%s' — "
"data is compressed!", self->mStoredContentEncoding.get()
); } } while (0)
;
758 }
759 // Log first bytes to detect compression format
760 if (pendingData.length() >= 4) {
761 const uint8_t* b = pendingData.begin();
762 DICTIONARY_LOG(do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Hash mismatch data: first bytes 0x%02x 0x%02x 0x%02x "
"0x%02x, length %zu %s", b[0], b[1], b[2], b[3], pendingData
.length(), (b[0] == 0x1f && b[1] == 0x8b) ? "(GZIP!)"
: (b[0] == 0x28 && b[1] == 0xb5 && b[2] == 0x2f
&& b[3] == 0xfd) ? "(ZSTD!)" : ""); } } while (0)
763 ("Hash mismatch data: first bytes 0x%02x 0x%02x 0x%02x "do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Hash mismatch data: first bytes 0x%02x 0x%02x 0x%02x "
"0x%02x, length %zu %s", b[0], b[1], b[2], b[3], pendingData
.length(), (b[0] == 0x1f && b[1] == 0x8b) ? "(GZIP!)"
: (b[0] == 0x28 && b[1] == 0xb5 && b[2] == 0x2f
&& b[3] == 0xfd) ? "(ZSTD!)" : ""); } } while (0)
764 "0x%02x, length %zu %s",do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Hash mismatch data: first bytes 0x%02x 0x%02x 0x%02x "
"0x%02x, length %zu %s", b[0], b[1], b[2], b[3], pendingData
.length(), (b[0] == 0x1f && b[1] == 0x8b) ? "(GZIP!)"
: (b[0] == 0x28 && b[1] == 0xb5 && b[2] == 0x2f
&& b[3] == 0xfd) ? "(ZSTD!)" : ""); } } while (0)
765 b[0], b[1], b[2], b[3], pendingData.length(),do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Hash mismatch data: first bytes 0x%02x 0x%02x 0x%02x "
"0x%02x, length %zu %s", b[0], b[1], b[2], b[3], pendingData
.length(), (b[0] == 0x1f && b[1] == 0x8b) ? "(GZIP!)"
: (b[0] == 0x28 && b[1] == 0xb5 && b[2] == 0x2f
&& b[3] == 0xfd) ? "(ZSTD!)" : ""); } } while (0)
766 (b[0] == 0x1f && b[1] == 0x8b) ? "(GZIP!)"do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Hash mismatch data: first bytes 0x%02x 0x%02x 0x%02x "
"0x%02x, length %zu %s", b[0], b[1], b[2], b[3], pendingData
.length(), (b[0] == 0x1f && b[1] == 0x8b) ? "(GZIP!)"
: (b[0] == 0x28 && b[1] == 0xb5 && b[2] == 0x2f
&& b[3] == 0xfd) ? "(ZSTD!)" : ""); } } while (0)
767 : (b[0] == 0x28 && b[1] == 0xb5 && b[2] == 0x2f &&do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Hash mismatch data: first bytes 0x%02x 0x%02x 0x%02x "
"0x%02x, length %zu %s", b[0], b[1], b[2], b[3], pendingData
.length(), (b[0] == 0x1f && b[1] == 0x8b) ? "(GZIP!)"
: (b[0] == 0x28 && b[1] == 0xb5 && b[2] == 0x2f
&& b[3] == 0xfd) ? "(ZSTD!)" : ""); } } while (0)
768 b[3] == 0xfd)do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Hash mismatch data: first bytes 0x%02x 0x%02x 0x%02x "
"0x%02x, length %zu %s", b[0], b[1], b[2], b[3], pendingData
.length(), (b[0] == 0x1f && b[1] == 0x8b) ? "(GZIP!)"
: (b[0] == 0x28 && b[1] == 0xb5 && b[2] == 0x2f
&& b[3] == 0xfd) ? "(ZSTD!)" : ""); } } while (0)
769 ? "(ZSTD!)"do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Hash mismatch data: first bytes 0x%02x 0x%02x 0x%02x "
"0x%02x, length %zu %s", b[0], b[1], b[2], b[3], pendingData
.length(), (b[0] == 0x1f && b[1] == 0x8b) ? "(GZIP!)"
: (b[0] == 0x28 && b[1] == 0xb5 && b[2] == 0x2f
&& b[3] == 0xfd) ? "(ZSTD!)" : ""); } } while (0)
770 : ""))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Hash mismatch data: first bytes 0x%02x 0x%02x 0x%02x "
"0x%02x, length %zu %s", b[0], b[1], b[2], b[3], pendingData
.length(), (b[0] == 0x1f && b[1] == 0x8b) ? "(GZIP!)"
: (b[0] == 0x28 && b[1] == 0xb5 && b[2] == 0x2f
&& b[3] == 0xfd) ? "(ZSTD!)" : ""); } } while (0)
;
771 }
772 }
773 // Report to OHTTP ping with dictionary URI's ETLD+1
774 // Only send if at least one waiting request is NOT in private
775 // browsing
776 bool hasNonPrivateRequest = false;
777 for (const auto& request : self->mWaitingPrefetch) {
778 if (!request.isPrivateBrowsing) {
779 hasNonPrivateRequest = true;
780 break;
781 }
782 }
783
784 if (hasNonPrivateRequest) {
785 nsAutoCString site;
786 nsCOMPtr<nsIURI> uri;
787 if (NS_SUCCEEDED(NS_NewURI(getter_AddRefs(uri), self->mURI))((bool)(__builtin_expect(!!(!NS_FAILED_impl(NS_NewURI(getter_AddRefs
(uri), self->mURI))), 1)))
) {
788 nsCOMPtr<nsIEffectiveTLDService> eTLDService =
789 do_GetService(NS_EFFECTIVETLDSERVICE_CONTRACTID"@mozilla.org/network/effective-tld-service;1");
790 if (eTLDService) {
791 (void)eTLDService->GetBaseDomain(uri, 0, site);
792 }
793 }
794 if (site.IsEmpty()) {
795 site.AssignLiteral("unknown");
796 }
797 mozilla::glean::network::ContentDecodingErrorReportExtra extra = {
798 .errorType = Some(nsCString("dict_hash_mismatch"_ns)),
799 .topLevelSite = Some(site)};
800 glean::network::content_decoding_error_report.Record(Some(extra));
801 }
802
803 finalResult = NS_ERROR_CORRUPTED_CONTENT;
804 pendingData.clear();
805 shouldRemoveDictionary = true;
806 } else {
807 // Hash matches or no hash to check - install the data
808 self->mDictionaryData = std::move(pendingData);
809 self->mDictionaryDataComplete = true;
810 }
811 }
812
813 if (NS_SUCCEEDED(finalResult)((bool)(__builtin_expect(!!(!NS_FAILED_impl(finalResult)), 1)
))
&& !self->mDictionaryDataComplete) {
814 DICTIONARY_LOG(("Zero-byte cache entry for %s", self->mURI.get()))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Zero-byte cache entry for %s"
, self->mURI.get()); } } while (0)
;
815 finalResult = NS_ERROR_FAILURE;
816 shouldRemoveDictionary = true;
817 }
818
819 self->CleanupOnCacheData(finalResult);
820 self->mStopReceived = true;
821 if (shouldRemoveDictionary) {
822 // Already on MainThread
823 DictionaryCache::RemoveDictionary(self->mURI);
824 }
825 });
826 NS_DispatchToMainThread(runnable);
827
828 return result;
829}
830
831void DictionaryCacheEntry::UnblockAddEntry(DictionaryOrigin* aOrigin) {
832 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "./../../../netwerk/cache2/Dictionary.cpp", 832); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { MOZ_CrashSequence
(__null, 832); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
833 if (!mHash.IsEmpty()) {
834 // Already done, we can move to mEntries now
835 aOrigin->FinishAddEntry(this);
836 }
837 mBlocked = false;
838}
839
840void DictionaryCacheEntry::WriteOnHash() {
841 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "./../../../netwerk/cache2/Dictionary.cpp", 841); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { MOZ_CrashSequence
(__null, 841); __attribute__((nomerge)) ::abort(); } while (false
); } } while (false)
;
842 if (!mHash.IsEmpty() && mOrigin) {
843 DICTIONARY_LOG(("Write already hashed"))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Write already hashed"
); } } while (0)
;
844 mOrigin->Write(this);
845 }
846}
847
848//-----------------------------------------------------------------------------
849// nsICacheEntryOpenCallback implementation
850//-----------------------------------------------------------------------------
851// Note: we don't care if the entry is stale since we're not loading it; we're
852// just saying with have this specific set of bits with this hash available
853// to use as a dictionary.
854
855// This may be called on a random thread due to
856// nsICacheStorage::CHECK_MULTITHREADED
857NS_IMETHODIMPnsresult
858DictionaryCacheEntry::OnCacheEntryCheck(nsICacheEntry* aEntry,
859 uint32_t* result) {
860 DICTIONARY_LOG(("OnCacheEntryCheck %p", this))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "OnCacheEntryCheck %p"
, this); } } while (0)
;
861 *result = nsICacheEntryOpenCallback::ENTRY_WANTED;
862 return NS_OK;
863}
864
865// This may be called on a random thread due to
866// nsICacheStorage::CHECK_MULTITHREADED
867NS_IMETHODIMPnsresult
868DictionaryCacheEntry::OnCacheEntryAvailable(nsICacheEntry* entry, bool isNew,
869 nsresult status) {
870 DICTIONARY_LOG(("OnCacheEntryAvailable %p, result %u, entry %p", this,do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "OnCacheEntryAvailable %p, result %u, entry %p"
, this, (uint32_t)status, entry); } } while (0)
871 (uint32_t)status, entry))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "OnCacheEntryAvailable %p, result %u, entry %p"
, this, (uint32_t)status, entry); } } while (0)
;
872 if (entry) {
873 if (MOZ_UNLIKELY(MOZ_LOG_TEST(gDictionaryLog, mozilla::LogLevel::Debug))(__builtin_expect(!!((__builtin_expect(!!(mozilla::detail::log_test
(gDictionaryLog, mozilla::LogLevel::Debug)), 0))), 0))
) {
874 // Check if the cache entry still has Content-Encoding in its stored
875 // response headers. If so, the data on disk is likely still compressed
876 // (the decompressor wasn't applied before saving).
877 nsCString responseHead;
878 if (NS_SUCCEEDED(entry->GetMetaDataElement(((bool)(__builtin_expect(!!(!NS_FAILED_impl(entry->GetMetaDataElement
( "response-head", getter_Copies(responseHead)))), 1)))
879 "response-head", getter_Copies(responseHead)))((bool)(__builtin_expect(!!(!NS_FAILED_impl(entry->GetMetaDataElement
( "response-head", getter_Copies(responseHead)))), 1)))
) {
880 // Extract Content-Encoding value from stored response headers
881 auto ceStart = responseHead.Find("Content-Encoding:"_ns);
882 if (ceStart != kNotFound) {
883 auto valueStart = ceStart + 17; // strlen("Content-Encoding:")
884 auto lineEnd = responseHead.FindChar('\n', valueStart);
885 if (lineEnd == kNotFound) {
886 lineEnd = responseHead.Length();
887 }
888 mStoredContentEncoding =
889 Substring(responseHead, valueStart, lineEnd - valueStart);
890 mStoredContentEncoding.Trim(" \t\r");
891 DICTIONARY_LOG(do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "WARNING: Cache entry for dictionary %s has stored "
"Content-Encoding: '%s'. Data is likely compressed!", mURI.get
(), mStoredContentEncoding.get()); } } while (0)
892 ("WARNING: Cache entry for dictionary %s has stored "do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "WARNING: Cache entry for dictionary %s has stored "
"Content-Encoding: '%s'. Data is likely compressed!", mURI.get
(), mStoredContentEncoding.get()); } } while (0)
893 "Content-Encoding: '%s'. Data is likely compressed!",do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "WARNING: Cache entry for dictionary %s has stored "
"Content-Encoding: '%s'. Data is likely compressed!", mURI.get
(), mStoredContentEncoding.get()); } } while (0)
894 mURI.get(), mStoredContentEncoding.get()))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "WARNING: Cache entry for dictionary %s has stored "
"Content-Encoding: '%s'. Data is likely compressed!", mURI.get
(), mStoredContentEncoding.get()); } } while (0)
;
895 }
896 }
897 }
898
899 nsCOMPtr<nsIInputStream> stream;
900 entry->OpenInputStream(0, getter_AddRefs(stream));
901 if (!stream) {
902 DICTIONARY_LOG(("OpenInputStream failed for %s", mURI.get()))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "OpenInputStream failed for %s"
, mURI.get()); } } while (0)
;
903 nsCOMPtr<nsIRunnable> runnable = NS_NewRunnableFunction(
904 "DictionaryCacheEntry::OnCacheEntryAvailable",
905 [self = RefPtr{this}]() {
906 self->CleanupOnCacheData(NS_ERROR_FAILURE);
907 DictionaryCache::RemoveDictionary(self->mURI);
908 });
909 NS_DispatchToMainThread(runnable);
910 return NS_OK;
911 }
912
913 // nsInputStreamPump supports off-main-thread use: when constructed
914 // off-thread it sets mOffMainThread and targets the calling thread's
915 // serial event target, so callbacks fire on whatever thread calls
916 // AsyncRead.
917 RefPtr<nsInputStreamPump> pump;
918 nsresult rv = nsInputStreamPump::Create(getter_AddRefs(pump), stream);
919 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
920 DICTIONARY_LOG(("nsInputStreamPump::Create failed for %s", mURI.get()))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "nsInputStreamPump::Create failed for %s"
, mURI.get()); } } while (0)
;
921 NS_DispatchToMainThread(NS_NewRunnableFunction(
922 "DictionaryCacheEntry::OnCacheEntryAvailable",
923 [self = RefPtr{this}]() {
924 self->CleanupOnCacheData(NS_ERROR_FAILURE);
925 DictionaryCache::RemoveDictionary(self->mURI);
926 }));
927 return NS_OK;
928 }
929 rv = pump->AsyncRead(this);
930 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
931 DICTIONARY_LOG(("AsyncRead failed for %s", mURI.get()))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "AsyncRead failed for %s"
, mURI.get()); } } while (0)
;
932 NS_DispatchToMainThread(NS_NewRunnableFunction(
933 "DictionaryCacheEntry::OnCacheEntryAvailable",
934 [self = RefPtr{this}]() {
935 self->CleanupOnCacheData(NS_ERROR_FAILURE);
936 DictionaryCache::RemoveDictionary(self->mURI);
937 }));
938 return NS_OK;
939 }
940 DICTIONARY_LOG(("Waiting for data"))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Waiting for data"
); } } while (0)
;
941 } else {
942 // Error out any channels waiting on this cache entry. Also,
943 // remove the dictionary entry from the origin.
944 mNotCached = true; // For Prefetch()
945 DICTIONARY_LOG(("Prefetched cache entry not available!!!"))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Prefetched cache entry not available!!!"
); } } while (0)
;
946
947 // Dispatch cleanup to main thread
948 nsCString uriCopy = mURI;
949 nsCOMPtr<nsIRunnable> runnable = NS_NewRunnableFunction(
950 "DictionaryCacheEntry::OnCacheEntryAvailable",
951 [self = RefPtr{this}, uriCopy]() {
952 self->CleanupOnCacheData(NS_ERROR_CORRUPTED_CONTENT);
953 DictionaryCache::RemoveDictionary(self->mURI);
954 });
955 NS_DispatchToMainThread(runnable);
956 }
957
958 return NS_OK;
959}
960
961//----------------------------------------------------------------------------------
962
963// Read the metadata for an Origin and parse it, creating DictionaryCacheEntrys
964// as needed. If aType is TYPE_OTHER, there is no Match() to do
965void DictionaryOriginReader::Start(
966 bool aCreate, DictionaryOrigin* aOrigin, nsACString& aKey, nsIURI* aURI,
967 ExtContentPolicyType aType, DictionaryCache* aCache,
968 const std::function<nsresult(bool, DictionaryCacheEntry*)>& aCallback) {
969 mOrigin = aOrigin;
970 mURI = aURI;
971 mType = aType;
972 mCallback = aCallback;
973 mCache = aCache;
974
975 AUTO_PROFILER_FLOW_MARKER("DictionaryOriginReader::Start", NETWORK,::mozilla::AutoProfilerFlowMarker raiiObject976( "DictionaryOriginReader::Start"
, ::mozilla::baseprofiler::category::NETWORK, Flow::FromPointer
(this))
976 Flow::FromPointer(this))::mozilla::AutoProfilerFlowMarker raiiObject976( "DictionaryOriginReader::Start"
, ::mozilla::baseprofiler::category::NETWORK, Flow::FromPointer
(this))
;
977
978 // The cache entry is for originattribute extension of
979 // META_DICTIONARY_PREFIX, plus key of prepath
980
981 // This also keeps this alive until we get the callback. We must do this
982 // BEFORE we call AsyncOpenURIString, or we may get a callback to
983 // OnCacheEntryAvailable before we can do this
984 mOrigin->mWaitingCacheRead.AppendElement(this);
985 if (mOrigin->mWaitingCacheRead.Length() == 1) { // was empty
986 DICTIONARY_LOG(("DictionaryOriginReader::Start(%s): %p",do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "DictionaryOriginReader::Start(%s): %p"
, TPromiseFlatString<char>(aKey).get(), this); } } while
(0)
987 PromiseFlatCString(aKey).get(), this))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "DictionaryOriginReader::Start(%s): %p"
, TPromiseFlatString<char>(aKey).get(), this); } } while
(0)
;
988 DictionaryCache::sCacheStorage->AsyncOpenURIString(
989 aKey, META_DICTIONARY_PREFIX"dict:"_ns,
990 aCreate
991 ? nsICacheStorage::OPEN_NORMALLY |
992 nsICacheStorage::CHECK_MULTITHREADED
993 : nsICacheStorage::OPEN_READONLY | nsICacheStorage::OPEN_SECRETLY |
994 nsICacheStorage::CHECK_MULTITHREADED,
995 this);
996 // This one will get the direct callback to do Match()
997 }
998 // Else we already have a read for this cache entry pending, just wait
999 // for that
1000}
1001
1002void DictionaryOriginReader::FinishMatch() {
1003 RefPtr<DictionaryCacheEntry> result;
1004 // Don't Match if this was a call from AddEntry()
1005 if (mType != ExtContentPolicy::TYPE_OTHER) {
1006 nsCString path;
1007 mURI->GetPathQueryRef(path);
1008 result = mOrigin->Match(path, mType);
1009 }
1010 DICTIONARY_LOG(("Done with reading origin for %p", mOrigin.get()))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Done with reading origin for %p"
, mOrigin.get()); } } while (0)
;
1011 (mCallback)(true, result);
1012}
1013
1014NS_IMPL_ISUPPORTS(DictionaryOriginReader, nsICacheEntryOpenCallback,MozExternalRefCountType DictionaryOriginReader::AddRef(void) {
static_assert(!std::is_destructible_v<DictionaryOriginReader
>, "Reference-counted class " "DictionaryOriginReader" " should not have a public destructor. "
"Make this class's destructor non-public"); do { static_assert
( mozilla::detail::AssertionConditionType<decltype(int32_t
(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "./../../../netwerk/cache2/Dictionary.cpp"
, 1015); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { MOZ_CrashSequence(__null, 1015
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("DictionaryOriginReader" != nullptr)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!("DictionaryOriginReader" != nullptr))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("\"DictionaryOriginReader\" != nullptr"
" (" "Must specify a name" ")", "./../../../netwerk/cache2/Dictionary.cpp"
, 1015); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"DictionaryOriginReader\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 1015); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("DictionaryOriginReader" " not thread-safe")
; nsrefcnt count = ++mRefCnt; NS_LogAddRef((this), (count), (
"DictionaryOriginReader"), (uint32_t)(sizeof(*this))); return
count; } MozExternalRefCountType DictionaryOriginReader::Release
(void) { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(int32_t(mRefCnt) > 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) > 0))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0"
" (" "dup release" ")", "./../../../netwerk/cache2/Dictionary.cpp"
, 1015); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { MOZ_CrashSequence(__null, 1015
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("DictionaryOriginReader" != nullptr)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!("DictionaryOriginReader" != nullptr))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("\"DictionaryOriginReader\" != nullptr"
" (" "Must specify a name" ")", "./../../../netwerk/cache2/Dictionary.cpp"
, 1015); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"DictionaryOriginReader\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 1015); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("DictionaryOriginReader" " not thread-safe")
; const char* const nametmp = "DictionaryOriginReader"; nsrefcnt
count = --mRefCnt; NS_LogRelease((this), (count), (nametmp))
; if (count == 0) { mRefCnt = 1; delete (this); return 0; } return
count; } nsresult DictionaryOriginReader::QueryInterface(const
nsIID& aIID, void** aInstancePtr) { do { if (!(aInstancePtr
)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!"
, "aInstancePtr", "./../../../netwerk/cache2/Dictionary.cpp",
1015); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE
; static_assert(2 > 0, "Need more arguments to NS_INTERFACE_TABLE"
); static const QITableEntry table[] = { {&mozilla::detail
::kImplementedIID<DictionaryOriginReader, nsICacheEntryOpenCallback
>, int32_t( reinterpret_cast<char*>(static_cast<nsICacheEntryOpenCallback
*>((DictionaryOriginReader*)0x1000)) - reinterpret_cast<
char*>((DictionaryOriginReader*)0x1000))}, {&mozilla::
detail::kImplementedIID<DictionaryOriginReader, nsIStreamListener
>, int32_t( reinterpret_cast<char*>(static_cast<nsIStreamListener
*>((DictionaryOriginReader*)0x1000)) - reinterpret_cast<
char*>((DictionaryOriginReader*)0x1000))}, {&mozilla::
detail::kImplementedIID<DictionaryOriginReader, nsISupports
>, int32_t(reinterpret_cast<char*>(static_cast<nsISupports
*>( static_cast<nsICacheEntryOpenCallback*>((DictionaryOriginReader
*)0x1000))) - reinterpret_cast<char*>((DictionaryOriginReader
*)0x1000))}, { nullptr, 0 } } ; static_assert(std::size(table
) > 1, "need at least 1 interface"); rv = NS_TableDrivenQI
(static_cast<void*>(this), aIID, aInstancePtr, table); return
rv; }
1015 nsIStreamListener)MozExternalRefCountType DictionaryOriginReader::AddRef(void) {
static_assert(!std::is_destructible_v<DictionaryOriginReader
>, "Reference-counted class " "DictionaryOriginReader" " should not have a public destructor. "
"Make this class's destructor non-public"); do { static_assert
( mozilla::detail::AssertionConditionType<decltype(int32_t
(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "./../../../netwerk/cache2/Dictionary.cpp"
, 1015); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { MOZ_CrashSequence(__null, 1015
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("DictionaryOriginReader" != nullptr)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!("DictionaryOriginReader" != nullptr))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("\"DictionaryOriginReader\" != nullptr"
" (" "Must specify a name" ")", "./../../../netwerk/cache2/Dictionary.cpp"
, 1015); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"DictionaryOriginReader\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 1015); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("DictionaryOriginReader" " not thread-safe")
; nsrefcnt count = ++mRefCnt; NS_LogAddRef((this), (count), (
"DictionaryOriginReader"), (uint32_t)(sizeof(*this))); return
count; } MozExternalRefCountType DictionaryOriginReader::Release
(void) { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(int32_t(mRefCnt) > 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) > 0))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0"
" (" "dup release" ")", "./../../../netwerk/cache2/Dictionary.cpp"
, 1015); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { MOZ_CrashSequence(__null, 1015
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("DictionaryOriginReader" != nullptr)>::isValid
, "invalid assertion condition"); if ((__builtin_expect(!!(!(
!!("DictionaryOriginReader" != nullptr))), 0))) { do { } while
(false); MOZ_ReportAssertionFailure("\"DictionaryOriginReader\" != nullptr"
" (" "Must specify a name" ")", "./../../../netwerk/cache2/Dictionary.cpp"
, 1015); AnnotateMozCrashReason("MOZ_ASSERT" "(" "\"DictionaryOriginReader\" != nullptr"
") (" "Must specify a name" ")"); do { MOZ_CrashSequence(__null
, 1015); __attribute__((nomerge)) ::abort(); } while (false);
} } while (false); if (!mRefCnt.isThreadSafe) _mOwningThread
.AssertOwnership("DictionaryOriginReader" " not thread-safe")
; const char* const nametmp = "DictionaryOriginReader"; nsrefcnt
count = --mRefCnt; NS_LogRelease((this), (count), (nametmp))
; if (count == 0) { mRefCnt = 1; delete (this); return 0; } return
count; } nsresult DictionaryOriginReader::QueryInterface(const
nsIID& aIID, void** aInstancePtr) { do { if (!(aInstancePtr
)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!"
, "aInstancePtr", "./../../../netwerk/cache2/Dictionary.cpp",
1015); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE
; static_assert(2 > 0, "Need more arguments to NS_INTERFACE_TABLE"
); static const QITableEntry table[] = { {&mozilla::detail
::kImplementedIID<DictionaryOriginReader, nsICacheEntryOpenCallback
>, int32_t( reinterpret_cast<char*>(static_cast<nsICacheEntryOpenCallback
*>((DictionaryOriginReader*)0x1000)) - reinterpret_cast<
char*>((DictionaryOriginReader*)0x1000))}, {&mozilla::
detail::kImplementedIID<DictionaryOriginReader, nsIStreamListener
>, int32_t( reinterpret_cast<char*>(static_cast<nsIStreamListener
*>((DictionaryOriginReader*)0x1000)) - reinterpret_cast<
char*>((DictionaryOriginReader*)0x1000))}, {&mozilla::
detail::kImplementedIID<DictionaryOriginReader, nsISupports
>, int32_t(reinterpret_cast<char*>(static_cast<nsISupports
*>( static_cast<nsICacheEntryOpenCallback*>((DictionaryOriginReader
*)0x1000))) - reinterpret_cast<char*>((DictionaryOriginReader
*)0x1000))}, { nullptr, 0 } } ; static_assert(std::size(table
) > 1, "need at least 1 interface"); rv = NS_TableDrivenQI
(static_cast<void*>(this), aIID, aInstancePtr, table); return
rv; }
1016
1017//-----------------------------------------------------------------------------
1018// nsICacheEntryOpenCallback implementation
1019//-----------------------------------------------------------------------------
1020
1021// This may be called on a random thread due to
1022// nsICacheStorage::CHECK_MULTITHREADED
1023NS_IMETHODIMPnsresult DictionaryOriginReader::OnCacheEntryCheck(nsICacheEntry* entry,
1024 uint32_t* result) {
1025 *result = nsICacheEntryOpenCallback::ENTRY_WANTED;
1026 DICTIONARY_LOG(do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "DictionaryOriginReader::OnCacheEntryCheck this=%p for entry %p"
, this, entry); } } while (0)
1027 ("DictionaryOriginReader::OnCacheEntryCheck this=%p for entry %p", this,do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "DictionaryOriginReader::OnCacheEntryCheck this=%p for entry %p"
, this, entry); } } while (0)
1028 entry))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "DictionaryOriginReader::OnCacheEntryCheck this=%p for entry %p"
, this, entry); } } while (0)
;
1029 return NS_OK;
1030}
1031
1032NS_IMETHODIMPnsresult DictionaryOriginReader::OnCacheEntryAvailable(
1033 nsICacheEntry* aCacheEntry, bool isNew, nsresult result) {
1034 MOZ_ASSERT(NS_IsMainThread(), "Got cache entry off main thread!")do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
" (" "Got cache entry off main thread!" ")", "./../../../netwerk/cache2/Dictionary.cpp"
, 1034); AnnotateMozCrashReason("MOZ_ASSERT" "(" "NS_IsMainThread()"
") (" "Got cache entry off main thread!" ")"); do { MOZ_CrashSequence
(__null, 1034); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
1035 DICTIONARY_LOG(do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "DictionaryOriginReader::OnCacheEntryAvailable this=%p for entry %p"
, this, aCacheEntry); } } while (0)
1036 ("DictionaryOriginReader::OnCacheEntryAvailable this=%p for entry %p",do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "DictionaryOriginReader::OnCacheEntryAvailable this=%p for entry %p"
, this, aCacheEntry); } } while (0)
1037 this, aCacheEntry))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "DictionaryOriginReader::OnCacheEntryAvailable this=%p for entry %p"
, this, aCacheEntry); } } while (0)
;
1038
1039 if (!aCacheEntry) {
1040 // Didn't have any dictionaries for this origin, and must have been readonly
1041 for (auto& reader : mOrigin->mWaitingCacheRead) {
1042 (reader->mCallback)(true, nullptr);
1043 }
1044 mOrigin->mWaitingCacheRead.Clear();
1045 AUTO_PROFILER_TERMINATING_FLOW_MARKER(::mozilla::AutoProfilerTerminatingFlowMarker raiiObject1047( "DictionaryOriginReader::OnCacheEntryAvailable"
, ::mozilla::baseprofiler::category::NETWORK, Flow::FromPointer
(this))
1046 "DictionaryOriginReader::OnCacheEntryAvailable", NETWORK,::mozilla::AutoProfilerTerminatingFlowMarker raiiObject1047( "DictionaryOriginReader::OnCacheEntryAvailable"
, ::mozilla::baseprofiler::category::NETWORK, Flow::FromPointer
(this))
1047 Flow::FromPointer(this))::mozilla::AutoProfilerTerminatingFlowMarker raiiObject1047( "DictionaryOriginReader::OnCacheEntryAvailable"
, ::mozilla::baseprofiler::category::NETWORK, Flow::FromPointer
(this))
;
1048 return NS_OK;
1049 }
1050
1051 mOrigin->SetCacheEntry(aCacheEntry);
1052 AUTO_PROFILER_FLOW_MARKER("DictionaryOriginReader::VisitMetaData", NETWORK,::mozilla::AutoProfilerFlowMarker raiiObject1053( "DictionaryOriginReader::VisitMetaData"
, ::mozilla::baseprofiler::category::NETWORK, Flow::FromPointer
(this))
1053 Flow::FromPointer(this))::mozilla::AutoProfilerFlowMarker raiiObject1053( "DictionaryOriginReader::VisitMetaData"
, ::mozilla::baseprofiler::category::NETWORK, Flow::FromPointer
(this))
;
1054 bool empty = false;
1055 aCacheEntry->GetIsEmpty(&empty);
1056 if (!empty) {
1057 // There's no data in the cache entry, just metadata
1058 nsCOMPtr<nsICacheEntryMetaDataVisitor> metadata(mOrigin);
1059 aCacheEntry->VisitMetaData(metadata);
1060 } // else new cache entry
1061
1062 // This list is the only thing keeping us alive
1063 RefPtr<DictionaryOriginReader> safety(this);
1064 for (auto& reader : mOrigin->mWaitingCacheRead) {
1065 reader->FinishMatch();
1066 }
1067 mOrigin->mWaitingCacheRead.Clear();
1068 AUTO_PROFILER_TERMINATING_FLOW_MARKER(::mozilla::AutoProfilerTerminatingFlowMarker raiiObject1070( "DictionaryOriginReader::OnCacheEntryAvailable"
, ::mozilla::baseprofiler::category::NETWORK, Flow::FromPointer
(this))
1069 "DictionaryOriginReader::OnCacheEntryAvailable", NETWORK,::mozilla::AutoProfilerTerminatingFlowMarker raiiObject1070( "DictionaryOriginReader::OnCacheEntryAvailable"
, ::mozilla::baseprofiler::category::NETWORK, Flow::FromPointer
(this))
1070 Flow::FromPointer(this))::mozilla::AutoProfilerTerminatingFlowMarker raiiObject1070( "DictionaryOriginReader::OnCacheEntryAvailable"
, ::mozilla::baseprofiler::category::NETWORK, Flow::FromPointer
(this))
;
1071 return NS_OK;
1072}
1073
1074//-----------------------------------------------------------------------------
1075// nsIStreamListener implementation
1076//-----------------------------------------------------------------------------
1077
1078NS_IMETHODIMPnsresult
1079DictionaryOriginReader::OnStartRequest(nsIRequest* request) {
1080 DICTIONARY_LOG(("DictionaryOriginReader %p OnStartRequest", this))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "DictionaryOriginReader %p OnStartRequest"
, this); } } while (0)
;
1081 return NS_OK;
1082}
1083
1084NS_IMETHODIMPnsresult
1085DictionaryOriginReader::OnDataAvailable(nsIRequest* request,
1086 nsIInputStream* aInputStream,
1087 uint64_t aOffset, uint32_t aCount) {
1088 DICTIONARY_LOG(do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "DictionaryOriginReader %p OnDataAvailable %u"
, this, aCount); } } while (0)
1089 ("DictionaryOriginReader %p OnDataAvailable %u", this, aCount))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "DictionaryOriginReader %p OnDataAvailable %u"
, this, aCount); } } while (0)
;
1090 return NS_OK;
1091}
1092
1093NS_IMETHODIMPnsresult
1094DictionaryOriginReader::OnStopRequest(nsIRequest* request, nsresult result) {
1095 DICTIONARY_LOG(("DictionaryOriginReader %p OnStopRequest", this))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "DictionaryOriginReader %p OnStopRequest"
, this); } } while (0)
;
1096 return NS_OK;
1097}
1098
1099// static
1100already_AddRefed<DictionaryCache> DictionaryCache::GetInstance() {
1101 // Return nullptr if shutdown has occurred to prevent resurrection
1102 if (sShutdown) {
1103 return nullptr;
1104 }
1105 // XXX lock? In practice probably not needed, in theory yes
1106 if (!gDictionaryCache) {
1107 gDictionaryCache = new DictionaryCache();
1108 }
1109 return do_AddRef(gDictionaryCache);
1110}
1111
1112nsresult DictionaryCache::Init() {
1113 if (XRE_IsParentProcess()) {
1114 nsCOMPtr<nsICacheStorageService> cacheStorageService(
1115 components::CacheStorage::Service());
1116 if (!cacheStorageService) {
1117 return NS_ERROR_FAILURE;
1118 }
1119 nsCOMPtr<nsICacheStorage> temp;
1120 nsresult rv = cacheStorageService->DiskCacheStorage(
1121 nullptr, getter_AddRefs(temp)); // Don't need a load context
1122 if (NS_FAILED(rv)((bool)(__builtin_expect(!!(NS_FAILED_impl(rv)), 0)))) {
1123 return rv;
1124 }
1125 sCacheStorage = temp;
1126
1127 nsCOMPtr<nsIObserverService> obsService =
1128 mozilla::services::GetObserverService();
1129 if (obsService) {
1130 obsService->AddObserver(this, "idle-daily", false);
1131 }
1132 }
1133 DICTIONARY_LOG(("Inited DictionaryCache %p", sCacheStorage.get()))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Inited DictionaryCache %p"
, sCacheStorage.get()); } } while (0)
;
1134 return NS_OK;
1135}
1136
1137void DictionaryCache::Shutdown() {
1138 DICTIONARY_LOG(("DictionaryCache::Shutdown"))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "DictionaryCache::Shutdown"
); } } while (0)
;
1139 sShutdown = true;
1140 if (XRE_IsParentProcess()) {
1141 nsCOMPtr<nsIObserverService> obsService =
1142 mozilla::services::GetObserverService();
1143 if (obsService && gDictionaryCache) {
1144 obsService->RemoveObserver(gDictionaryCache.get(), "idle-daily");
1145 }
1146 }
1147 gDictionaryCache = nullptr;
1148 sCacheStorage = nullptr;
1149}
1150
1151NS_IMETHODIMPnsresult
1152DictionaryCache::Observe(nsISupports* subject, const char* topic,
1153 const char16_t* data) {
1154 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "./../../../netwerk/cache2/Dictionary.cpp", 1154); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { MOZ_CrashSequence
(__null, 1154); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
1155 if (!strcmp(topic, "idle-daily")) {
1156 // Submit the content decoding error ping once per day
1157 glean_pings::ContentDecodingError.Submit();
1158 }
1159 return NS_OK;
1160}
1161
1162//-----------------------------------------------------------------------------
1163// DictionaryCache::nsISupports
1164//-----------------------------------------------------------------------------
1165
1166NS_IMPL_ISUPPORTS(DictionaryCache, nsIObserver)MozExternalRefCountType DictionaryCache::AddRef(void) { static_assert
(!std::is_destructible_v<DictionaryCache>, "Reference-counted class "
"DictionaryCache" " should not have a public destructor. " "Make this class's destructor non-public"
); do { static_assert( mozilla::detail::AssertionConditionType
<decltype(int32_t(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "./../../../netwerk/cache2/Dictionary.cpp"
, 1166); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { MOZ_CrashSequence(__null, 1166
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("DictionaryCache" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("DictionaryCache" != nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"\"DictionaryCache\" != nullptr" " (" "Must specify a name" ")"
, "./../../../netwerk/cache2/Dictionary.cpp", 1166); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "\"DictionaryCache\" != nullptr" ") (" "Must specify a name"
")"); do { MOZ_CrashSequence(__null, 1166); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); if (!mRefCnt
.isThreadSafe) _mOwningThread.AssertOwnership("DictionaryCache"
" not thread-safe"); nsrefcnt count = ++mRefCnt; NS_LogAddRef
((this), (count), ("DictionaryCache"), (uint32_t)(sizeof(*this
))); return count; } MozExternalRefCountType DictionaryCache::
Release(void) { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(int32_t(mRefCnt) > 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) > 0))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0"
" (" "dup release" ")", "./../../../netwerk/cache2/Dictionary.cpp"
, 1166); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { MOZ_CrashSequence(__null, 1166
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("DictionaryCache" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("DictionaryCache" != nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"\"DictionaryCache\" != nullptr" " (" "Must specify a name" ")"
, "./../../../netwerk/cache2/Dictionary.cpp", 1166); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "\"DictionaryCache\" != nullptr" ") (" "Must specify a name"
")"); do { MOZ_CrashSequence(__null, 1166); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); if (!mRefCnt
.isThreadSafe) _mOwningThread.AssertOwnership("DictionaryCache"
" not thread-safe"); const char* const nametmp = "DictionaryCache"
; nsrefcnt count = --mRefCnt; NS_LogRelease((this), (count), (
nametmp)); if (count == 0) { mRefCnt = 1; delete (this); return
0; } return count; } nsresult DictionaryCache::QueryInterface
(const nsIID& aIID, void** aInstancePtr) { do { if (!(aInstancePtr
)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!"
, "aInstancePtr", "./../../../netwerk/cache2/Dictionary.cpp",
1166); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE
; static_assert(1 > 0, "Need more arguments to NS_INTERFACE_TABLE"
); static const QITableEntry table[] = { {&mozilla::detail
::kImplementedIID<DictionaryCache, nsIObserver>, int32_t
( reinterpret_cast<char*>(static_cast<nsIObserver*>
((DictionaryCache*)0x1000)) - reinterpret_cast<char*>((
DictionaryCache*)0x1000))}, {&mozilla::detail::kImplementedIID
<DictionaryCache, nsISupports>, int32_t(reinterpret_cast
<char*>(static_cast<nsISupports*>( static_cast<
nsIObserver*>((DictionaryCache*)0x1000))) - reinterpret_cast
<char*>((DictionaryCache*)0x1000))}, { nullptr, 0 } } ;
static_assert(std::size(table) > 1, "need at least 1 interface"
); rv = NS_TableDrivenQI(static_cast<void*>(this), aIID
, aInstancePtr, table); return rv; }
1167
1168nsresult DictionaryCache::AddEntry(nsIURI* aURI, const nsACString& aKey,
1169 const nsACString& aPattern,
1170 nsTArray<nsCString>& aMatchDest,
1171 const nsACString& aId,
1172 const Maybe<nsCString>& aHash,
1173 bool aNewEntry, uint32_t aExpiration,
1174 DictionaryCacheEntry** aDictEntry) {
1175 // Note that normally we're getting an entry in and until all the data
1176 // has been received, we can't use it. The Hash being null is a flag
1177 // that it's not yet valid.
1178 DICTIONARY_LOG(("AddEntry for %s, pattern %s, id %s, expiration %u",do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "AddEntry for %s, pattern %s, id %s, expiration %u"
, TPromiseFlatString<char>(aKey).get(), TPromiseFlatString
<char>(aPattern).get(), TPromiseFlatString<char>(
aId).get(), aExpiration); } } while (0)
1179 PromiseFlatCString(aKey).get(),do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "AddEntry for %s, pattern %s, id %s, expiration %u"
, TPromiseFlatString<char>(aKey).get(), TPromiseFlatString
<char>(aPattern).get(), TPromiseFlatString<char>(
aId).get(), aExpiration); } } while (0)
1180 PromiseFlatCString(aPattern).get(),do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "AddEntry for %s, pattern %s, id %s, expiration %u"
, TPromiseFlatString<char>(aKey).get(), TPromiseFlatString
<char>(aPattern).get(), TPromiseFlatString<char>(
aId).get(), aExpiration); } } while (0)
1181 PromiseFlatCString(aId).get(), aExpiration))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "AddEntry for %s, pattern %s, id %s, expiration %u"
, TPromiseFlatString<char>(aKey).get(), TPromiseFlatString
<char>(aPattern).get(), TPromiseFlatString<char>(
aId).get(), aExpiration); } } while (0)
;
1182 // Note that we don't know if there's an entry for this key in the origin
1183 RefPtr<DictionaryCacheEntry> dict = new DictionaryCacheEntry(
1184 aKey, aPattern, aMatchDest, aId, aExpiration, aHash);
1185 dict = AddEntry(aURI, aNewEntry, dict);
1186 if (dict) {
1187 *aDictEntry = do_AddRef(dict).take();
1188 return NS_OK;
1189 }
1190 DICTIONARY_LOG(do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; 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 adding entry for %s"
, TPromiseFlatString<char>(aKey).get()); } } while (0)
1191 ("Failed adding entry for %s", PromiseFlatCString(aKey).get()))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; 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 adding entry for %s"
, TPromiseFlatString<char>(aKey).get()); } } while (0)
;
1192 *aDictEntry = nullptr;
1193 return NS_ERROR_FAILURE;
1194}
1195
1196already_AddRefed<DictionaryCacheEntry> DictionaryCache::AddEntry(
1197 nsIURI* aURI, bool aNewEntry, DictionaryCacheEntry* aDictEntry) {
1198 // Note that normally we're getting an entry in and until all the data
1199 // has been received, we can't use it. The Hash being null is a flag
1200 // that it's not yet valid.
1201 nsCString prepath;
1202 if (NS_FAILED(GetDictPath(aURI, prepath))((bool)(__builtin_expect(!!(NS_FAILED_impl(GetDictPath(aURI, prepath
))), 0)))
) {
1203 return nullptr;
1204 }
1205 DICTIONARY_LOG(do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "AddEntry: %s, %d, %p"
, prepath.get(), aNewEntry, aDictEntry); } } while (0)
1206 ("AddEntry: %s, %d, %p", prepath.get(), aNewEntry, aDictEntry))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "AddEntry: %s, %d, %p"
, prepath.get(), aNewEntry, aDictEntry); } } while (0)
;
1207 // create for the origin if it doesn't exist
1208 RefPtr<DictionaryCacheEntry> newEntry;
1209 (void)mDictionaryCache.WithEntryHandle(prepath, [&](auto&& entry) {
1210 auto& origin = entry.OrInsertWith([&] {
1211 RefPtr<DictionaryOrigin> origin = new DictionaryOrigin(prepath, nullptr);
1212 // Create a cache entry for this if it doesn't exist. Note
1213 // that the entry we're adding will need to be saved later once
1214 // we have the cache entry
1215
1216 // This creates a cycle until the dictionary is removed from the cache
1217 aDictEntry->SetOrigin(origin);
1218 DICTIONARY_LOG(("Creating cache entry for origin %s", prepath.get()))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Creating cache entry for origin %s"
, prepath.get()); } } while (0)
;
1219
1220 // Open (and parse metadata) or create
1221 RefPtr<DictionaryOriginReader> reader = new DictionaryOriginReader();
1222 // the type is irrelevant; we won't be calling Match()
1223 reader->Start(
1224 true, origin, prepath, aURI, ExtContentPolicy::TYPE_OTHER, this,
1225 [entry = RefPtr(aDictEntry)](
1226 bool, DictionaryCacheEntry* aDict) { // XXX avoid so many lambdas
1227 // which cause allocations
1228 // Write the dirty entry we couldn't write before once
1229 // we get the hash
1230 entry->WriteOnHash();
1231 return NS_OK;
1232 });
1233 // Since this is read asynchronously, we need to either add the entry
1234 // async once the read is done and it's populated, or we have to handle
1235 // collisions on the read
1236 return origin;
1237 });
1238
1239 newEntry = origin->AddEntry(aDictEntry, aNewEntry);
1240 DICTIONARY_LOG(("AddEntry: added %s", prepath.get()))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "AddEntry: added %s"
, prepath.get()); } } while (0)
;
1241 return NS_OK;
1242 });
1243 return newEntry.forget();
1244}
1245
1246nsresult DictionaryCache::RemoveEntry(nsIURI* aURI, const nsACString& aKey) {
1247 nsCString prepath;
1248 if (NS_FAILED(GetDictPath(aURI, prepath))((bool)(__builtin_expect(!!(NS_FAILED_impl(GetDictPath(aURI, prepath
))), 0)))
) {
1249 return NS_ERROR_FAILURE;
1250 }
1251 DICTIONARY_LOG(("DictionaryCache::RemoveEntry for %s : %s", prepath.get(),do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "DictionaryCache::RemoveEntry for %s : %s"
, prepath.get(), TPromiseFlatString<char>(aKey).get());
} } while (0)
1252 PromiseFlatCString(aKey).get()))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "DictionaryCache::RemoveEntry for %s : %s"
, prepath.get(), TPromiseFlatString<char>(aKey).get());
} } while (0)
;
1253 if (auto origin = mDictionaryCache.Lookup(prepath)) {
1254 return origin.Data()->RemoveEntry(aKey);
1255 }
1256 return NS_ERROR_FAILURE;
1257}
1258
1259void DictionaryCache::Clear() {
1260 // There may be active Prefetch()es running, note, and active fetches
1261 // using dictionaries. They will stay alive until the channels using
1262 // them go away. However, no new requests will see them.
1263
1264 // This can be used to make the cache return to the state it has at
1265 // startup, especially useful for tests.
1266 mDictionaryCache.Clear();
1267}
1268
1269void DictionaryCache::CorruptHashForTesting(const nsACString& aURI) {
1270 DICTIONARY_LOG(("DictionaryCache::CorruptHashForTesting for %s",do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "DictionaryCache::CorruptHashForTesting for %s"
, TPromiseFlatString<char>(aURI).get()); } } while (0)
1271 PromiseFlatCString(aURI).get()))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "DictionaryCache::CorruptHashForTesting for %s"
, TPromiseFlatString<char>(aURI).get()); } } while (0)
;
1272 nsCOMPtr<nsIURI> uri;
1273 if (NS_FAILED(NS_NewURI(getter_AddRefs(uri), aURI))((bool)(__builtin_expect(!!(NS_FAILED_impl(NS_NewURI(getter_AddRefs
(uri), aURI))), 0)))
) {
1274 return;
1275 }
1276 nsAutoCString prepath;
1277 if (NS_FAILED(GetDictPath(uri, prepath))((bool)(__builtin_expect(!!(NS_FAILED_impl(GetDictPath(uri, prepath
))), 0)))
) {
1278 return;
1279 }
1280 if (auto origin = mDictionaryCache.Lookup(prepath)) {
1281 for (auto& entry : origin.Data()->mEntries) {
1282 if (entry->GetURI().Equals(aURI)) {
1283 DICTIONARY_LOG(("Corrupting hash for %s",do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Corrupting hash for %s"
, TPromiseFlatString<char>(entry->GetURI()).get()); }
} while (0)
1284 PromiseFlatCString(entry->GetURI()).get()))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Corrupting hash for %s"
, TPromiseFlatString<char>(entry->GetURI()).get()); }
} while (0)
;
1285 entry->SetHash("CORRUPTED_FOR_TESTING"_ns);
1286 return;
1287 }
1288 }
1289 for (auto& entry : origin.Data()->mPendingEntries) {
1290 if (entry->GetURI().Equals(aURI)) {
1291 DICTIONARY_LOG(("Corrupting hash for %s (pending)",do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Corrupting hash for %s (pending)"
, TPromiseFlatString<char>(entry->GetURI()).get()); }
} while (0)
1292 PromiseFlatCString(entry->GetURI()).get()))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Corrupting hash for %s (pending)"
, TPromiseFlatString<char>(entry->GetURI()).get()); }
} while (0)
;
1293 entry->SetHash("CORRUPTED_FOR_TESTING"_ns);
1294 return;
1295 }
1296 }
1297 }
1298}
1299
1300void DictionaryCache::ClearDictionaryDataForTesting(const nsACString& aURI) {
1301 DICTIONARY_LOG(("DictionaryCache::ClearDictionaryDataForTesting for %s",do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "DictionaryCache::ClearDictionaryDataForTesting for %s"
, TPromiseFlatString<char>(aURI).get()); } } while (0)
1302 PromiseFlatCString(aURI).get()))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "DictionaryCache::ClearDictionaryDataForTesting for %s"
, TPromiseFlatString<char>(aURI).get()); } } while (0)
;
1303 nsCOMPtr<nsIURI> uri;
1304 if (NS_FAILED(NS_NewURI(getter_AddRefs(uri), aURI))((bool)(__builtin_expect(!!(NS_FAILED_impl(NS_NewURI(getter_AddRefs
(uri), aURI))), 0)))
) {
1305 return;
1306 }
1307 nsAutoCString prepath;
1308 if (NS_FAILED(GetDictPath(uri, prepath))((bool)(__builtin_expect(!!(NS_FAILED_impl(GetDictPath(uri, prepath
))), 0)))
) {
1309 return;
1310 }
1311 if (auto origin = mDictionaryCache.Lookup(prepath)) {
1312 for (auto& entry : origin.Data()->mEntries) {
1313 if (entry->GetURI().Equals(aURI)) {
1314 DICTIONARY_LOG(("Clearing data for %s",do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Clearing data for %s"
, TPromiseFlatString<char>(entry->GetURI()).get()); }
} while (0)
1315 PromiseFlatCString(entry->GetURI()).get()))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Clearing data for %s"
, TPromiseFlatString<char>(entry->GetURI()).get()); }
} while (0)
;
1316 entry->ClearDataForTesting();
1317 return;
1318 }
1319 }
1320 }
1321}
1322
1323// Remove a dictionary if it exists for the key given
1324// static
1325void DictionaryCache::RemoveDictionaryOMT(const nsACString& aKey) {
1326 DICTIONARY_LOG(do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Removing dictionary for %s"
, TPromiseFlatString<char>(aKey).get()); } } while (0)
1327 ("Removing dictionary for %s", PromiseFlatCString(aKey).get()))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Removing dictionary for %s"
, TPromiseFlatString<char>(aKey).get()); } } while (0)
;
1328 NS_DispatchToMainThread(NS_NewRunnableFunction(
1329 "DictionaryCache::RemoveDictionaryOMT",
1330 [key = nsCString(aKey)]() { DictionaryCache::RemoveDictionary(key); }));
1331}
1332
1333// Remove a dictionary if it exists for the key given
1334// static
1335void DictionaryCache::RemoveDictionary(const nsACString& aKey) {
1336 MOZ_ASSERT(NS_IsMainThread())do { static_assert( mozilla::detail::AssertionConditionType<
decltype(NS_IsMainThread())>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(NS_IsMainThread()))), 0))) {
do { } while (false); MOZ_ReportAssertionFailure("NS_IsMainThread()"
, "./../../../netwerk/cache2/Dictionary.cpp", 1336); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "NS_IsMainThread()" ")"); do { MOZ_CrashSequence
(__null, 1336); __attribute__((nomerge)) ::abort(); } while (
false); } } while (false)
;
1337 DICTIONARY_LOG(do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Removing dictionary for %s"
, TPromiseFlatString<char>(aKey).get()); } } while (0)
1338 ("Removing dictionary for %s", PromiseFlatCString(aKey).get()))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Removing dictionary for %s"
, TPromiseFlatString<char>(aKey).get()); } } while (0)
;
1339
1340 RefPtr<DictionaryCache> cache = GetInstance();
1341 if (!cache) {
1342 // Shutdown has occurred, cannot remove dictionary
1343 return;
1344 }
1345 nsCOMPtr<nsIURI> uri;
1346 if (NS_FAILED(NS_NewURI(getter_AddRefs(uri), aKey))((bool)(__builtin_expect(!!(NS_FAILED_impl(NS_NewURI(getter_AddRefs
(uri), aKey))), 0)))
) {
1347 return;
1348 }
1349 nsAutoCString prepath;
1350 if (NS_SUCCEEDED(GetDictPath(uri, prepath))((bool)(__builtin_expect(!!(!NS_FAILED_impl(GetDictPath(uri, prepath
))), 1)))
) {
1351 if (auto origin = cache->mDictionaryCache.Lookup(prepath)) {
1352 origin.Data()->RemoveEntry(aKey);
1353 }
1354 }
1355}
1356
1357// static
1358void DictionaryCache::RemoveOriginFor(const nsACString& aKey) {
1359 RefPtr<DictionaryCache> cache = GetInstance();
1360 if (!cache) {
1361 // Shutdown has occurred, cannot remove origin
1362 return;
1363 }
1364 DICTIONARY_LOG(do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Removing dictionary origin %s"
, TPromiseFlatString<char>(aKey).get()); } } while (0)
1365 ("Removing dictionary origin %s", PromiseFlatCString(aKey).get()))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Removing dictionary origin %s"
, TPromiseFlatString<char>(aKey).get()); } } while (0)
;
1366 NS_DispatchToMainThread(NewRunnableMethod<const nsCString>(
1367 "DictionaryCache::RemoveOriginFor", cache,
1368 &DictionaryCache::RemoveOriginForInternal, aKey));
1369}
1370
1371// Remove a dictionary if it exists for the key given, if it's empty
1372void DictionaryCache::RemoveOriginForInternal(const nsACString& aKey) {
1373 nsCOMPtr<nsIURI> uri;
1374 if (NS_FAILED(NS_NewURI(getter_AddRefs(uri), aKey))((bool)(__builtin_expect(!!(NS_FAILED_impl(NS_NewURI(getter_AddRefs
(uri), aKey))), 0)))
) {
1375 return;
1376 }
1377 nsAutoCString prepath;
1378 if (NS_SUCCEEDED(GetDictPath(uri, prepath))((bool)(__builtin_expect(!!(!NS_FAILED_impl(GetDictPath(uri, prepath
))), 1)))
) {
1379 if (auto origin = mDictionaryCache.Lookup(prepath)) {
1380 if (MOZ_UNLIKELY(origin.Data()->IsEmpty())(__builtin_expect(!!(origin.Data()->IsEmpty()), 0))) {
1381 DICTIONARY_LOG(do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Removing origin for %s"
, TPromiseFlatString<char>(aKey).get()); } } while (0)
1382 ("Removing origin for %s", PromiseFlatCString(aKey).get()))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Removing origin for %s"
, TPromiseFlatString<char>(aKey).get()); } } while (0)
;
1383 // This removes it from the global list and also dooms the entry
1384 origin.Data()->Clear();
1385 } else {
1386 DICTIONARY_LOG(do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Origin not empty: %s"
, TPromiseFlatString<char>(aKey).get()); } } while (0)
1387 ("Origin not empty: %s", PromiseFlatCString(aKey).get()))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Origin not empty: %s"
, TPromiseFlatString<char>(aKey).get()); } } while (0)
;
1388 }
1389 }
1390 }
1391}
1392
1393// Remove a dictionary if it exists for the key given (key should be prepath)
1394void DictionaryCache::RemoveOrigin(const nsACString& aOrigin) {
1395 mDictionaryCache.Remove(aOrigin);
1396}
1397
1398// Remove a dictionary if it exists for the key given. Mainthread only.
1399// Note: due to cookie samesite rules, we need to clean for all ports!
1400// static
1401void DictionaryCache::RemoveDictionariesForOrigin(nsIURI* aURI) {
1402 // There's no PrePathNoPort()
1403 nsAutoCString temp;
1404 aURI->GetScheme(temp);
1405 nsCString origin(temp);
1406 aURI->GetUserPass(temp);
1407 origin += "://"_ns + temp;
1408 aURI->GetHost(temp);
1409 origin += temp;
1410
1411 DICTIONARY_LOG(("Removing all dictionaries for origin of %s (%zu)",do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Removing all dictionaries for origin of %s (%zu)"
, TPromiseFlatString<char>(origin).get(), origin.Length
()); } } while (0)
1412 PromiseFlatCString(origin).get(), origin.Length()))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Removing all dictionaries for origin of %s (%zu)"
, TPromiseFlatString<char>(origin).get(), origin.Length
()); } } while (0)
;
1413 RefPtr<DictionaryCache> cache = GetInstance();
1414 if (!cache) {
1415 // Shutdown has occurred, cannot remove dictionaries
1416 return;
1417 }
1418 // We can't just use Remove here; the ClearSiteData service strips the
1419 // port. We need to clear all that match the host with any port or none.
1420
1421 // Keep an array of origins to clear since that will want to modify the
1422 // hash table we're iterating
1423 AutoTArray<RefPtr<DictionaryOrigin>, 1> toClear;
1424 for (auto& entry : cache->mDictionaryCache) {
1425 // We need to drop any port from entry (and origin). Assuming they're
1426 // the same up to the / or : in mOrigin, we want to limit the host
1427 // there. We also know that entry is https://.
1428 // Verify that:
1429 // a) they're equal to that point
1430 // b) that the next character of mOrigin is '/' or ':', which avoids
1431 // issues like matching https://foo.bar to (mOrigin)
1432 // https://foo.barsoom.com:666/
1433 DICTIONARY_LOG(do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Possibly removing dictionary origin for %s (vs %s), %zu vs %zu"
, entry.GetData()->mOrigin.get(), TPromiseFlatString<char
>(origin).get(), entry.GetData()->mOrigin.Length(), origin
.Length()); } } while (0)
1434 ("Possibly removing dictionary origin for %s (vs %s), %zu vs %zu",do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Possibly removing dictionary origin for %s (vs %s), %zu vs %zu"
, entry.GetData()->mOrigin.get(), TPromiseFlatString<char
>(origin).get(), entry.GetData()->mOrigin.Length(), origin
.Length()); } } while (0)
1435 entry.GetData()->mOrigin.get(), PromiseFlatCString(origin).get(),do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Possibly removing dictionary origin for %s (vs %s), %zu vs %zu"
, entry.GetData()->mOrigin.get(), TPromiseFlatString<char
>(origin).get(), entry.GetData()->mOrigin.Length(), origin
.Length()); } } while (0)
1436 entry.GetData()->mOrigin.Length(), origin.Length()))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Possibly removing dictionary origin for %s (vs %s), %zu vs %zu"
, entry.GetData()->mOrigin.get(), TPromiseFlatString<char
>(origin).get(), entry.GetData()->mOrigin.Length(), origin
.Length()); } } while (0)
;
1437 if (entry.GetData()->mOrigin.Length() > origin.Length() &&
1438 (entry.GetData()->mOrigin[origin.Length()] == '/' || // no port
1439 entry.GetData()->mOrigin[origin.Length()] == ':')) { // port
1440 // no strncmp() for nsCStrings...
1441 nsDependentCSubstring host =
1442 Substring(entry.GetData()->mOrigin, 0,
1443 origin.Length()); // not including '/' or ':'
1444 DICTIONARY_LOG(("Compare %s vs %s", entry.GetData()->mOrigin.get(),do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Compare %s vs %s"
, entry.GetData()->mOrigin.get(), TPromiseFlatString<char
>(host).get()); } } while (0)
1445 PromiseFlatCString(host).get()))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Compare %s vs %s"
, entry.GetData()->mOrigin.get(), TPromiseFlatString<char
>(host).get()); } } while (0)
;
1446 if (origin.Equals(host)) {
1447 DICTIONARY_LOG(do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "RemoveDictionaries: Removing dictionary origin %p for %s"
, entry.GetData().get(), entry.GetData()->mOrigin.get()); }
} while (0)
1448 ("RemoveDictionaries: Removing dictionary origin %p for %s",do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "RemoveDictionaries: Removing dictionary origin %p for %s"
, entry.GetData().get(), entry.GetData()->mOrigin.get()); }
} while (0)
1449 entry.GetData().get(), entry.GetData()->mOrigin.get()))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "RemoveDictionaries: Removing dictionary origin %p for %s"
, entry.GetData().get(), entry.GetData()->mOrigin.get()); }
} while (0)
;
1450 toClear.AppendElement(entry.GetData());
1451 }
1452 }
1453 }
1454 // Now clear and doom all the entries
1455 for (auto& entry : toClear) {
1456 entry->Clear();
1457 }
1458}
1459
1460// Remove a dictionary if it exists for the key given. Mainthread only
1461// static
1462void DictionaryCache::RemoveAllDictionaries() {
1463 RefPtr<DictionaryCache> cache = GetInstance();
1464 if (!cache) {
1465 // Shutdown has occurred, cannot remove dictionaries
1466 return;
1467 }
1468
1469 DICTIONARY_LOG(("Removing all dictionaries"))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Removing all dictionaries"
); } } while (0)
;
1470 // Clear contents of all origins without calling DictionaryOrigin::Clear()
1471 // which would try to modify the hashtable during iteration (causing
1472 // reentrancy assertion in PLDHashTable).
1473 // Note: This duplicates logic from DictionaryOrigin::Clear() but avoids
1474 // the RemoveOrigin() call during iteration. For selective removal, see
1475 // RemoveDictionariesForOrigin() which uses a collect-then-clear pattern.
1476 AutoTArray<nsCOMPtr<nsICacheEntry>, 8> entriesToDoom;
1477 for (auto& origin : cache->mDictionaryCache) {
1478 DictionaryOrigin* originPtr = origin.GetData();
1479 DICTIONARY_LOG(("*** Clearing origin %s", originPtr->mOrigin.get()))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "*** Clearing origin %s"
, originPtr->mOrigin.get()); } } while (0)
;
1480 originPtr->mEntries.Clear();
1481 originPtr->mPendingEntries.Clear();
1482 originPtr->mPendingRemove.Clear();
1483 if (originPtr->mEntry) {
1484 entriesToDoom.AppendElement(originPtr->mEntry);
1485 }
1486 }
1487 // Doom all cache entries asynchronously in one task
1488 if (!entriesToDoom.IsEmpty()) {
1489 NS_DispatchBackgroundTask(NS_NewRunnableFunction(
1490 "DictionaryOrigin::ClearAll", [entries = std::move(entriesToDoom)]() {
1491 DICTIONARY_LOG(("*** Dooming %zu entries", entries.Length()))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "*** Dooming %zu entries"
, entries.Length()); } } while (0)
;
1492 for (auto& entry : entries) {
1493 entry->AsyncDoom(nullptr);
1494 }
1495 }));
1496 }
1497 // Now clear the hashtable after iteration is complete
1498 cache->mDictionaryCache.Clear();
1499}
1500
1501// Return an entry via a callback (async).
1502// If we don't have the origin in-memory, ask the cache for the origin, and
1503// when we get it, parse the metadata to build a DictionaryOrigin.
1504// Once we have a DictionaryOrigin (in-memory or parsed), scan it for matches.
1505// If it's not in the cache, return nullptr via callback.
1506void DictionaryCache::GetDictionaryFor(
1507 nsIURI* aURI, ExtContentPolicyType aType, nsHttpChannel* aChan,
1508 void (*aSuspend)(nsHttpChannel*),
1509 const std::function<nsresult(bool, DictionaryCacheEntry*)>& aCallback) {
1510 // Note: IETF 2.2.3 Multiple Matching Directories
1511 // We need to return match-dest matches first
1512 // If no match-dest, then the longest match
1513 nsCString prepath;
1514 if (NS_FAILED(GetDictPath(aURI, prepath))((bool)(__builtin_expect(!!(NS_FAILED_impl(GetDictPath(aURI, prepath
))), 0)))
) {
1515 (aCallback)(false, nullptr);
1516 return;
1517 }
1518 // Match immediately if we've already created the origin and read any
1519 // metadata
1520 if (auto existing = mDictionaryCache.Lookup(prepath)) {
1521 if (existing.Data()->mWaitingCacheRead.IsEmpty()) {
1522 // Find the longest match
1523 nsCString path;
1524 RefPtr<DictionaryCacheEntry> result;
1525
1526 aURI->GetSpec(path);
1527 DICTIONARY_LOG(("GetDictionaryFor(%s %s)", prepath.get(), path.get()))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "GetDictionaryFor(%s %s)"
, prepath.get(), path.get()); } } while (0)
;
1528
1529 result = existing.Data()->Match(path, aType);
1530 (aCallback)(false, result);
1531 } else {
1532 DICTIONARY_LOG(do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "GetDictionaryFor(%s): Waiting for metadata read to match"
, prepath.get()); } } while (0)
1533 ("GetDictionaryFor(%s): Waiting for metadata read to match",do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "GetDictionaryFor(%s): Waiting for metadata read to match"
, prepath.get()); } } while (0)
1534 prepath.get()))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "GetDictionaryFor(%s): Waiting for metadata read to match"
, prepath.get()); } } while (0)
;
1535 // Wait for the metadata read to complete
1536 RefPtr<DictionaryOriginReader> reader = new DictionaryOriginReader();
1537 // Must do this before calling start, which can run the callbacks and call
1538 // Resume
1539 DICTIONARY_LOG(("Suspending to get Dictionary headers"))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Suspending to get Dictionary headers"
); } } while (0)
;
1540 aSuspend(aChan);
1541 reader->Start(false, existing.Data(), prepath, aURI, aType, this,
1542 aCallback);
1543 }
1544 return;
1545 }
1546 // We don't have an entry at all. We need to check if there's an entry
1547 // on disk for <origin>, unless we know we have all entries in the memory
1548 // cache.
1549
1550 // Handle unknown origins by checking the disk cache
1551 if (!sCacheStorage) {
1552 (aCallback)(false, nullptr); // in case we have no disk storage
1553 return;
1554 }
1555
1556 // Sync check to see if the entry exists
1557 bool exists;
1558 nsCOMPtr<nsIURI> prepathURI;
1559
1560 if (NS_SUCCEEDED(NS_MutateURI(new net::nsStandardURL::Mutator())((bool)(__builtin_expect(!!(!NS_FAILED_impl(NS_MutateURI(new net
::nsStandardURL::Mutator()) .SetSpec(prepath) .Finalize(prepathURI
))), 1)))
1561 .SetSpec(prepath)((bool)(__builtin_expect(!!(!NS_FAILED_impl(NS_MutateURI(new net
::nsStandardURL::Mutator()) .SetSpec(prepath) .Finalize(prepathURI
))), 1)))
1562 .Finalize(prepathURI))((bool)(__builtin_expect(!!(!NS_FAILED_impl(NS_MutateURI(new net
::nsStandardURL::Mutator()) .SetSpec(prepath) .Finalize(prepathURI
))), 1)))
&&
1563 NS_SUCCEEDED(((bool)(__builtin_expect(!!(!NS_FAILED_impl(sCacheStorage->
Exists(prepathURI, "dict:"_ns, &exists))), 1)))
1564 sCacheStorage->Exists(prepathURI, META_DICTIONARY_PREFIX, &exists))((bool)(__builtin_expect(!!(!NS_FAILED_impl(sCacheStorage->
Exists(prepathURI, "dict:"_ns, &exists))), 1)))
&&
1565 exists) {
1566 // To keep track of the callback, we need a new object to get the
1567 // OnCacheEntryAvailable can resolve the callback.
1568 DICTIONARY_LOG(("Reading %s for dictionary entries", prepath.get()))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Reading %s for dictionary entries"
, prepath.get()); } } while (0)
;
1569 RefPtr<DictionaryOrigin> origin = new DictionaryOrigin(prepath, nullptr);
1570 // Add the origin to the list; we'll immediately start a reader which
1571 // will set mWaitingCacheRead, so future GetDictionaryFor() calls
1572 // will wait for the metadata to be read before doing Match()
1573 mDictionaryCache.InsertOrUpdate(prepath, origin);
1574
1575 RefPtr<DictionaryOriginReader> reader = new DictionaryOriginReader();
1576 // After Start(), if we drop this ref reader will kill itself on
1577 // completion; it holds a self-ref
1578 DICTIONARY_LOG(("Suspending to get Dictionary headers"))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Suspending to get Dictionary headers"
); } } while (0)
;
1579 aSuspend(aChan);
1580 reader->Start(false, origin, prepath, aURI, aType, this, aCallback);
1581 return;
1582 }
1583 // No dictionaries for origin
1584 (aCallback)(false, nullptr);
1585}
1586
1587//-----------------------------------------------------------------------------
1588// DictionaryOrigin
1589//-----------------------------------------------------------------------------
1590NS_IMPL_ISUPPORTS(DictionaryOrigin, nsICacheEntryMetaDataVisitor)MozExternalRefCountType DictionaryOrigin::AddRef(void) { static_assert
(!std::is_destructible_v<DictionaryOrigin>, "Reference-counted class "
"DictionaryOrigin" " should not have a public destructor. " "Make this class's destructor non-public"
); do { static_assert( mozilla::detail::AssertionConditionType
<decltype(int32_t(mRefCnt) >= 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) >= 0))),
0))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) >= 0"
" (" "illegal refcnt" ")", "./../../../netwerk/cache2/Dictionary.cpp"
, 1590); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) >= 0"
") (" "illegal refcnt" ")"); do { MOZ_CrashSequence(__null, 1590
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("DictionaryOrigin" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("DictionaryOrigin" != nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"\"DictionaryOrigin\" != nullptr" " (" "Must specify a name" ")"
, "./../../../netwerk/cache2/Dictionary.cpp", 1590); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "\"DictionaryOrigin\" != nullptr" ") (" "Must specify a name"
")"); do { MOZ_CrashSequence(__null, 1590); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); if (!mRefCnt
.isThreadSafe) _mOwningThread.AssertOwnership("DictionaryOrigin"
" not thread-safe"); nsrefcnt count = ++mRefCnt; NS_LogAddRef
((this), (count), ("DictionaryOrigin"), (uint32_t)(sizeof(*this
))); return count; } MozExternalRefCountType DictionaryOrigin
::Release(void) { do { static_assert( mozilla::detail::AssertionConditionType
<decltype(int32_t(mRefCnt) > 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(int32_t(mRefCnt) > 0))), 0
))) { do { } while (false); MOZ_ReportAssertionFailure("int32_t(mRefCnt) > 0"
" (" "dup release" ")", "./../../../netwerk/cache2/Dictionary.cpp"
, 1590); AnnotateMozCrashReason("MOZ_ASSERT" "(" "int32_t(mRefCnt) > 0"
") (" "dup release" ")"); do { MOZ_CrashSequence(__null, 1590
); __attribute__((nomerge)) ::abort(); } while (false); } } while
(false); do { static_assert( mozilla::detail::AssertionConditionType
<decltype("DictionaryOrigin" != nullptr)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!("DictionaryOrigin" != nullptr
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"\"DictionaryOrigin\" != nullptr" " (" "Must specify a name" ")"
, "./../../../netwerk/cache2/Dictionary.cpp", 1590); AnnotateMozCrashReason
("MOZ_ASSERT" "(" "\"DictionaryOrigin\" != nullptr" ") (" "Must specify a name"
")"); do { MOZ_CrashSequence(__null, 1590); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false); if (!mRefCnt
.isThreadSafe) _mOwningThread.AssertOwnership("DictionaryOrigin"
" not thread-safe"); const char* const nametmp = "DictionaryOrigin"
; nsrefcnt count = --mRefCnt; NS_LogRelease((this), (count), (
nametmp)); if (count == 0) { mRefCnt = 1; delete (this); return
0; } return count; } nsresult DictionaryOrigin::QueryInterface
(const nsIID& aIID, void** aInstancePtr) { do { if (!(aInstancePtr
)) { NS_DebugBreak(NS_DEBUG_ASSERTION, "QueryInterface requires a non-NULL destination!"
, "aInstancePtr", "./../../../netwerk/cache2/Dictionary.cpp",
1590); MOZ_PretendNoReturn(); } } while (0); nsresult rv = NS_ERROR_FAILURE
; static_assert(1 > 0, "Need more arguments to NS_INTERFACE_TABLE"
); static const QITableEntry table[] = { {&mozilla::detail
::kImplementedIID<DictionaryOrigin, nsICacheEntryMetaDataVisitor
>, int32_t( reinterpret_cast<char*>(static_cast<nsICacheEntryMetaDataVisitor
*>((DictionaryOrigin*)0x1000)) - reinterpret_cast<char*
>((DictionaryOrigin*)0x1000))}, {&mozilla::detail::kImplementedIID
<DictionaryOrigin, nsISupports>, int32_t(reinterpret_cast
<char*>(static_cast<nsISupports*>( static_cast<
nsICacheEntryMetaDataVisitor*>((DictionaryOrigin*)0x1000))
) - reinterpret_cast<char*>((DictionaryOrigin*)0x1000))
}, { nullptr, 0 } } ; static_assert(std::size(table) > 1, "need at least 1 interface"
); rv = NS_TableDrivenQI(static_cast<void*>(this), aIID
, aInstancePtr, table); return rv; }
1591
1592nsresult DictionaryOrigin::Write(DictionaryCacheEntry* aDictEntry) {
1593 DICTIONARY_LOG(("DictionaryOrigin::Write %s %p", mOrigin.get(), aDictEntry))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "DictionaryOrigin::Write %s %p"
, mOrigin.get(), aDictEntry); } } while (0)
;
1594 if (mEntry) {
1595 return aDictEntry->Write(mEntry);
1596 }
1597 // Write it once DictionaryOriginReader creates the entry
1598 mDeferredWrites = true;
1599 return NS_OK;
1600}
1601
1602void DictionaryOrigin::SetCacheEntry(nsICacheEntry* aEntry) {
1603 mEntry = aEntry;
1604 mEntry->SetContentType(nsICacheEntry::CONTENT_TYPE_DICTIONARY);
1605 if (mDeferredWrites) {
1606 // RemoveEntry() mutates mEntries, so defer removals.
1607 DictCacheList remove;
1608 for (auto& entry : mEntries) {
1609 if (NS_FAILED(Write(entry))((bool)(__builtin_expect(!!(NS_FAILED_impl(Write(entry))), 0)
))
) {
1610 remove.AppendElement(entry);
1611 }
1612 }
1613 for (auto& entry : remove) {
1614 RemoveEntry(entry);
1615 }
1616 }
1617 mDeferredWrites = false;
1618 // Handle removes that were pending
1619 for (auto& remove : mPendingRemove) {
1620 DICTIONARY_LOG(("Pending RemoveEntry for %s", remove->mURI.get()))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Pending RemoveEntry for %s"
, remove->mURI.get()); } } while (0)
;
1621 remove->RemoveEntry(mEntry);
1622 }
1623 mPendingRemove.Clear();
1624}
1625
1626already_AddRefed<DictionaryCacheEntry> DictionaryOrigin::AddEntry(
1627 DictionaryCacheEntry* aDictEntry, bool aNewEntry) {
1628 // Remove any entry for the same item
1629 for (size_t i = 0; i < mEntries.Length(); i++) {
1630 if (mEntries[i]->GetURI().Equals(aDictEntry->GetURI())) {
1631 DictionaryCacheEntry* oldEntry = mEntries[i];
1632 if (aNewEntry) {
1633 // We're overwriting an existing entry, perhaps with a new hash. It
1634 // might be different, of course.
1635 // Until we receive and save the new data, we should use the old data.
1636
1637 // We need to pause this channel, regardless of how it's encoded,
1638 // until the entry we're replacing has either no users, or has data
1639 // read in from the cache. Then we can un-Suspend and start
1640 // replacing the data in the cache itself. If there are no current
1641 // users, and we start replacing the data, we need to remove the
1642 // old entry so no one tries to use the old data/hash for a new
1643 // request.
1644
1645 // Note that when we start replacing data in the cache we need to
1646 // also remove it from the origin's entry in the cache, in case we
1647 // exit or crash before we finish replacing the entry and updating
1648 // the origin's entry with the new hash.
1649
1650 // Once we've replaced the entry (which will be after we have
1651 // hash), new requests will use the new data/hash. I.e. we'll
1652 // still allow new requests to use the old cache data/hash until
1653 // the swap occurs. Once the swap happens, the channels using the
1654 // old data/hash will still have an mDictDecoding reference to the
1655 // DictionaryCacheEntry for the old data/hash.
1656
1657 // XXX possible edge case: if a second request to replace the
1658 // entry appears. Is this possible, or would the second request
1659 // for the same URI get subsumed into the older one still in
1660 // process? I'm guessing it doesn't, so we may need to deal with this
1661
1662 DICTIONARY_LOG((do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Replacing dictionary %p for %s: new will be %p"
, mEntries[i].get(), TPromiseFlatString<char>(oldEntry->
GetURI()).get(), oldEntry); } } while (0)
1663 "Replacing dictionary %p for %s: new will be %p", mEntries[i].get(),do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Replacing dictionary %p for %s: new will be %p"
, mEntries[i].get(), TPromiseFlatString<char>(oldEntry->
GetURI()).get(), oldEntry); } } while (0)
1664 PromiseFlatCString(oldEntry->GetURI()).get(), oldEntry))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Replacing dictionary %p for %s: new will be %p"
, mEntries[i].get(), TPromiseFlatString<char>(oldEntry->
GetURI()).get(), oldEntry); } } while (0)
;
1665 // May be overkill to check HasHash here
1666 if (mEntries[i]->IsReading() && !aDictEntry->HasHash()) {
1667 DICTIONARY_LOG(("Old entry is reading data"))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Old entry is reading data"
); } } while (0)
;
1668 // If the old entry doesn't already have the data from the
1669 // dictionary, we'll need to Suspend this channel, and do a
1670 // replace later. Remember this new entry so when the current
1671 // entry has it's data in memory we can un-Suspend the new
1672 // channel/entry. When the new entry finishes saving, it will
1673 // use the mReplacement link to come back and insert itself
1674 // into mEntries and drop the old entry. Use an origin link
1675 // for that since the old entry could in theory get purged and
1676 // removed from the origin before we finish.
1677 mEntries[i]->SetReplacement(aDictEntry, this);
1678 // SetReplacement will also set aDictEntry->mShouldSuspend
1679 return do_AddRef(aDictEntry);
1680 } else {
1681 DICTIONARY_LOG(("Removing old entry, no users or already read data"))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Removing old entry, no users or already read data"
); } } while (0)
;
1682 // We can just replace, there are no users active for the old data.
1683 // This stops new requests from trying to use the old data we're in
1684 // the process of replacing Remove the entry from the Origin and
1685 // Write().
1686 if (mEntry) {
1687 mEntries[i]->RemoveEntry(mEntry);
1688 }
1689 mEntries.RemoveElementAt(i);
1690 }
1691 } else {
1692 // We're updating an existing entry (on a 304 Not Modified). Assume
1693 // the values may have changed (though likely they haven't). Check Spec
1694 // XXX
1695 DICTIONARY_LOG(do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Updating dictionary for %s (%p)"
, mOrigin.get(), oldEntry); } } while (0)
1696 ("Updating dictionary for %s (%p)", mOrigin.get(), oldEntry))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Updating dictionary for %s (%p)"
, mOrigin.get(), oldEntry); } } while (0)
;
1697 oldEntry->CopyFrom(aDictEntry);
1698 // write the entry back if something changed
1699 // XXX Check if something changed
1700 oldEntry->Write(mEntry);
1701
1702 // We don't need to reference the entry
1703 return nullptr;
1704 }
1705 break;
1706 }
1707 }
1708
1709 DICTIONARY_LOG(("New dictionary %sfor %s: %p",do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "New dictionary %sfor %s: %p"
, aDictEntry->HasHash() ? "" : "(pending) ", mOrigin.get()
, aDictEntry); } } while (0)
1710 aDictEntry->HasHash() ? "" : "(pending) ", mOrigin.get(),do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "New dictionary %sfor %s: %p"
, aDictEntry->HasHash() ? "" : "(pending) ", mOrigin.get()
, aDictEntry); } } while (0)
1711 aDictEntry))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "New dictionary %sfor %s: %p"
, aDictEntry->HasHash() ? "" : "(pending) ", mOrigin.get()
, aDictEntry); } } while (0)
;
1712 if (aDictEntry->HasHash()) {
1713 mEntries.AppendElement(aDictEntry);
1714 } else {
1715 // Still need to receive the data. When we have the hash, move to
1716 // mEntries (and Write) using entry->mOrigin
1717 mPendingEntries.AppendElement(aDictEntry);
1718 aDictEntry->SetReplacement(nullptr, this);
1719 }
1720
1721 // DictionaryCache/caller is responsible for ensure this gets written if
1722 // needed
1723 return do_AddRef(aDictEntry);
1724}
1725
1726nsresult DictionaryOrigin::RemoveEntry(const nsACString& aKey) {
1727 DICTIONARY_LOG(do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "DictionaryOrigin::RemoveEntry for %s"
, TPromiseFlatString<char>(aKey).get()); } } while (0)
1728 ("DictionaryOrigin::RemoveEntry for %s", PromiseFlatCString(aKey).get()))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "DictionaryOrigin::RemoveEntry for %s"
, TPromiseFlatString<char>(aKey).get()); } } while (0)
;
1729 RefPtr<DictionaryCacheEntry> hold;
1730 for (const auto& dict : mEntries) {
1731 if (dict->GetURI().Equals(aKey)) {
1732 // Ensure it doesn't disappear on us
1733 hold = dict;
1734 DICTIONARY_LOG(("Removing %p", dict.get()))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Removing %p", dict
.get()); } } while (0)
;
1735 mEntries.RemoveElement(dict);
1736 if (mEntry) {
1737 hold->RemoveEntry(mEntry);
1738 } else {
1739 // We don't have the cache entry yet. Defer the removal from
1740 // the entry until we do
1741 mPendingRemove.AppendElement(hold);
1742 return NS_OK;
1743 }
1744 break;
1745 }
1746 }
1747 if (!hold) {
1748 DICTIONARY_LOG(("DictionaryOrigin::RemoveEntry (pending) for %s",do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "DictionaryOrigin::RemoveEntry (pending) for %s"
, TPromiseFlatString<char>(aKey).get()); } } while (0)
1749 PromiseFlatCString(aKey).get()))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "DictionaryOrigin::RemoveEntry (pending) for %s"
, TPromiseFlatString<char>(aKey).get()); } } while (0)
;
1750 for (const auto& dict : mPendingEntries) {
1751 if (dict->GetURI().Equals(aKey)) {
1752 // Ensure it doesn't disappear on us
1753 RefPtr<DictionaryCacheEntry> hold(dict);
1754 DICTIONARY_LOG(("Removing %p", dict.get()))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "Removing %p", dict
.get()); } } while (0)
;
1755 mPendingEntries.RemoveElement(dict);
1756 break;
1757 }
1758 }
1759 }
1760 // If this origin has no entries, remove it and doom the entry
1761 if (IsEmpty()) {
1762 Clear();
1763 }
1764 return hold ? NS_OK : NS_ERROR_FAILURE;
1765}
1766
1767void DictionaryOrigin::FinishAddEntry(DictionaryCacheEntry* aEntry) {
1768 // if aDictEntry is in mPendingEntries, move to mEntries
1769 if (mPendingEntries.RemoveElement(aEntry)) {
1770 // We need to give priority to elements fetched most recently if they
1771 // have an equivalent match length (and dest)
1772 // XXX insert at the start of entries of this length
1773 mEntries.InsertElementAt(0, aEntry);
1774 }
1775 DICTIONARY_LOG(("FinishAddEntry(%s)", aEntry->mURI.get()))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "FinishAddEntry(%s)"
, aEntry->mURI.get()); } } while (0)
;
1776 if (MOZ_UNLIKELY(MOZ_LOG_TEST(gDictionaryLog, mozilla::LogLevel::Debug))(__builtin_expect(!!((__builtin_expect(!!(mozilla::detail::log_test
(gDictionaryLog, mozilla::LogLevel::Debug)), 0))), 0))
) {
1777 DumpEntries();
1778 }
1779}
1780
1781void DictionaryOrigin::RemoveEntry(DictionaryCacheEntry* aEntry) {
1782 DICTIONARY_LOG(("RemoveEntry(%s)", aEntry->mURI.get()))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "RemoveEntry(%s)"
, aEntry->mURI.get()); } } while (0)
;
1783 if (!mEntries.RemoveElement(aEntry)) {
1784 mPendingEntries.RemoveElement(aEntry);
1785 }
1786 if (MOZ_UNLIKELY(MOZ_LOG_TEST(gDictionaryLog, mozilla::LogLevel::Debug))(__builtin_expect(!!((__builtin_expect(!!(mozilla::detail::log_test
(gDictionaryLog, mozilla::LogLevel::Debug)), 0))), 0))
) {
1787 DumpEntries();
1788 }
1789}
1790
1791void DictionaryOrigin::DumpEntries() {
1792 DICTIONARY_LOG(("*** Origin %s ***", mOrigin.get()))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "*** Origin %s ***"
, mOrigin.get()); } } while (0)
;
1793 for (const auto& dict : mEntries) {
1794 DICTIONARY_LOG(do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "* %s: pattern %s, id %s, match-dest[0]: %s, hash: %s, expiration: "
"%u", dict->mURI.get(), dict->mPattern.get(), dict->
mId.get(), dict->mMatchDest.IsEmpty() ? "" : dom::GetEnumString
(dict->mMatchDest[0]).get(), dict->GetHash().get(), dict
->mExpiration); } } while (0)
1795 ("* %s: pattern %s, id %s, match-dest[0]: %s, hash: %s, expiration: "do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "* %s: pattern %s, id %s, match-dest[0]: %s, hash: %s, expiration: "
"%u", dict->mURI.get(), dict->mPattern.get(), dict->
mId.get(), dict->mMatchDest.IsEmpty() ? "" : dom::GetEnumString
(dict->mMatchDest[0]).get(), dict->GetHash().get(), dict
->mExpiration); } } while (0)
1796 "%u",do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "* %s: pattern %s, id %s, match-dest[0]: %s, hash: %s, expiration: "
"%u", dict->mURI.get(), dict->mPattern.get(), dict->
mId.get(), dict->mMatchDest.IsEmpty() ? "" : dom::GetEnumString
(dict->mMatchDest[0]).get(), dict->GetHash().get(), dict
->mExpiration); } } while (0)
1797 dict->mURI.get(), dict->mPattern.get(), dict->mId.get(),do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "* %s: pattern %s, id %s, match-dest[0]: %s, hash: %s, expiration: "
"%u", dict->mURI.get(), dict->mPattern.get(), dict->
mId.get(), dict->mMatchDest.IsEmpty() ? "" : dom::GetEnumString
(dict->mMatchDest[0]).get(), dict->GetHash().get(), dict
->mExpiration); } } while (0)
1798 dict->mMatchDest.IsEmpty()do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "* %s: pattern %s, id %s, match-dest[0]: %s, hash: %s, expiration: "
"%u", dict->mURI.get(), dict->mPattern.get(), dict->
mId.get(), dict->mMatchDest.IsEmpty() ? "" : dom::GetEnumString
(dict->mMatchDest[0]).get(), dict->GetHash().get(), dict
->mExpiration); } } while (0)
1799 ? ""do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "* %s: pattern %s, id %s, match-dest[0]: %s, hash: %s, expiration: "
"%u", dict->mURI.get(), dict->mPattern.get(), dict->
mId.get(), dict->mMatchDest.IsEmpty() ? "" : dom::GetEnumString
(dict->mMatchDest[0]).get(), dict->GetHash().get(), dict
->mExpiration); } } while (0)
1800 : dom::GetEnumString(dict->mMatchDest[0]).get(),do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "* %s: pattern %s, id %s, match-dest[0]: %s, hash: %s, expiration: "
"%u", dict->mURI.get(), dict->mPattern.get(), dict->
mId.get(), dict->mMatchDest.IsEmpty() ? "" : dom::GetEnumString
(dict->mMatchDest[0]).get(), dict->GetHash().get(), dict
->mExpiration); } } while (0)
1801 dict->GetHash().get(), dict->mExpiration))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "* %s: pattern %s, id %s, match-dest[0]: %s, hash: %s, expiration: "
"%u", dict->mURI.get(), dict->mPattern.get(), dict->
mId.get(), dict->mMatchDest.IsEmpty() ? "" : dom::GetEnumString
(dict->mMatchDest[0]).get(), dict->GetHash().get(), dict
->mExpiration); } } while (0)
;
1802 }
1803 DICTIONARY_LOG(("*** Pending ***"))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "*** Pending ***"
); } } while (0)
;
1804 for (const auto& dict : mPendingEntries) {
1805 DICTIONARY_LOG(do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "* %s: pattern %s, id %s, match-dest[0]: %s, hash: %s, expiration: "
"%u", dict->mURI.get(), dict->mPattern.get(), dict->
mId.get(), dict->mMatchDest.IsEmpty() ? "" : dom::GetEnumString
(dict->mMatchDest[0]).get(), dict->GetHash().get(), dict
->mExpiration); } } while (0)
1806 ("* %s: pattern %s, id %s, match-dest[0]: %s, hash: %s, expiration: "do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "* %s: pattern %s, id %s, match-dest[0]: %s, hash: %s, expiration: "
"%u", dict->mURI.get(), dict->mPattern.get(), dict->
mId.get(), dict->mMatchDest.IsEmpty() ? "" : dom::GetEnumString
(dict->mMatchDest[0]).get(), dict->GetHash().get(), dict
->mExpiration); } } while (0)
1807 "%u",do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "* %s: pattern %s, id %s, match-dest[0]: %s, hash: %s, expiration: "
"%u", dict->mURI.get(), dict->mPattern.get(), dict->
mId.get(), dict->mMatchDest.IsEmpty() ? "" : dom::GetEnumString
(dict->mMatchDest[0]).get(), dict->GetHash().get(), dict
->mExpiration); } } while (0)
1808 dict->mURI.get(), dict->mPattern.get(), dict->mId.get(),do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "* %s: pattern %s, id %s, match-dest[0]: %s, hash: %s, expiration: "
"%u", dict->mURI.get(), dict->mPattern.get(), dict->
mId.get(), dict->mMatchDest.IsEmpty() ? "" : dom::GetEnumString
(dict->mMatchDest[0]).get(), dict->GetHash().get(), dict
->mExpiration); } } while (0)
1809 dict->mMatchDest.IsEmpty()do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "* %s: pattern %s, id %s, match-dest[0]: %s, hash: %s, expiration: "
"%u", dict->mURI.get(), dict->mPattern.get(), dict->
mId.get(), dict->mMatchDest.IsEmpty() ? "" : dom::GetEnumString
(dict->mMatchDest[0]).get(), dict->GetHash().get(), dict
->mExpiration); } } while (0)
1810 ? ""do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "* %s: pattern %s, id %s, match-dest[0]: %s, hash: %s, expiration: "
"%u", dict->mURI.get(), dict->mPattern.get(), dict->
mId.get(), dict->mMatchDest.IsEmpty() ? "" : dom::GetEnumString
(dict->mMatchDest[0]).get(), dict->GetHash().get(), dict
->mExpiration); } } while (0)
1811 : dom::GetEnumString(dict->mMatchDest[0]).get(),do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "* %s: pattern %s, id %s, match-dest[0]: %s, hash: %s, expiration: "
"%u", dict->mURI.get(), dict->mPattern.get(), dict->
mId.get(), dict->mMatchDest.IsEmpty() ? "" : dom::GetEnumString
(dict->mMatchDest[0]).get(), dict->GetHash().get(), dict
->mExpiration); } } while (0)
1812 dict->GetHash().get(), dict->mExpiration))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "* %s: pattern %s, id %s, match-dest[0]: %s, hash: %s, expiration: "
"%u", dict->mURI.get(), dict->mPattern.get(), dict->
mId.get(), dict->mMatchDest.IsEmpty() ? "" : dom::GetEnumString
(dict->mMatchDest[0]).get(), dict->GetHash().get(), dict
->mExpiration); } } while (0)
;
1813 }
1814}
1815
1816void DictionaryOrigin::Clear() {
1817 DICTIONARY_LOG(("*** Clearing origin %s", mOrigin.get()))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "*** Clearing origin %s"
, mOrigin.get()); } } while (0)
;
1818 mEntries.Clear();
1819 mPendingEntries.Clear();
1820 mPendingRemove.Clear();
1821 // We may be under a lock; doom this asynchronously
1822 if (mEntry) {
1823 // This will attempt to delete the DictionaryOrigin, but we'll do
1824 // that more directly
1825 NS_DispatchBackgroundTask(NS_NewRunnableFunction(
1826 "DictionaryOrigin::Clear", [entry = mEntry, origin(mOrigin)]() {
1827 DICTIONARY_LOG(("*** Dooming origin %s", origin.get()))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "*** Dooming origin %s"
, origin.get()); } } while (0)
;
1828 entry->AsyncDoom(nullptr);
1829 }));
1830 }
1831 gDictionaryCache->RemoveOrigin(mOrigin);
1832}
1833
1834// caller will throw this into a RefPtr
1835DictionaryCacheEntry* DictionaryOrigin::Match(const nsACString& aPath,
1836 ExtContentPolicyType aType) {
1837 uint32_t longest = 0;
1838 DictionaryCacheEntry* result = nullptr;
1839 uint32_t now = mozilla::net::NowInSeconds()PRTimeToSeconds(PR_Now());
1840
1841 for (const auto& dict : mEntries) {
1842 if (dict->Match(aPath, aType, now, longest)) {
1843 result = dict;
1844 }
1845 }
1846 // XXX if we want to LRU the origins so we can push them out of memory based
1847 // on LRU, do something like this:
1848 /*
1849 if (result) {
1850 removeFrom(dictionarycase->mDictionaryCacheLRU);
1851 dictionarycase->mDictionaryCacheLRU.insertFront(this);
1852 }
1853 */
1854 return result;
1855}
1856
1857//-----------------------------------------------------------------------------
1858// DictionaryOrigin::nsICacheEntryMetaDataVisitor
1859//-----------------------------------------------------------------------------
1860nsresult DictionaryOrigin::OnMetaDataElement(const char* asciiKey,
1861 const char* asciiValue) {
1862 DICTIONARY_LOG(("DictionaryOrigin::OnMetaDataElement %s %s",do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "DictionaryOrigin::OnMetaDataElement %s %s"
, asciiKey ? asciiKey : "", asciiValue); } } while (0)
1863 asciiKey ? asciiKey : "", asciiValue))do { const ::mozilla::LogModule* moz_real_module = gDictionaryLog
; if ((__builtin_expect(!!(mozilla::detail::log_test(moz_real_module
, mozilla::LogLevel::Debug)), 0))) { mozilla::detail::log_print
(moz_real_module, mozilla::LogLevel::Debug, "DictionaryOrigin::OnMetaDataElement %s %s"
, asciiKey ? asciiKey : "", asciiValue); } } while (0)
;
1864
1865 // We set the content ID to CONTENT_TYPE_DICTIONARY, ensure that's correct
1866 if (strcmp(asciiKey, "ctid") == 0) {
1867 MOZ_ASSERT(strcmp(asciiValue, "7") == 0)do { static_assert( mozilla::detail::AssertionConditionType<
decltype(strcmp(asciiValue, "7") == 0)>::isValid, "invalid assertion condition"
); if ((__builtin_expect(!!(!(!!(strcmp(asciiValue, "7") == 0
))), 0))) { do { } while (false); MOZ_ReportAssertionFailure(
"strcmp(asciiValue, \"7\") == 0", "./../../../netwerk/cache2/Dictionary.cpp"
, 1867); AnnotateMozCrashReason("MOZ_ASSERT" "(" "strcmp(asciiValue, \"7\") == 0"
")"); do { MOZ_CrashSequence(__null, 1867); __attribute__((nomerge
)) ::abort(); } while (false); } } while (false)
;
1868 return NS_OK;
1869 }
1870 // All other keys should be URLs for dictionaries
1871 // If we already have an entry for this key (pending or in the list),
1872 // don't override it
1873 for (auto& entry : mEntries) {
1874 if (entry->GetURI().Equals(asciiKey)) {
1875 return NS_OK;
1876 }
1877 }
1878 for (auto& entry : mPendingEntries) {
1879 if (entry->GetURI().Equals(asciiKey)) {
1880 return NS_OK;
1881 }
1882 }
1883 RefPtr<DictionaryCacheEntry> entry = new DictionaryCacheEntry(asciiKey);
1884 if (entry->ParseMetadata(asciiValue)) {
1885 mEntries.AppendElement(entry);
1886 }
1887 return NS_OK;
1888}
1889
1890// Overall structure:
1891// Dictionary:
1892// DictionaryCache:
1893// OriginHashmap:
1894// LinkedList: DictionaryCacheEntry
1895// Data from cache (sometimes)
1896//
1897// Each origin is in the cache as a dictionary-origin entry. In that
1898// entry's metadata, we have an LRU-sorted list of dictionary entries to be able
1899// to build a DictionaryCacheEntry.
1900// When we offer a dictionary on a load, we'll start prefetching the data into
1901// the DictionaryCacheEntry for the item in the cache. When the response comes
1902// in, we'll either use it to decompress, or indicate we no longer care about
1903// the data. If no one cares about the data, we'll purge it from memory.
1904// Hold refs to the data in requests. When the only ref is in the
1905// DictionaryCacheEntry, purge the data. This could also be done via the
1906// InUse counter
1907//
1908// XXX be careful about thrashing the cache loading and purging.
1909// XXX Perhaps allow a little dwell time in ram if not too large?
1910
1911// When a load comes in, we need to block decompressing it on having the data
1912// from the cache if it's dcb or dcz.
1913// XXX If the cache fails for some reason, we probably should consider
1914// re-fetching the data without Dictionary-Available.
1915
1916} // namespace net
1917} // namespace mozilla