tor-browser

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

document-rules.https.html (12079B)


      1 <!DOCTYPE html>
      2 <script src="/resources/testharness.js"></script>
      3 <script src="/resources/testharnessreport.js"></script>
      4 <script src="/common/utils.js"></script>
      5 <script src="/common/dispatcher/dispatcher.js"></script>
      6 <script src="../resources/utils.js"></script>
      7 <script src="resources/utils.sub.js"></script>
      8 <script src="/common/subset-tests-by-key.js"></script>
      9 
     10 <meta name="variant" content="?include=defaultPredicate">
     11 <meta name="variant" content="?include=hrefMatches">
     12 <meta name="variant" content="?include=and">
     13 <meta name="variant" content="?include=or">
     14 <meta name="variant" content="?include=not">
     15 <meta name="variant" content="?include=invalidPredicate">
     16 <meta name="variant" content="?include=linkInShadowTree">
     17 <meta name="variant" content="?include=linkHrefChanged">
     18 <meta name="variant" content="?include=newRuleSetAdded">
     19 <meta name="variant" content="?include=selectorMatches">
     20 <meta name="variant" content="?include=selectorMatchesScopingRoot">
     21 <meta name="variant" content="?include=selectorMatchesDisplayNone">
     22 <meta name="variant" content="?include=selectorMatchesDisplayLocked">
     23 <meta name="variant" content="?include=unslottedLink">
     24 <meta name="variant" content="?include=immediateMutation">
     25 <meta name="variant" content="?include=baseURLChangedBySameDocumentNavigation">
     26 <meta name="variant" content="?include=baseURLChangedByBaseElement">
     27 <meta name="variant" content="?include=linkToSelfFragment">
     28 
     29 <body>
     30 <script>
     31  setup(() => assertSpeculationRulesIsSupported());
     32 
     33  subsetTestByKey('defaultPredicate', promise_test, async t => {
     34    const url = getPrefetchUrl();
     35    addLink(url);
     36    insertDocumentRule();
     37    await new Promise(resolve => t.step_timeout(resolve, 2000));
     38 
     39    assert_equals(await isUrlPrefetched(url), 1);
     40  }, 'test document rule with no predicate');
     41 
     42  subsetTestByKey('hrefMatches', promise_test, async t => {
     43    insertDocumentRule({ href_matches: '*\\?uuid=*&foo=bar' });
     44 
     45    const url_1 = getPrefetchUrl({foo: 'bar'});
     46    addLink(url_1);
     47    const url_2 = getPrefetchUrl({foo: 'buzz'});
     48    addLink(url_2)
     49    await new Promise(resolve => t.step_timeout(resolve, 2000));
     50 
     51    assert_equals(await isUrlPrefetched(url_1), 1);
     52    assert_equals(await isUrlPrefetched(url_2), 0);
     53  }, 'test href_matches document rule');
     54 
     55  subsetTestByKey('and', promise_test, async t => {
     56    insertDocumentRule({
     57      'and': [
     58        { href_matches: '*\\?*foo=bar*' },
     59        { href_matches: '*\\?*fizz=buzz*' }]
     60    });
     61 
     62    const url_1 = getPrefetchUrl({foo: 'bar'});
     63    const url_2 = getPrefetchUrl({fizz: 'buzz'});
     64    const url_3 = getPrefetchUrl({foo: 'bar', fizz: 'buzz'});
     65    [url_1, url_2, url_3].forEach(url => addLink(url));
     66    await new Promise(resolve => t.step_timeout(resolve, 2000));
     67 
     68    assert_equals(await isUrlPrefetched(url_1), 0);
     69    assert_equals(await isUrlPrefetched(url_2), 0);
     70    assert_equals(await isUrlPrefetched(url_3), 1);
     71  }, 'test document rule with conjunction predicate');
     72 
     73  subsetTestByKey('or', promise_test, async t => {
     74    insertDocumentRule({
     75      'or': [
     76        { href_matches: '*\\?*foo=bar*' },
     77        { href_matches: '*\\?*fizz=buzz*' }]
     78    });
     79 
     80    const url_1 = getPrefetchUrl({ foo: 'buzz' });
     81    const url_2 = getPrefetchUrl({ fizz: 'buzz' });
     82    const url_3 = getPrefetchUrl({ foo: 'bar'});
     83    [url_1, url_2, url_3].forEach(url => addLink(url));
     84    await new Promise(resolve => t.step_timeout(resolve, 2000));
     85 
     86    assert_equals(await isUrlPrefetched(url_1), 0);
     87    assert_equals(await isUrlPrefetched(url_2), 1);
     88    assert_equals(await isUrlPrefetched(url_3), 1);
     89  }, 'test document rule with disjunction predicate');
     90 
     91  subsetTestByKey('not', promise_test, async t => {
     92    insertDocumentRule({ not: { href_matches: '*\\?uuid=*&foo=bar' } });
     93 
     94    const url_1 = getPrefetchUrl({foo: 'bar'});
     95    addLink(url_1);
     96    const url_2 = getPrefetchUrl({foo: 'buzz'});
     97    addLink(url_2)
     98    await new Promise(resolve => t.step_timeout(resolve, 2000));
     99 
    100    assert_equals(await isUrlPrefetched(url_1), 0);
    101    assert_equals(await isUrlPrefetched(url_2), 1);
    102  }, 'test document rule with negation predicate');
    103 
    104  subsetTestByKey('invalidPredicate', promise_test, async t => {
    105    const url = getPrefetchUrl();
    106    addLink(url);
    107    insertDocumentRule({invalid: 'predicate'});
    108    await new Promise(resolve => t.step_timeout(resolve, 2000));
    109 
    110    assert_equals(await isUrlPrefetched(url), 0);
    111  }, 'invalid predicate should not throw error or start prefetch');
    112 
    113  subsetTestByKey('linkInShadowTree', promise_test, async t => {
    114    insertDocumentRule();
    115 
    116    // Create shadow root.
    117    const shadowHost = document.createElement('div');
    118    document.body.appendChild(shadowHost);
    119    const shadowRoot = shadowHost.attachShadow({mode: 'open'});
    120 
    121    const url = getPrefetchUrl();
    122    addLink(url, shadowRoot);
    123    await new Promise(resolve => t.step_timeout(resolve, 2000));
    124 
    125    assert_equals(await isUrlPrefetched(url), 1);
    126  }, 'test that matching link in a shadow tree is prefetched');
    127 
    128  subsetTestByKey('linkHrefChanged', promise_test, async t => {
    129    insertDocumentRule({href_matches: "*\\?*foo=bar*"});
    130 
    131    const url = getPrefetchUrl();
    132    const link = addLink(url);
    133    await new Promise(resolve => t.step_timeout(resolve, 2000));
    134    assert_equals(await isUrlPrefetched(url), 0);
    135 
    136    const matching_url = getPrefetchUrl({foo: 'bar'});
    137    link.href = matching_url;
    138    await new Promise(resolve => t.step_timeout(resolve, 2000));
    139    assert_equals(await isUrlPrefetched(matching_url), 1);
    140  }, 'test that changing the href of an invalid link to a matching value triggers a prefetch');
    141 
    142  subsetTestByKey('newRuleSetAdded', promise_test, async t => {
    143    insertDocumentRule({href_matches: "*\\?*foo=bar*"});
    144    const url = getPrefetchUrl({fizz: "buzz"});
    145    addLink(url);
    146    await new Promise(resolve => t.step_timeout(resolve, 2000));
    147    assert_equals(await isUrlPrefetched(url), 0);
    148 
    149    insertDocumentRule({href_matches: "*\\?*fizz=buzz*"});
    150    await new Promise(resolve => t.step_timeout(resolve, 2000));
    151    assert_equals(await isUrlPrefetched(url), 1);
    152  }, 'test that adding a second rule set triggers prefetch');
    153 
    154  subsetTestByKey('selectorMatches', promise_test, async t => {
    155    insertDocumentRule({ selector_matches: 'a.important-link' });
    156 
    157    const url_1 = getPrefetchUrl({foo: 'bar'});
    158    const importantLink = addLink(url_1);
    159    importantLink.className = 'important-link';
    160    const url_2 = getPrefetchUrl({foo: 'buzz'});
    161    addLink(url_2)
    162    await new Promise(resolve => t.step_timeout(resolve, 2000));
    163 
    164    assert_equals(await isUrlPrefetched(url_1), 1);
    165    assert_equals(await isUrlPrefetched(url_2), 0);
    166  }, 'test selector_matches document rule');
    167 
    168  subsetTestByKey('selectorMatchesScopingRoot', promise_test, async t => {
    169    insertDocumentRule({ selector_matches: ':root > body > a' });
    170 
    171    const url_1 = getPrefetchUrl({ foo: 'bar' });
    172    addLink(url_1);
    173 
    174    const url_2 = getPrefetchUrl({ foo: 'buzz' });
    175    const extraContainer = document.createElement('div');
    176    document.body.appendChild(extraContainer);
    177    addLink(url_2, extraContainer);
    178 
    179    await new Promise(resolve => t.step_timeout(resolve, 2000));
    180 
    181    assert_equals(await isUrlPrefetched(url_1), 1);
    182    assert_equals(await isUrlPrefetched(url_2), 0);
    183  }, 'test selector_matches with :root');
    184 
    185  subsetTestByKey('selectorMatchesDisplayNone', promise_test, async t => {
    186    const style = document.createElement('style');
    187    style.innerText = ".important-section { display: none; }";
    188    document.head.appendChild(style);
    189    insertDocumentRule();
    190 
    191    const importantSection = document.createElement('div');
    192    importantSection.className = 'important-section';
    193    document.body.appendChild(importantSection);
    194    const url = getPrefetchUrl();
    195    addLink(url, importantSection);
    196 
    197    await new Promise(resolve => t.step_timeout(resolve, 2000));
    198    assert_equals(await isUrlPrefetched(url), 0);
    199 
    200    style.remove();
    201    await new Promise(resolve => t.step_timeout(resolve, 2000));
    202    assert_equals(await isUrlPrefetched(url), 1);
    203  }, 'test selector_matches with link inside display:none container');
    204 
    205  subsetTestByKey('selectorMatchesDisplayLocked', promise_test, async t => {
    206    const style = document.createElement('style');
    207    style.innerText = ".important-section { content-visibility: hidden; }";
    208    document.head.appendChild(style);
    209    insertDocumentRule({ selector_matches: '.important-section a' });
    210 
    211    const importantSection = document.createElement('div');
    212    importantSection.className = 'important-section';
    213    document.body.appendChild(importantSection);
    214    const url = getPrefetchUrl();
    215    addLink(url, importantSection);
    216 
    217    await new Promise(resolve => t.step_timeout(resolve, 2000));
    218    assert_equals(await isUrlPrefetched(url), 0);
    219 
    220    style.remove();
    221    await new Promise(resolve => t.step_timeout(resolve, 2000));
    222    assert_equals(await isUrlPrefetched(url), 1);
    223  }, 'test selector_matches with link inside display locked container');
    224 
    225  subsetTestByKey('unslottedLink', promise_test, async t => {
    226    insertDocumentRule();
    227 
    228    // Create shadow root.
    229    const shadowHost = document.createElement('div');
    230    document.body.appendChild(shadowHost);
    231    const shadowRoot = shadowHost.attachShadow({ mode: 'open' });
    232 
    233    // Add unslotted link.
    234    const url = getPrefetchUrl();
    235    addLink(url, shadowHost);
    236 
    237    await new Promise(resolve => t.step_timeout(resolve, 2000));
    238    assert_equals(await isUrlPrefetched(url), 0);
    239  }, 'test that unslotted link never matches document rule');
    240 
    241  subsetTestByKey('immediateMutation', promise_test, async t => {
    242    // Add a link and allow it to get its style computed.
    243    // (Double RAF lets this happen normally.)
    244    const url = getPrefetchUrl();
    245    const link = addLink(url, document.body);
    246    await new Promise(resolve => requestAnimationFrame(() => requestAnimationFrame(() => resolve())));
    247 
    248    // Add a document rule and then immediately change the DOM to make it match.
    249    insertDocumentRule({ selector_matches: '.late-class *' });
    250    document.body.className = 'late-class';
    251 
    252    await new Promise(resolve => t.step_timeout(resolve, 2000));
    253    assert_equals(await isUrlPrefetched(url), 1);
    254  }, 'test that selector_matches predicates respect changes immediately');
    255 
    256  const baseURLChangedTestFixture = (testName, modifyBaseURLFunc) => {
    257    return subsetTestByKey(testName, promise_test, async t => {
    258      const url = getPrefetchUrl();
    259      const link = addLink(url);
    260      const url_pattern_string = `prefetch.py${url.search}`;
    261 
    262      // Insert a document rule with a url pattern predicate that uses a
    263      // relative URL which will not match with |url|, due to |document.baseURI|
    264      // being different from |url|'s path.
    265      assert_false((new URLPattern(url_pattern_string, document.baseURI)).test(url));
    266      insertDocumentRule({ href_matches: url_pattern_string });
    267      await new Promise(resolve => t.step_timeout(resolve, 2000));
    268      assert_equals(await isUrlPrefetched(url), 0);
    269 
    270      // Change the baseURL of the document to |url|. |url| should now be
    271      // prefetched.
    272      modifyBaseURLFunc(url);
    273      assert_true((new URLPattern(url_pattern_string, document.baseURI)).test(url));
    274      await new Promise(resolve => t.step_timeout(resolve, 2000));
    275      assert_equals(await isUrlPrefetched(url), 1);
    276    });
    277  }
    278 
    279  baseURLChangedTestFixture('baseURLChangedBySameDocumentNavigation', url => {
    280    history.pushState({}, "", url);
    281  });
    282 
    283  baseURLChangedTestFixture('baseURLChangedByBaseElement', url => {
    284    const base = document.createElement('base');
    285    base.href = url;
    286    document.head.appendChild(base);
    287  });
    288 
    289  subsetTestByKey('linkToSelfFragment', promise_test, async t => {
    290    const url = getPrefetchUrl();
    291    history.pushState({}, "", url);
    292    addLink(new URL('#fragment', url));
    293    insertDocumentRule();
    294    await new Promise(resolve => t.step_timeout(resolve, 2000));
    295    assert_equals(await isUrlPrefetched(url), 0);
    296  }, 'test that a fragment link to the current document does not prefetch');
    297 
    298 </script>
    299 </body>