Bug Summary

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