Coverage Report

Created: 2018-09-25 14:53

/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