tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

nsHtml5SpeculativeLoad.h (17866B)


      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 #ifndef nsHtml5SpeculativeLoad_h
      6 #define nsHtml5SpeculativeLoad_h
      7 
      8 #include "nsString.h"
      9 #include "nsContentUtils.h"
     10 #include "nsHtml5DocumentMode.h"
     11 #include "nsHtml5String.h"
     12 #include "ReferrerInfo.h"
     13 
     14 class nsHtml5TreeOpExecutor;
     15 
     16 enum eHtml5SpeculativeLoad {
     17  eSpeculativeLoadUninitialized,
     18  eSpeculativeLoadBase,
     19  eSpeculativeLoadCSP,
     20  eSpeculativeLoadMetaReferrer,
     21  eSpeculativeLoadImage,
     22  eSpeculativeLoadOpenPicture,
     23  eSpeculativeLoadEndPicture,
     24  eSpeculativeLoadPictureSource,
     25  eSpeculativeLoadScript,
     26  eSpeculativeLoadScriptFromHead,
     27  eSpeculativeLoadStyle,
     28  eSpeculativeLoadManifest,
     29  eSpeculativeLoadSetDocumentCharset,
     30  eSpeculativeLoadSetDocumentMode,
     31  eSpeculativeLoadPreconnect,
     32  eSpeculativeLoadFont,
     33  eSpeculativeLoadFetch,
     34  eSpeculativeLoadMaybeComplainAboutCharset
     35 };
     36 
     37 class nsHtml5SpeculativeLoad {
     38  using Encoding = mozilla::Encoding;
     39  template <typename T>
     40  using NotNull = mozilla::NotNull<T>;
     41 
     42 public:
     43  nsHtml5SpeculativeLoad();
     44  ~nsHtml5SpeculativeLoad();
     45 
     46  inline void InitBase(nsHtml5String aUrl) {
     47    MOZ_ASSERT(mOpCode == eSpeculativeLoadUninitialized,
     48               "Trying to reinitialize a speculative load!");
     49    mOpCode = eSpeculativeLoadBase;
     50    aUrl.ToString(mUrlOrSizes);
     51  }
     52 
     53  inline void InitMetaCSP(nsHtml5String aCSP) {
     54    MOZ_ASSERT(mOpCode == eSpeculativeLoadUninitialized,
     55               "Trying to reinitialize a speculative load!");
     56    mOpCode = eSpeculativeLoadCSP;
     57    nsString csp;  // Not Auto, because using it to hold nsStringBuffer*
     58    aCSP.ToString(csp);
     59    mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity.Assign(
     60        nsContentUtils::TrimWhitespace<nsContentUtils::IsHTMLWhitespace>(csp));
     61  }
     62 
     63  inline void InitMetaReferrerPolicy(nsHtml5String aReferrerPolicy) {
     64    MOZ_ASSERT(mOpCode == eSpeculativeLoadUninitialized,
     65               "Trying to reinitialize a speculative load!");
     66    mOpCode = eSpeculativeLoadMetaReferrer;
     67    nsString
     68        referrerPolicy;  // Not Auto, because using it to hold nsStringBuffer*
     69    aReferrerPolicy.ToString(referrerPolicy);
     70    mReferrerPolicyOrIntegrity.Assign(
     71        nsContentUtils::TrimWhitespace<nsContentUtils::IsHTMLWhitespace>(
     72            referrerPolicy));
     73  }
     74 
     75  inline void InitImage(nsHtml5String aUrl, nsHtml5String aCrossOrigin,
     76                        nsHtml5String aMedia, nsHtml5String aReferrerPolicy,
     77                        nsHtml5String aSrcset, nsHtml5String aSizes,
     78                        bool aLinkPreload, nsHtml5String aFetchPriority,
     79                        nsHtml5String aType) {
     80    MOZ_ASSERT(mOpCode == eSpeculativeLoadUninitialized,
     81               "Trying to reinitialize a speculative load!");
     82    mOpCode = eSpeculativeLoadImage;
     83    aUrl.ToString(mUrlOrSizes);
     84    aCrossOrigin.ToString(mCrossOrigin);
     85    aMedia.ToString(mMedia);
     86    nsString
     87        referrerPolicy;  // Not Auto, because using it to hold nsStringBuffer*
     88    aReferrerPolicy.ToString(referrerPolicy);
     89    mReferrerPolicyOrIntegrity.Assign(
     90        nsContentUtils::TrimWhitespace<nsContentUtils::IsHTMLWhitespace>(
     91            referrerPolicy));
     92    aSrcset.ToString(mCharsetOrSrcset);
     93    aSizes.ToString(
     94        mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity);
     95    mIsLinkPreload = aLinkPreload;
     96    aFetchPriority.ToString(mFetchPriority);
     97    aType.ToString(mNonceOrType);
     98  }
     99 
    100  inline void InitFont(nsHtml5String aUrl, nsHtml5String aCrossOrigin,
    101                       nsHtml5String aMedia, nsHtml5String aReferrerPolicy,
    102                       nsHtml5String aFetchPriority) {
    103    MOZ_ASSERT(mOpCode == eSpeculativeLoadUninitialized,
    104               "Trying to reinitialize a speculative load!");
    105    mOpCode = eSpeculativeLoadFont;
    106    aUrl.ToString(mUrlOrSizes);
    107    aCrossOrigin.ToString(mCrossOrigin);
    108    aMedia.ToString(mMedia);
    109    nsString
    110        referrerPolicy;  // Not Auto, because using it to hold nsStringBuffer*
    111    aReferrerPolicy.ToString(referrerPolicy);
    112    mReferrerPolicyOrIntegrity.Assign(
    113        nsContentUtils::TrimWhitespace<nsContentUtils::IsHTMLWhitespace>(
    114            referrerPolicy));
    115    aFetchPriority.ToString(mFetchPriority);
    116    // This can be only triggered by <link rel=preload type=font>
    117    mIsLinkPreload = true;
    118  }
    119 
    120  inline void InitFetch(nsHtml5String aUrl, nsHtml5String aCrossOrigin,
    121                        nsHtml5String aMedia, nsHtml5String aReferrerPolicy,
    122                        nsHtml5String aFetchPriority) {
    123    MOZ_ASSERT(mOpCode == eSpeculativeLoadUninitialized,
    124               "Trying to reinitialize a speculative load!");
    125    mOpCode = eSpeculativeLoadFetch;
    126    aUrl.ToString(mUrlOrSizes);
    127    aCrossOrigin.ToString(mCrossOrigin);
    128    aMedia.ToString(mMedia);
    129    nsString
    130        referrerPolicy;  // Not Auto, because using it to hold nsStringBuffer*
    131    aReferrerPolicy.ToString(referrerPolicy);
    132    mReferrerPolicyOrIntegrity.Assign(
    133        nsContentUtils::TrimWhitespace<nsContentUtils::IsHTMLWhitespace>(
    134            referrerPolicy));
    135    aFetchPriority.ToString(mFetchPriority);
    136 
    137    // This method can be only be triggered by <link rel=preload type=fetch>,
    138    // hence this operation is always a preload.
    139    mIsLinkPreload = true;
    140  }
    141 
    142  // <picture> elements have multiple <source> nodes followed by an <img>,
    143  // where we use the first valid source, which may be the img. Because we
    144  // can't determine validity at this point without parsing CSS and getting
    145  // main thread state, we push preload operations for picture pushed and
    146  // popped, so that the target of the preload ops can determine what picture
    147  // and nesting level each source/img from the main preloading code exists
    148  // at.
    149  inline void InitOpenPicture() {
    150    MOZ_ASSERT(mOpCode == eSpeculativeLoadUninitialized,
    151               "Trying to reinitialize a speculative load!");
    152    mOpCode = eSpeculativeLoadOpenPicture;
    153  }
    154 
    155  inline void InitEndPicture() {
    156    MOZ_ASSERT(mOpCode == eSpeculativeLoadUninitialized,
    157               "Trying to reinitialize a speculative load!");
    158    mOpCode = eSpeculativeLoadEndPicture;
    159  }
    160 
    161  inline void InitPictureSource(nsHtml5String aSrcset, nsHtml5String aSizes,
    162                                nsHtml5String aType, nsHtml5String aMedia) {
    163    MOZ_ASSERT(mOpCode == eSpeculativeLoadUninitialized,
    164               "Trying to reinitialize a speculative load!");
    165    mOpCode = eSpeculativeLoadPictureSource;
    166    aSrcset.ToString(mCharsetOrSrcset);
    167    aSizes.ToString(mUrlOrSizes);
    168    aType.ToString(
    169        mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity);
    170    aMedia.ToString(mMedia);
    171  }
    172 
    173  inline void InitScript(nsHtml5String aUrl, nsHtml5String aCharset,
    174                         nsHtml5String aType, nsHtml5String aCrossOrigin,
    175                         nsHtml5String aMedia, nsHtml5String aNonce,
    176                         nsHtml5String aFetchPriority, nsHtml5String aIntegrity,
    177                         nsHtml5String aReferrerPolicy, bool aParserInHead,
    178                         bool aAsync, bool aDefer, bool aLinkPreload) {
    179    MOZ_ASSERT(mOpCode == eSpeculativeLoadUninitialized,
    180               "Trying to reinitialize a speculative load!");
    181    mOpCode =
    182        aParserInHead ? eSpeculativeLoadScriptFromHead : eSpeculativeLoadScript;
    183    aUrl.ToString(mUrlOrSizes);
    184    aCharset.ToString(mCharsetOrSrcset);
    185    aType.ToString(
    186        mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity);
    187    aCrossOrigin.ToString(mCrossOrigin);
    188    aMedia.ToString(mMedia);
    189    aNonce.ToString(mNonceOrType);
    190    aFetchPriority.ToString(mFetchPriority);
    191    aIntegrity.ToString(mReferrerPolicyOrIntegrity);
    192    nsAutoString referrerPolicy;
    193    aReferrerPolicy.ToString(referrerPolicy);
    194    referrerPolicy =
    195        nsContentUtils::TrimWhitespace<nsContentUtils::IsHTMLWhitespace>(
    196            referrerPolicy);
    197    mScriptReferrerPolicy =
    198        mozilla::dom::ReferrerInfo::ReferrerPolicyAttributeFromString(
    199            referrerPolicy);
    200 
    201    mIsAsync = aAsync;
    202    mIsDefer = aDefer;
    203    mIsLinkPreload = aLinkPreload;
    204  }
    205 
    206  inline void InitImportStyle(nsString&& aUrl) {
    207    MOZ_ASSERT(mOpCode == eSpeculativeLoadUninitialized,
    208               "Trying to reinitialize a speculative load!");
    209    mOpCode = eSpeculativeLoadStyle;
    210    mUrlOrSizes = std::move(aUrl);
    211    mCharsetOrSrcset.SetIsVoid(true);
    212    mCrossOrigin.SetIsVoid(true);
    213    mMedia.SetIsVoid(true);
    214    mReferrerPolicyOrIntegrity.SetIsVoid(true);
    215    mNonceOrType.SetIsVoid(true);
    216    mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity.SetIsVoid(
    217        true);
    218  }
    219 
    220  inline void InitStyle(nsHtml5String aUrl, nsHtml5String aCharset,
    221                        nsHtml5String aCrossOrigin, nsHtml5String aMedia,
    222                        nsHtml5String aReferrerPolicy, nsHtml5String aNonce,
    223                        nsHtml5String aIntegrity, bool aLinkPreload,
    224                        nsHtml5String aFetchPriority) {
    225    MOZ_ASSERT(mOpCode == eSpeculativeLoadUninitialized,
    226               "Trying to reinitialize a speculative load!");
    227    mOpCode = eSpeculativeLoadStyle;
    228    aUrl.ToString(mUrlOrSizes);
    229    aCharset.ToString(mCharsetOrSrcset);
    230    aCrossOrigin.ToString(mCrossOrigin);
    231    aMedia.ToString(mMedia);
    232    nsString
    233        referrerPolicy;  // Not Auto, because using it to hold nsStringBuffer*
    234    aReferrerPolicy.ToString(referrerPolicy);
    235    mReferrerPolicyOrIntegrity.Assign(
    236        nsContentUtils::TrimWhitespace<nsContentUtils::IsHTMLWhitespace>(
    237            referrerPolicy));
    238    aNonce.ToString(mNonceOrType);
    239    aIntegrity.ToString(
    240        mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity);
    241    mIsLinkPreload = aLinkPreload;
    242    aFetchPriority.ToString(mFetchPriority);
    243  }
    244 
    245  /**
    246   * "Speculative" manifest loads aren't truly speculative--if a manifest
    247   * gets loaded, we are committed to it. There can never be a <script>
    248   * before the manifest, so the situation of having to undo a manifest due
    249   * to document.write() never arises. The reason why a parser
    250   * thread-discovered manifest gets loaded via the speculative load queue
    251   * as opposed to tree operation queue is that the manifest must get
    252   * processed before any actual speculative loads such as scripts. Thus,
    253   * manifests seen by the parser thread have to maintain the queue order
    254   * relative to true speculative loads. See bug 541079.
    255   */
    256  inline void InitManifest(nsHtml5String aUrl) {
    257    MOZ_ASSERT(mOpCode == eSpeculativeLoadUninitialized,
    258               "Trying to reinitialize a speculative load!");
    259    mOpCode = eSpeculativeLoadManifest;
    260    aUrl.ToString(mUrlOrSizes);
    261  }
    262 
    263  /**
    264   * We communicate the encoding change via the speculative operation
    265   * queue in order to act upon it as soon as possible and so as not to
    266   * have speculative loads generated after an encoding change fail to
    267   * make use of the encoding change.
    268   */
    269  inline void InitSetDocumentCharset(NotNull<const Encoding*> aEncoding,
    270                                     int32_t aCharsetSource,
    271                                     bool aCommitEncodingSpeculation) {
    272    MOZ_ASSERT(mOpCode == eSpeculativeLoadUninitialized,
    273               "Trying to reinitialize a speculative load!");
    274    mOpCode = eSpeculativeLoadSetDocumentCharset;
    275    mCharsetOrSrcset.~nsString();
    276    mEncoding = aEncoding;
    277    mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity.Assign(
    278        (char16_t)aCharsetSource);
    279    mCommitEncodingSpeculation = aCommitEncodingSpeculation;
    280  }
    281 
    282  inline void InitMaybeComplainAboutCharset(const char* aMsgId, bool aError,
    283                                            int32_t aLineNumber) {
    284    MOZ_ASSERT(mOpCode == eSpeculativeLoadUninitialized,
    285               "Trying to reinitialize a speculative load!");
    286    mOpCode = eSpeculativeLoadMaybeComplainAboutCharset;
    287    mCharsetOrSrcset.~nsString();
    288    mMsgId = aMsgId;
    289    mIsError = aError;
    290    // Transport a 32-bit integer as two 16-bit code units of a string
    291    // in order to avoid adding an integer field to the object.
    292    // See https://bugzilla.mozilla.org/show_bug.cgi?id=1733043 for a better
    293    // eventual approach.
    294    char16_t high = (char16_t)(((uint32_t)aLineNumber) >> 16);
    295    char16_t low = (char16_t)(((uint32_t)aLineNumber) & 0xFFFF);
    296    mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity.Assign(high);
    297    mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity.Append(low);
    298  }
    299 
    300  /**
    301   * Speculative document mode setting isn't really speculative. Once it
    302   * happens, we are committed to it. However, this information needs to
    303   * travel in the speculation queue in order to have this information
    304   * available before parsing the speculatively loaded style sheets.
    305   */
    306  inline void InitSetDocumentMode(nsHtml5DocumentMode aMode) {
    307    MOZ_ASSERT(mOpCode == eSpeculativeLoadUninitialized,
    308               "Trying to reinitialize a speculative load!");
    309    mOpCode = eSpeculativeLoadSetDocumentMode;
    310    mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity.Assign(
    311        (char16_t)aMode);
    312  }
    313 
    314  inline void InitPreconnect(nsHtml5String aUrl, nsHtml5String aCrossOrigin) {
    315    MOZ_ASSERT(mOpCode == eSpeculativeLoadUninitialized,
    316               "Trying to reinitialize a speculative load!");
    317    mOpCode = eSpeculativeLoadPreconnect;
    318    aUrl.ToString(mUrlOrSizes);
    319    aCrossOrigin.ToString(mCrossOrigin);
    320  }
    321 
    322  void Perform(nsHtml5TreeOpExecutor* aExecutor);
    323 
    324 private:
    325  nsHtml5SpeculativeLoad(const nsHtml5SpeculativeLoad&) = delete;
    326  nsHtml5SpeculativeLoad& operator=(const nsHtml5SpeculativeLoad&) = delete;
    327 
    328  eHtml5SpeculativeLoad mOpCode;
    329 
    330  /**
    331   * Whether the refering element has async attribute.
    332   */
    333  bool mIsAsync;
    334 
    335  /**
    336   * Whether the refering element has defer attribute.
    337   */
    338  bool mIsDefer;
    339 
    340  /**
    341   * True if and only if this is a speculative load initiated by <link
    342   * rel="preload"> or <link rel="modulepreload"> tag encounter.  Passed to the
    343   * handling loader as an indication to raise the priority.
    344   */
    345  bool mIsLinkPreload;
    346 
    347  /**
    348   * Whether the charset complaint is an error.
    349   */
    350  bool mIsError;
    351 
    352  /**
    353   * Whether setting document encoding involves also committing to an encoding
    354   * speculation.
    355   */
    356  bool mCommitEncodingSpeculation;
    357 
    358  /* If mOpCode is eSpeculativeLoadPictureSource, this is the value of the
    359   * "sizes" attribute. If the attribute is not set, this will be a void
    360   * string. Otherwise it empty or the value of the url.
    361   */
    362  nsString mUrlOrSizes;
    363  /**
    364   * If mOpCode is eSpeculativeLoadScript[FromHead], this is the value of the
    365   * "integrity" attribute. If the attribute is not set, this will be a void
    366   * string. Otherwise it is empty or the value of the referrer policy.
    367   */
    368  nsString mReferrerPolicyOrIntegrity;
    369  /**
    370   * If mOpCode is eSpeculativeLoadStyle or eSpeculativeLoadScript[FromHead]
    371   * then this is the value of the "charset" attribute. For
    372   * eSpeculativeLoadSetDocumentCharset it is the charset that the
    373   * document's charset is being set to. If mOpCode is eSpeculativeLoadImage
    374   * or eSpeculativeLoadPictureSource, this is the value of the "srcset"
    375   * attribute. If the attribute is not set, this will be a void string.
    376   * Otherwise it's empty.
    377   * For eSpeculativeLoadMaybeComplainAboutCharset mMsgId is used.
    378   */
    379  union {
    380    nsString mCharsetOrSrcset;
    381    const Encoding* mEncoding;
    382    const char* mMsgId;
    383  };
    384  /**
    385   * If mOpCode is eSpeculativeLoadSetDocumentCharset, this is a
    386   * one-character string whose single character's code point is to be
    387   * interpreted as a charset source integer. If mOpCode is
    388   * eSpeculativeLoadSetDocumentMode, this is a one-character string whose
    389   * single character's code point is to be interpreted as an
    390   * nsHtml5DocumentMode. If mOpCode is eSpeculativeLoadCSP, this is a meta
    391   * element's CSP value. If mOpCode is eSpeculativeLoadImage, this is the
    392   * value of the "sizes" attribute. If the attribute is not set, this will
    393   * be a void string. If mOpCode is eSpeculativeLoadStyle, this
    394   * is the value of the "integrity" attribute. If the attribute is not set,
    395   * this will be a void string. Otherwise, it is empty or the value of the type
    396   * attribute.
    397   */
    398  nsString mTypeOrCharsetSourceOrDocumentModeOrMetaCSPOrSizesOrIntegrity;
    399  /**
    400   * If mOpCode is eSpeculativeLoadImage or eSpeculativeLoadScript[FromHead]
    401   * or eSpeculativeLoadPreconnect or eSpeculativeLoadStyle this is the value of
    402   * the "crossorigin" attribute.  If the attribute is not set, this will be a
    403   * void string.
    404   */
    405  nsString mCrossOrigin;
    406  /**
    407   * If mOpCode is eSpeculativeLoadPictureSource or eSpeculativeLoadStyle or
    408   * Fetch or Image or Media or Script this is the value of the relevant "media"
    409   * attribute of the <link rel="preload"> or <link rel="stylesheet">. If the
    410   * attribute is not set, or the preload didn't originate from a <link>, this
    411   * will be a void string.
    412   */
    413  nsString mMedia;
    414  /**
    415   * If mOpCode is eSpeculativeLoadImage this represents the value of the "type"
    416   * attribute. If the attribute is not set, this will be a void string.
    417   * Otherwise, it is empty or the value of the "nonce" attribute.
    418   */
    419  nsString mNonceOrType;
    420  /**
    421   * If mOpCode is eSpeculativeLoadNoModuleScript[FromHead] or
    422   * eSpeculativeLoadScript[FromHead] this represents the value of the
    423   * "fetchpriority" attribute.
    424   */
    425  nsString mFetchPriority;
    426  /**
    427   * If mOpCode is eSpeculativeLoadScript[FromHead] this represents the value
    428   * of the "referrerpolicy" attribute. This field holds one of the values
    429   * (REFERRER_POLICY_*) defined in nsIHttpChannel.
    430   */
    431  mozilla::dom::ReferrerPolicy mScriptReferrerPolicy;
    432 };
    433 
    434 #endif  // nsHtml5SpeculativeLoad_h