/work/obj-fuzz/dist/include/mozilla/URLPreloader.h
Line | Count | Source (jump to first uncovered line) |
1 | | /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4; -*- */ |
2 | | /* This Source Code Form is subject to the terms of the Mozilla Public |
3 | | * License, v. 2.0. If a copy of the MPL was not distributed with this |
4 | | * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ |
5 | | |
6 | | #ifndef URLPreloader_h |
7 | | #define URLPreloader_h |
8 | | |
9 | | #include "mozilla/FileLocation.h" |
10 | | #include "mozilla/HashFunctions.h" |
11 | | #include "mozilla/LinkedList.h" |
12 | | #include "mozilla/MemoryReporting.h" |
13 | | #include "mozilla/Monitor.h" |
14 | | #include "mozilla/Omnijar.h" |
15 | | #include "mozilla/Range.h" |
16 | | #include "mozilla/Vector.h" |
17 | | #include "mozilla/Result.h" |
18 | | #include "nsClassHashtable.h" |
19 | | #include "nsHashKeys.h" |
20 | | #include "nsIChromeRegistry.h" |
21 | | #include "nsIFile.h" |
22 | | #include "nsIURI.h" |
23 | | #include "nsIMemoryReporter.h" |
24 | | #include "nsIObserver.h" |
25 | | #include "nsIResProtocolHandler.h" |
26 | | #include "nsIThread.h" |
27 | | #include "nsReadableUtils.h" |
28 | | |
29 | | class nsZipArchive; |
30 | | |
31 | | namespace mozilla { |
32 | | namespace loader { |
33 | | class InputBuffer; |
34 | | } |
35 | | |
36 | | using namespace mozilla::loader; |
37 | | |
38 | | class ScriptPreloader; |
39 | | |
40 | | /** |
41 | | * A singleton class to manage loading local URLs during startup, recording |
42 | | * them, and pre-loading them during early startup in the next session. URLs |
43 | | * that are not already loaded (or already being pre-loaded) when required are |
44 | | * read synchronously from disk, and (if startup is not already complete) |
45 | | * added to the pre-load list for the next session. |
46 | | */ |
47 | | class URLPreloader final : public nsIObserver |
48 | | , public nsIMemoryReporter |
49 | | { |
50 | | MOZ_DEFINE_MALLOC_SIZE_OF(MallocSizeOf) |
51 | | |
52 | | URLPreloader(); |
53 | | |
54 | | public: |
55 | | NS_DECL_THREADSAFE_ISUPPORTS |
56 | | NS_DECL_NSIOBSERVER |
57 | | NS_DECL_NSIMEMORYREPORTER |
58 | | |
59 | | static URLPreloader& GetSingleton(); |
60 | | |
61 | | // The type of read operation to perform. |
62 | | enum ReadType |
63 | | { |
64 | | // Read the file and then immediately forget its data. |
65 | | Forget, |
66 | | // Read the file and retain its data for the next caller. |
67 | | Retain, |
68 | | }; |
69 | | |
70 | | // Helpers to read the contents of files or JAR archive entries with various |
71 | | // representations. If the preloader has not yet been initialized, or the |
72 | | // given location is not supported by the cache, the entries will be read |
73 | | // synchronously, and not stored in the cache. |
74 | | static Result<const nsCString, nsresult> Read(FileLocation& location, ReadType readType = Forget); |
75 | | |
76 | | static Result<const nsCString, nsresult> ReadURI(nsIURI* uri, ReadType readType = Forget); |
77 | | |
78 | | static Result<const nsCString, nsresult> ReadFile(nsIFile* file, ReadType readType = Forget); |
79 | | |
80 | | static Result<const nsCString, nsresult> ReadZip(nsZipArchive* archive, |
81 | | const nsACString& path, |
82 | | ReadType readType = Forget); |
83 | | |
84 | | private: |
85 | | struct CacheKey; |
86 | | |
87 | | Result<const nsCString, nsresult> ReadInternal(const CacheKey& key, ReadType readType); |
88 | | |
89 | | Result<const nsCString, nsresult> ReadURIInternal(nsIURI* uri, ReadType readType); |
90 | | |
91 | | Result<const nsCString, nsresult> ReadFileInternal(nsIFile* file, ReadType readType); |
92 | | |
93 | | static Result<const nsCString, nsresult> Read(const CacheKey& key, ReadType readType); |
94 | | |
95 | | static bool sInitialized; |
96 | | |
97 | | static mozilla::StaticRefPtr<URLPreloader> sSingleton; |
98 | | |
99 | | protected: |
100 | | friend class AddonManagerStartup; |
101 | | friend class ScriptPreloader; |
102 | | |
103 | | virtual ~URLPreloader(); |
104 | | |
105 | | Result<Ok, nsresult> WriteCache(); |
106 | | |
107 | | static URLPreloader& ReInitialize(); |
108 | | |
109 | | // Clear leftover entries after the cache has been written. |
110 | | void Cleanup(); |
111 | | |
112 | | // Begins reading files off-thread, and ensures that initialization has |
113 | | // completed before leaving the current scope. The caller *must* ensure that |
114 | | // no code on the main thread access Omnijar, either directly or indirectly, |
115 | | // for the lifetime of this guard object. |
116 | | struct MOZ_RAII AutoBeginReading final |
117 | | { |
118 | | AutoBeginReading() |
119 | 6 | { |
120 | 6 | GetSingleton().BeginBackgroundRead(); |
121 | 6 | } |
122 | | |
123 | | ~AutoBeginReading() |
124 | 6 | { |
125 | 6 | auto& reader = GetSingleton(); |
126 | 6 | |
127 | 6 | MonitorAutoLock mal(reader.mMonitor); |
128 | 6 | |
129 | 7 | while (!reader.mReaderInitialized && URLPreloader::sInitialized) { |
130 | 1 | mal.Wait(); |
131 | 1 | } |
132 | 6 | } |
133 | | }; |
134 | | |
135 | | private: |
136 | | // Represents a key for an entry in the URI cache, based on its file or JAR |
137 | | // location. |
138 | | struct CacheKey |
139 | | { |
140 | | // The type of the entry. TypeAppJar and TypeGREJar entries are in the |
141 | | // app-specific or toolkit Omnijar files, and are handled specially. |
142 | | // TypeFile entries are plain files in the filesystem. |
143 | | enum EntryType : uint8_t |
144 | | { |
145 | | TypeAppJar, |
146 | | TypeGREJar, |
147 | | TypeFile, |
148 | | }; |
149 | | |
150 | 0 | CacheKey() = default; |
151 | 24 | CacheKey(const CacheKey& other) = default; |
152 | | |
153 | | CacheKey(EntryType type, const nsACString& path) |
154 | | : mType(type), mPath(path) |
155 | 18 | {} |
156 | | |
157 | | explicit CacheKey(nsIFile* file) |
158 | | : mType(TypeFile) |
159 | 6 | { |
160 | 6 | nsString path; |
161 | 6 | MOZ_ALWAYS_SUCCEEDS(file->GetPath(path)); |
162 | 6 | CopyUTF16toUTF8(path, mPath); |
163 | 6 | } |
164 | | |
165 | | explicit inline CacheKey(InputBuffer& buffer); |
166 | | |
167 | | // Encodes or decodes the cache key for storage in a session cache file. |
168 | | template <typename Buffer> |
169 | | void Code(Buffer& buffer) |
170 | 0 | { |
171 | 0 | buffer.codeUint8(*reinterpret_cast<uint8_t*>(&mType)); |
172 | 0 | buffer.codeString(mPath); |
173 | 0 | } Unexecuted instantiation: void mozilla::URLPreloader::CacheKey::Code<mozilla::loader::InputBuffer>(mozilla::loader::InputBuffer&) Unexecuted instantiation: void mozilla::URLPreloader::CacheKey::Code<mozilla::loader::OutputBuffer>(mozilla::loader::OutputBuffer&) |
174 | | |
175 | | uint32_t Hash() const |
176 | 0 | { |
177 | 0 | return HashGeneric(mType, HashString(mPath)); |
178 | 0 | } |
179 | | |
180 | | bool operator==(const CacheKey& other) const |
181 | 0 | { |
182 | 0 | return mType == other.mType && mPath == other.mPath; |
183 | 0 | } |
184 | | |
185 | | // Returns the Omnijar type for this entry. This may *only* be called |
186 | | // for Omnijar entries. |
187 | | Omnijar::Type OmnijarType() |
188 | 18 | { |
189 | 18 | switch (mType) { |
190 | 18 | case TypeAppJar: |
191 | 0 | return Omnijar::APP; |
192 | 18 | case TypeGREJar: |
193 | 18 | return Omnijar::GRE; |
194 | 18 | default: |
195 | 0 | MOZ_CRASH("Unexpected entry type"); |
196 | 0 | return Omnijar::GRE; |
197 | 18 | } |
198 | 18 | } |
199 | | |
200 | | const char* TypeString() |
201 | 0 | { |
202 | 0 | switch (mType) { |
203 | 0 | case TypeAppJar: return "AppJar"; |
204 | 0 | case TypeGREJar: return "GREJar"; |
205 | 0 | case TypeFile: return "File"; |
206 | 0 | } |
207 | 0 | MOZ_ASSERT_UNREACHABLE("no such type"); |
208 | 0 | return ""; |
209 | 0 | } |
210 | | |
211 | | already_AddRefed<nsZipArchive> Archive() |
212 | 18 | { |
213 | 18 | return Omnijar::GetReader(OmnijarType()); |
214 | 18 | } |
215 | | |
216 | | Result<FileLocation, nsresult> ToFileLocation(); |
217 | | |
218 | | EntryType mType = TypeFile; |
219 | | |
220 | | // The path of the entry. For Type*Jar entries, this is the path within |
221 | | // the Omnijar archive. For TypeFile entries, this is the full path to |
222 | | // the file. |
223 | | nsCString mPath{}; |
224 | | }; |
225 | | |
226 | | // Represents an entry in the URI cache. |
227 | | struct URLEntry final : public CacheKey |
228 | | , public LinkedListElement<URLEntry> |
229 | | { |
230 | | MOZ_IMPLICIT URLEntry(const CacheKey& key) |
231 | | : CacheKey(key) |
232 | | , mData(VoidCString()) |
233 | 24 | {} |
234 | | |
235 | | explicit URLEntry(nsIFile* file) |
236 | | : CacheKey(file) |
237 | 0 | {} |
238 | | |
239 | | // For use with nsTArray::Sort. |
240 | | // |
241 | | // Sorts entries by the time they were initially read during this |
242 | | // session. |
243 | | struct Comparator final |
244 | | { |
245 | | bool Equals(const URLEntry* a, const URLEntry* b) const |
246 | 0 | { |
247 | 0 | return a->mReadTime == b->mReadTime; |
248 | 0 | } |
249 | | |
250 | | bool LessThan(const URLEntry* a, const URLEntry* b) const |
251 | 0 | { |
252 | 0 | return a->mReadTime < b->mReadTime; |
253 | 0 | } |
254 | | }; |
255 | | |
256 | | // Sets the first-used time of this file to the earlier of its current |
257 | | // first-use time or the given timestamp. |
258 | | void UpdateUsedTime(const TimeStamp& time = TimeStamp::Now()) |
259 | 0 | { |
260 | 0 | if (!mReadTime || time < mReadTime) { |
261 | 0 | mReadTime = time; |
262 | 0 | } |
263 | 0 | } |
264 | | |
265 | | Result<const nsCString, nsresult> Read(); |
266 | | static Result<const nsCString, nsresult> ReadLocation(FileLocation& location); |
267 | | |
268 | | size_t SizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf) const |
269 | 0 | { |
270 | 0 | return (mallocSizeOf(this) + |
271 | 0 | mPath.SizeOfExcludingThisEvenIfShared(mallocSizeOf) + |
272 | 0 | mData.SizeOfExcludingThisEvenIfShared(mallocSizeOf)); |
273 | 0 | } |
274 | | |
275 | | // Reads the contents of the file referenced by this entry, or wait for |
276 | | // an off-thread read operation to finish if it is currently pending, |
277 | | // and return the file's contents. |
278 | | Result<const nsCString, nsresult> ReadOrWait(ReadType readType); |
279 | | |
280 | | nsCString mData; |
281 | | |
282 | | TimeStamp mReadTime{}; |
283 | | |
284 | | nsresult mResultCode = NS_OK; |
285 | | }; |
286 | | |
287 | | // Resolves the given URI to a CacheKey, if the URI is cacheable. |
288 | | Result<CacheKey, nsresult> ResolveURI(nsIURI* uri); |
289 | | |
290 | | Result<Ok, nsresult> InitInternal(); |
291 | | |
292 | | // Returns a file pointer to the (possibly nonexistent) cache file with the |
293 | | // given suffix. |
294 | | Result<nsCOMPtr<nsIFile>, nsresult> GetCacheFile(const nsAString& suffix); |
295 | | // Finds the correct cache file to use for this session. |
296 | | Result<nsCOMPtr<nsIFile>, nsresult> FindCacheFile(); |
297 | | |
298 | | Result<Ok, nsresult> ReadCache(LinkedList<URLEntry>& pendingURLs); |
299 | | |
300 | | void BackgroundReadFiles(); |
301 | | void BeginBackgroundRead(); |
302 | | |
303 | | using HashType = nsClassHashtable<nsGenericHashKey<CacheKey>, URLEntry>; |
304 | | |
305 | | size_t ShallowSizeOfIncludingThis(mozilla::MallocSizeOf mallocSizeOf); |
306 | | |
307 | | |
308 | | bool mStartupFinished = false; |
309 | | bool mReaderInitialized = false; |
310 | | |
311 | | // Only to be accessed from the cache write thread. |
312 | | bool mCacheWritten = false; |
313 | | |
314 | | // The prefix URLs for files in the GRE and App omni jar archives. |
315 | | nsCString mGREPrefix; |
316 | | nsCString mAppPrefix; |
317 | | |
318 | | nsCOMPtr<nsIResProtocolHandler> mResProto; |
319 | | nsCOMPtr<nsIChromeRegistry> mChromeReg; |
320 | | nsCOMPtr<nsIFile> mProfD; |
321 | | |
322 | | nsCOMPtr<nsIThread> mReaderThread; |
323 | | |
324 | | // A map of URL entries which have were either read this session, or read |
325 | | // from the last session's cache file. |
326 | | HashType mCachedURLs; |
327 | | |
328 | | Monitor mMonitor{"[URLPreloader::mMutex]"}; |
329 | | }; |
330 | | |
331 | | } // namespace mozilla |
332 | | |
333 | | #endif // URLPreloader_h |