summaryrefslogtreecommitdiffstats
path: root/netwerk/base/Predictor.h
blob: a16e09adad65328f7594faa8c74f08669d4632fa (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
/* vim: set ts=2 sts=2 et sw=2: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */

#ifndef mozilla_net_Predictor_h
#define mozilla_net_Predictor_h

#include "nsINetworkPredictor.h"
#include "nsINetworkPredictorVerifier.h"

#include "nsCOMPtr.h"
#include "nsICacheEntry.h"
#include "nsICacheEntryOpenCallback.h"
#include "nsICacheStorageService.h"
#include "nsICacheStorageVisitor.h"
#include "nsIDNSListener.h"
#include "nsIInterfaceRequestor.h"
#include "nsIObserver.h"
#include "nsISpeculativeConnect.h"
#include "nsIStreamListener.h"
#include "mozilla/RefPtr.h"
#include "nsString.h"
#include "nsTArray.h"

#include "mozilla/TimeStamp.h"

class nsICacheStorage;
class nsIDNSService;
class nsIIOService;
class nsILoadContextInfo;
class nsITimer;

namespace mozilla {
namespace net {

class nsHttpRequestHead;
class nsHttpResponseHead;

class Predictor final : public nsINetworkPredictor,
                        public nsIObserver,
                        public nsISpeculativeConnectionOverrider,
                        public nsIInterfaceRequestor,
                        public nsICacheEntryMetaDataVisitor,
                        public nsINetworkPredictorVerifier {
 public:
  NS_DECL_ISUPPORTS
  NS_DECL_NSINETWORKPREDICTOR
  NS_DECL_NSIOBSERVER
  NS_DECL_NSISPECULATIVECONNECTIONOVERRIDER
  NS_DECL_NSIINTERFACEREQUESTOR
  NS_DECL_NSICACHEENTRYMETADATAVISITOR
  NS_DECL_NSINETWORKPREDICTORVERIFIER

  Predictor();

  nsresult Init();
  void Shutdown();
  static nsresult Create(const nsIID& iid, void** result);

  // Used to update whether a particular URI was cacheable or not.
  // sourceURI and targetURI are the same as the arguments to Learn
  // and httpStatus is the status code we got while loading targetURI.
  static void UpdateCacheability(nsIURI* sourceURI, nsIURI* targetURI,
                                 uint32_t httpStatus,
                                 nsHttpRequestHead& requestHead,
                                 nsHttpResponseHead* responseHead,
                                 nsILoadContextInfo* lci, bool isTracking);

 private:
  virtual ~Predictor();

  // Stores callbacks for a child process predictor (for test purposes)
  nsCOMPtr<nsINetworkPredictorVerifier> mChildVerifier;

  union Reason {
    PredictorLearnReason mLearn;
    PredictorPredictReason mPredict;
  };

  class DNSListener : public nsIDNSListener {
   public:
    NS_DECL_THREADSAFE_ISUPPORTS
    NS_DECL_NSIDNSLISTENER

    DNSListener() = default;

   private:
    virtual ~DNSListener() = default;
  };

  class Action : public nsICacheEntryOpenCallback {
   public:
    NS_DECL_THREADSAFE_ISUPPORTS
    NS_DECL_NSICACHEENTRYOPENCALLBACK

    Action(bool fullUri, bool predict, Reason reason, nsIURI* targetURI,
           nsIURI* sourceURI, nsINetworkPredictorVerifier* verifier,
           Predictor* predictor);
    Action(bool fullUri, bool predict, Reason reason, nsIURI* targetURI,
           nsIURI* sourceURI, nsINetworkPredictorVerifier* verifier,
           Predictor* predictor, uint8_t stackCount);

    static const bool IS_FULL_URI = true;
    static const bool IS_ORIGIN = false;

    static const bool DO_PREDICT = true;
    static const bool DO_LEARN = false;

   private:
    virtual ~Action() = default;

    bool mFullUri : 1;
    bool mPredict : 1;
    union {
      PredictorPredictReason mPredictReason;
      PredictorLearnReason mLearnReason;
    };
    nsCOMPtr<nsIURI> mTargetURI;
    nsCOMPtr<nsIURI> mSourceURI;
    nsCOMPtr<nsINetworkPredictorVerifier> mVerifier;
    TimeStamp mStartTime;
    uint8_t mStackCount;
    RefPtr<Predictor> mPredictor;
  };

  class CacheabilityAction : public nsICacheEntryOpenCallback,
                             public nsICacheEntryMetaDataVisitor {
   public:
    NS_DECL_THREADSAFE_ISUPPORTS
    NS_DECL_NSICACHEENTRYOPENCALLBACK
    NS_DECL_NSICACHEENTRYMETADATAVISITOR

    CacheabilityAction(nsIURI* targetURI, uint32_t httpStatus,
                       const nsCString& method, bool isTracking, bool couldVary,
                       bool isNoStore, Predictor* predictor)
        : mTargetURI(targetURI),
          mHttpStatus(httpStatus),
          mMethod(method),
          mIsTracking(isTracking),
          mCouldVary(couldVary),
          mIsNoStore(isNoStore),
          mPredictor(predictor) {}

   private:
    virtual ~CacheabilityAction() = default;

    nsCOMPtr<nsIURI> mTargetURI;
    uint32_t mHttpStatus;
    nsCString mMethod;
    bool mIsTracking;
    bool mCouldVary;
    bool mIsNoStore;
    RefPtr<Predictor> mPredictor;
    nsTArray<nsCString> mKeysToCheck;
    nsTArray<nsCString> mValuesToCheck;
  };

  class Resetter : public nsICacheEntryOpenCallback,
                   public nsICacheEntryMetaDataVisitor,
                   public nsICacheStorageVisitor {
   public:
    NS_DECL_THREADSAFE_ISUPPORTS
    NS_DECL_NSICACHEENTRYOPENCALLBACK
    NS_DECL_NSICACHEENTRYMETADATAVISITOR
    NS_DECL_NSICACHESTORAGEVISITOR

    explicit Resetter(Predictor* predictor);

   private:
    virtual ~Resetter() = default;

    void Complete();

    uint32_t mEntriesToVisit;
    nsTArray<nsCString> mKeysToDelete;
    RefPtr<Predictor> mPredictor;
    nsTArray<nsCOMPtr<nsIURI>> mURIsToVisit;
    nsTArray<nsCOMPtr<nsILoadContextInfo>> mInfosToVisit;
  };

  class SpaceCleaner : public nsICacheEntryMetaDataVisitor {
   public:
    NS_DECL_ISUPPORTS
    NS_DECL_NSICACHEENTRYMETADATAVISITOR

    explicit SpaceCleaner(Predictor* predictor)
        : mLRUStamp(0), mLRUKeyToDelete(nullptr), mPredictor(predictor) {}

    void Finalize(nsICacheEntry* entry);

   private:
    virtual ~SpaceCleaner() = default;
    uint32_t mLRUStamp;
    const char* mLRUKeyToDelete;
    nsTArray<nsCString> mLongKeysToDelete;
    RefPtr<Predictor> mPredictor;
  };

  class PrefetchListener : public nsIStreamListener {
   public:
    NS_DECL_ISUPPORTS
    NS_DECL_NSIREQUESTOBSERVER
    NS_DECL_NSISTREAMLISTENER

    PrefetchListener(nsINetworkPredictorVerifier* verifier, nsIURI* uri,
                     Predictor* predictor)
        : mVerifier(verifier), mURI(uri), mPredictor(predictor) {}

   private:
    virtual ~PrefetchListener() = default;

    nsCOMPtr<nsINetworkPredictorVerifier> mVerifier;
    nsCOMPtr<nsIURI> mURI;
    RefPtr<Predictor> mPredictor;
    TimeStamp mStartTime;
  };

  // Observer-related stuff
  nsresult InstallObserver();
  void RemoveObserver();

  // Service startup utilities
  void MaybeCleanupOldDBFiles();

  // The guts of prediction

  // This is the top-level driver for doing any prediction that needs
  // information from the cache. Returns true if any predictions were queued up
  //   * reason - What kind of prediction this is/why this prediction is
  //              happening (pageload, startup)
  //   * entry - the cache entry with the information we need
  //   * isNew - whether or not the cache entry is brand new and empty
  //   * fullUri - whether we are doing predictions based on a full page URI, or
  //               just the origin of the page
  //   * targetURI - the URI that we are predicting based upon - IOW, the URI
  //                 that is being loaded or being redirected to
  //   * verifier - used for testing to verify the expected predictions happen
  //   * stackCount - used to ensure we don't recurse too far trying to find the
  //                  final redirection in a redirect chain
  bool PredictInternal(PredictorPredictReason reason, nsICacheEntry* entry,
                       bool isNew, bool fullUri, nsIURI* targetURI,
                       nsINetworkPredictorVerifier* verifier,
                       uint8_t stackCount);

  // Used when predicting because the user's mouse hovered over a link
  //   * targetURI - the URI target of the link
  //   * sourceURI - the URI of the page on which the link appears
  //   * originAttributes - the originAttributes for this prediction
  //   * verifier - used for testing to verify the expected predictions happen
  void PredictForLink(nsIURI* targetURI, nsIURI* sourceURI,
                      const OriginAttributes& originAttributes,
                      nsINetworkPredictorVerifier* verifier);

  // Used when predicting because a page is being loaded (which may include
  // being the target of a redirect). All arguments are the same as for
  // PredictInternal. Returns true if any predictions were queued up.
  bool PredictForPageload(nsICacheEntry* entry, nsIURI* targetURI,
                          uint8_t stackCount, bool fullUri,
                          nsINetworkPredictorVerifier* verifier);

  // Used when predicting pages that will be used near browser startup. All
  // arguments are the same as for PredictInternal. Returns true if any
  // predictions were queued up.
  bool PredictForStartup(nsICacheEntry* entry, bool fullUri,
                         nsINetworkPredictorVerifier* verifier);

  // Utilities related to prediction

  // Used to update our rolling load count (how many of the last n loads was a
  // partular resource loaded on?)
  //   * entry - cache entry of page we're loading
  //   * flags - value that contains our rolling count as the top 20 bits (but
  //             we may use fewer than those 20 bits for calculations)
  //   * key - metadata key that we will update on entry
  //   * hitCount - part of the metadata we need to preserve
  //   * lastHit - part of the metadata we need to preserve
  void UpdateRollingLoadCount(nsICacheEntry* entry, const uint32_t flags,
                              const char* key, const uint32_t hitCount,
                              const uint32_t lastHit);

  // Used to calculate how much to degrade our confidence for all resources
  // on a particular page, because of how long ago the most recent load of that
  // page was. Returns a value between 0 (very recent most recent load) and 100
  // (very distant most recent load)
  //   * lastLoad - time stamp of most recent load of a page
  int32_t CalculateGlobalDegradation(uint32_t lastLoad);

  // Used to calculate how confident we are that a particular resource will be
  // used. Returns a value between 0 (no confidence) and 100 (very confident)
  //   * hitCount - number of times this resource has been seen when loading
  //                this page
  //   * hitsPossible - number of times this page has been loaded
  //   * lastHit - timestamp of the last time this resource was seen when
  //               loading this page
  //   * lastPossible - timestamp of the last time this page was loaded
  //   * globalDegradation - value calculated by CalculateGlobalDegradation for
  //                         this page
  int32_t CalculateConfidence(uint32_t hitCount, uint32_t hitsPossible,
                              uint32_t lastHit, uint32_t lastPossible,
                              int32_t globalDegradation);

  // Used to calculate all confidence values for all resources associated with a
  // page.
  //   * entry - the cache entry with all necessary information about this page
  //   * referrer - the URI that we are loading (may be null)
  //   * lastLoad - timestamp of the last time this page was loaded
  //   * loadCount - number of times this page has been loaded
  //   * gloablDegradation - value calculated by CalculateGlobalDegradation for
  //                         this page
  //   * fullUri - whether we're predicting for a full URI or origin-only
  void CalculatePredictions(nsICacheEntry* entry, nsIURI* referrer,
                            uint32_t lastLoad, uint32_t loadCount,
                            int32_t globalDegradation, bool fullUri);

  enum PrefetchIgnoreReason {
    PREFETCH_OK,
    NOT_FULL_URI,
    NO_REFERRER,
    MISSED_A_LOAD,
    PREFETCH_DISABLED,
    PREFETCH_DISABLED_VIA_COUNT,
    CONFIDENCE_TOO_LOW
  };

  // Used to prepare any necessary prediction for a resource on a page
  //   * confidence - value calculated by CalculateConfidence for this resource
  //   * flags - the flags taken from the resource
  //   * uri - the ascii spec of the URI of the resource
  void SetupPrediction(int32_t confidence, uint32_t flags, const nsCString& uri,
                       PrefetchIgnoreReason reason);

  // Used to kick off a prefetch from RunPredictions if necessary
  //   * uri - the URI to prefetch
  //   * referrer - the URI of the referring page
  //   * originAttributes - the originAttributes of this prefetch
  //   * verifier - used for testing to ensure the expected prefetch happens
  nsresult Prefetch(nsIURI* uri, nsIURI* referrer,
                    const OriginAttributes& originAttributes,
                    nsINetworkPredictorVerifier* verifier);

  // Used to actually perform any predictions set up via SetupPrediction.
  // Returns true if any predictions were performed.
  //   * referrer - the URI we are predicting from
  //   * originAttributs - the originAttributes we are predicting from
  //   * verifier - used for testing to ensure the expected predictions happen
  bool RunPredictions(nsIURI* referrer,
                      const OriginAttributes& originAttributes,
                      nsINetworkPredictorVerifier* verifier);

  // Used to guess whether a page will redirect to another page or not. Returns
  // true if a redirection is likely.
  //   * entry - cache entry with all necessary information about this page
  //   * loadCount - number of times this page has been loaded
  //   * lastLoad - timestamp of the last time this page was loaded
  //   * globalDegradation - value calculated by CalculateGlobalDegradation for
  //                         this page
  //   * redirectURI - if this returns true, the URI that is likely to be
  //                   redirected to, otherwise null
  bool WouldRedirect(nsICacheEntry* entry, uint32_t loadCount,
                     uint32_t lastLoad, int32_t globalDegradation,
                     nsIURI** redirectURI);

  // The guts of learning information

  // This is the top-level driver for doing any updating of our information in
  // the cache
  //   * reason - why this learn is happening (pageload, startup, redirect)
  //   * entry - the cache entry with the information we need
  //   * isNew - whether or not the cache entry is brand new and empty
  //   * fullUri - whether we are doing predictions based on a full page URI, or
  //               just the origin of the page
  //   * targetURI - the URI that we are adding to our data - most often a
  //                 resource loaded by a page the user navigated to
  //   * sourceURI - the URI that caused targetURI to be loaded, usually the
  //                 page the user navigated to
  void LearnInternal(PredictorLearnReason reason, nsICacheEntry* entry,
                     bool isNew, bool fullUri, nsIURI* targetURI,
                     nsIURI* sourceURI);

  // Used when learning about a resource loaded by a page
  //   * entry - the cache entry with information that needs updating
  //   * targetURI - the URI of the resource that was loaded by the page
  void LearnForSubresource(nsICacheEntry* entry, nsIURI* targetURI);

  // Used when learning about a redirect from one page to another
  //   * entry - the cache entry of the page that was redirected from
  //   * targetURI - the URI of the redirect target
  void LearnForRedirect(nsICacheEntry* entry, nsIURI* targetURI);

  // Used to learn about pages loaded close to browser startup. This results in
  // LearnForStartup being called if we are, in fact, near browser startup
  //   * uri - the URI of a page that has been loaded (may not have been near
  //           browser startup)
  //   * fullUri - true if this is a full page uri, false if it's an origin
  //   * originAttributes - the originAttributes for this learning.
  void MaybeLearnForStartup(nsIURI* uri, bool fullUri,
                            const OriginAttributes& originAttributes);

  // Used in conjunction with MaybeLearnForStartup to learn about pages loaded
  // close to browser startup
  //   * entry - the cache entry that stores the startup page list
  //   * targetURI - the URI of a page that was loaded near browser startup
  void LearnForStartup(nsICacheEntry* entry, nsIURI* targetURI);

  // Used to parse the data we store in cache metadata
  //   * key - the cache metadata key
  //   * value - the cache metadata value
  //   * uri - (out) the ascii spec of the URI this metadata entry was about
  //   * hitCount - (out) the number of times this URI has been seen
  //   * lastHit - (out) timestamp of the last time this URI was seen
  //   * flags - (out) flags for this metadata entry
  bool ParseMetaDataEntry(const char* key, const char* value, nsCString& uri,
                          uint32_t& hitCount, uint32_t& lastHit,
                          uint32_t& flags);

  // Used to update whether a particular URI was cacheable or not.
  // sourceURI and targetURI are the same as the arguments to Learn
  // and httpStatus is the status code we got while loading targetURI.
  void UpdateCacheabilityInternal(nsIURI* sourceURI, nsIURI* targetURI,
                                  uint32_t httpStatus, const nsCString& method,
                                  const OriginAttributes& originAttributes,
                                  bool isTracking, bool couldVary,
                                  bool isNoStore);

  // Gets the pref value and clamps it within the acceptable range.
  uint32_t ClampedPrefetchRollingLoadCount();

  // Our state
  bool mInitialized{false};

  nsTArray<nsCString> mKeysToOperateOn;
  nsTArray<nsCString> mValuesToOperateOn;

  nsCOMPtr<nsICacheStorageService> mCacheStorageService;

  nsCOMPtr<nsISpeculativeConnect> mSpeculativeService;

  nsCOMPtr<nsIURI> mStartupURI;
  uint32_t mStartupTime{0};
  uint32_t mLastStartupTime{0};
  int32_t mStartupCount{1};

  nsCOMPtr<nsIDNSService> mDnsService;

  RefPtr<DNSListener> mDNSListener;

  nsTArray<nsCOMPtr<nsIURI>> mPrefetches;
  nsTArray<nsCOMPtr<nsIURI>> mPreconnects;
  nsTArray<nsCOMPtr<nsIURI>> mPreresolves;

  static Predictor* sSelf;
};

}  // namespace net
}  // namespace mozilla

#endif  // mozilla_net_Predictor_h