tor-browser

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

test_CrossSiteXHR.html (56651B)


      1 <!DOCTYPE HTML>
      2 <html>
      3 <head>
      4  <META HTTP-EQUIV="Content-Type" CONTENT="text/html; charset=utf-8">
      5  <title>Test for Cross Site XMLHttpRequest</title>
      6  <script src="/tests/SimpleTest/SimpleTest.js"></script>
      7  <link rel="stylesheet" type="text/css" href="/tests/SimpleTest/test.css" />
      8 </head>
      9 <body onload="initTest()">
     10 <p id="display">
     11 <iframe id=loader></iframe>
     12 </p>
     13 <div id="content" style="display: none">
     14 
     15 </div>
     16 <pre id="test">
     17 <script class="testbody" type="application/javascript">
     18 
     19 const runPreflightTests = 1;
     20 const runCookieTests = 1;
     21 const runRedirectTests = 1;
     22 
     23 var gen;
     24 
     25 function initTest() {
     26  SimpleTest.waitForExplicitFinish();
     27  // Allow all cookies, then do the actual test initialization
     28  SpecialPowers.pushPrefEnv({
     29    "set": [
     30      ["network.cookie.cookieBehavior", 0],
     31      // Bug 1617611: Fix all the tests broken by "cookies SameSite=lax by default"
     32      ["network.cookie.sameSite.laxByDefault", false],
     33      ["network.cors_preflight.authorization_covered_by_wildcard", false],
     34   ]
     35  }, initTestCallback);
     36 }
     37 
     38 function initTestCallback() {
     39  window.addEventListener("message", function(e) {
     40    gen.next(e.data);
     41  });
     42 
     43  gen = runTest();
     44 
     45  gen.next()
     46 }
     47 
     48 async function clearCORSPreflightCacheTest() {
     49  // need to be on the parent process to access cors-preflight-cache service to:
     50  // send the CORS preflight cache length to the content process (before clearing)
     51  // clear the CORS preflight cache
     52  // and send the cache length again (after clearing)
     53  let script = SpecialPowers.loadChromeScript(function() {
     54    addMessageListener("start", function(principal) {
     55      try {
     56        let preflightCache = Cc["@mozilla.org/network/cors-preflight-cache;1"]
     57                                .getService(Ci.nsICORSPreflightCache);
     58        let entries = preflightCache.getEntries(principal);
     59        sendAsyncMessage("before", entries.length);
     60 
     61        for (let entry of entries) {
     62          preflightCache.clearEntry(entry);
     63        }
     64 
     65        let afterEntries = preflightCache.getEntries(principal);
     66        sendAsyncMessage("after", afterEntries.length);
     67      } catch (e) {
     68        console.error("Failed to get or clear the CORS preflight cache", e);
     69        sendAsyncMessage("before", -1);
     70        sendAsyncMessage("after", -1);
     71      }
     72    });
     73  });
     74 
     75  // document.location.origin varies depending on --enable-xorigin-tests:
     76  // .com or .org
     77  // we pass the "opposite" url to the parent process (as principal)
     78  let url = (document.location.origin == "https://example.org") ?
     79      "https://example.com" : "https://example.org";
     80  let oa = SpecialPowers.wrap(document).nodePrincipal.originAttributes;
     81  let principal = SpecialPowers.Services.scriptSecurityManager
     82      .createContentPrincipal(SpecialPowers.Services.io.newURI(url), oa);
     83  script.sendAsyncMessage("start", principal);
     84 
     85  // on the content process:
     86  // assert on the expected CORS preflight cache sizes, before and after
     87  await script.promiseOneMessage("before").then(val => {
     88    // This check depends on the number of preflight cache items created
     89    // by other tests in this file.
     90    // For our purposes here, it is important only that the value is valid and
     91    // indicating existing entries in the CORS preflight cache (positive values)
     92    ok(val > 0, "CORS preflight cache size before clearing as expected");
     93  });
     94  await script.promiseOneMessage("after").then(val => {
     95    is(val, 0, "CORS preflight cache empty after clearing");
     96  });
     97 
     98  SimpleTest.finish();
     99 }
    100 
    101 // eslint-disable-next-line complexity
    102 function* runTest() {
    103  var loader = document.getElementById('loader');
    104  var loaderWindow = loader.contentWindow;
    105  loader.onload = function () { gen.next() };
    106 
    107  // Test preflight-less requests
    108  basePath = "/tests/dom/security/test/cors/file_CrossSiteXHR_server.sjs?"
    109  base = self.location.origin;
    110  baseHost = self.location.host;
    111  baseURL = base + basePath;
    112 
    113  // Test preflighted requests
    114  origin = (base == "https://example.com") ? "https://example.org" : "https://example.com";
    115  originHost = (baseHost == "example.com") ? "example.org" : "example.com";
    116  loader.src = origin + "/tests/dom/security/test/cors/file_CrossSiteXHR_inner.html";
    117  yield undefined;
    118 
    119  tests =     [// Plain request
    120               { pass: 1,
    121                 method: "GET",
    122                 noAllowPreflight: 1,
    123               },
    124 
    125               // undefined username
    126               { pass: 1,
    127                 method: "GET",
    128                 noAllowPreflight: 1,
    129                 username: undefined
    130               },
    131 
    132               // undefined username and password
    133               { pass: 1,
    134                 method: "GET",
    135                 noAllowPreflight: 1,
    136                 username: undefined,
    137                 password: undefined
    138               },
    139 
    140               // nonempty username
    141               { pass: 1,
    142                 method: "GET",
    143                 noAllowPreflight: 1,
    144                 username: "user",
    145               },
    146 
    147               // nonempty password
    148               { pass: 1,
    149                 method: "GET",
    150                 noAllowPreflight: 1,
    151                 password: "password",
    152               },
    153 
    154               // Default allowed headers
    155               { pass: 1,
    156                 method: "GET",
    157                 headers: { "Content-Type": "text/plain",
    158                            "Accept": "foo/bar",
    159                            "Accept-Language": "sv-SE" },
    160                 noAllowPreflight: 1,
    161               },
    162               { pass: 0,
    163                 method: "GET",
    164                 headers: { "Content-Type": "foo/bar",
    165                            "Accept": "foo/bar",
    166                            "Accept-Language": "sv-SE" },
    167                 noAllowPreflight: 1,
    168               },
    169               { pass: 0,
    170                 method: "GET",
    171                 headers: { "Content-Type": "foo/bar, text/plain" },
    172                 noAllowPreflight: 1,
    173               },
    174               { pass: 0,
    175                 method: "GET",
    176                 headers: { "Content-Type": "foo/bar, text/plain, garbage" },
    177                 noAllowPreflight: 1,
    178               },
    179 
    180               // Custom headers
    181               { pass: 1,
    182                 method: "GET",
    183                 headers: { "x-my-header": "myValue" },
    184                 allowHeaders: "x-my-header",
    185               },
    186               { pass: 1,
    187                 method: "GET",
    188                 headers: { "x-my-header": "myValue" },
    189                 allowHeaders: "X-My-Header",
    190               },
    191               { pass: 1,
    192                 method: "GET",
    193                 headers: { "x-my-header": "myValue",
    194                            "long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header": "secondValue" },
    195                 allowHeaders: "x-my-header, long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header-long-header",
    196               },
    197               { pass: 1,
    198                 method: "GET",
    199                 headers: { "x-my%-header": "myValue" },
    200                 allowHeaders: "x-my%-header",
    201               },
    202               { pass: 0,
    203                 method: "GET",
    204                 headers: { "x-my-header": "myValue" },
    205               },
    206               { pass: 0,
    207                 method: "GET",
    208                 headers: { "x-my-header": "" },
    209               },
    210               { pass: 0,
    211                 method: "GET",
    212                 headers: { "x-my-header": "myValue" },
    213                 allowHeaders: "",
    214               },
    215               { pass: 0,
    216                 method: "GET",
    217                 headers: { "x-my-header": "myValue" },
    218                 allowHeaders: "y-my-header",
    219               },
    220               { pass: 0,
    221                 method: "GET",
    222                 headers: { "x-my-header": "myValue" },
    223                 allowHeaders: "x-my-header y-my-header",
    224               },
    225               { pass: 0,
    226                 method: "GET",
    227                 headers: { "x-my-header": "myValue" },
    228                 allowHeaders: "x-my-header, y-my-header z",
    229               },
    230               { pass: 0,
    231                 method: "GET",
    232                 headers: { "x-my-header": "myValue" },
    233                 allowHeaders: "x-my-header, y-my-he(ader",
    234               },
    235               { pass: 0,
    236                 method: "GET",
    237                 headers: { "myheader": "" },
    238                 allowMethods: "myheader",
    239               },
    240               { pass: 1,
    241                 method: "GET",
    242                 headers: { "User-Agent": "myValue" },
    243                 allowHeaders: "User-Agent",
    244               },
    245               { pass: 0,
    246                 method: "GET",
    247                 headers: { "User-Agent": "myValue" },
    248               },
    249 
    250               // Multiple custom headers
    251               { pass: 1,
    252                 method: "GET",
    253                 headers: { "x-my-header": "myValue",
    254                            "second-header": "secondValue",
    255                            "third-header": "thirdValue" },
    256                 allowHeaders: "x-my-header, second-header, third-header",
    257               },
    258               { pass: 1,
    259                 method: "GET",
    260                 headers: { "x-my-header": "myValue",
    261                            "second-header": "secondValue",
    262                            "third-header": "thirdValue" },
    263                 allowHeaders: "x-my-header,second-header,third-header",
    264               },
    265               { pass: 1,
    266                 method: "GET",
    267                 headers: { "x-my-header": "myValue",
    268                            "second-header": "secondValue",
    269                            "third-header": "thirdValue" },
    270                 allowHeaders: "x-my-header ,second-header ,third-header",
    271               },
    272               { pass: 1,
    273                 method: "GET",
    274                 headers: { "x-my-header": "myValue",
    275                            "second-header": "secondValue",
    276                            "third-header": "thirdValue" },
    277                 allowHeaders: "x-my-header , second-header , third-header",
    278               },
    279               { pass: 1,
    280                 method: "GET",
    281                 headers: { "x-my-header": "myValue",
    282                            "second-header": "secondValue" },
    283                 allowHeaders: ",  x-my-header, , ,, second-header, ,   ",
    284               },
    285               { pass: 1,
    286                 method: "GET",
    287                 headers: { "x-my-header": "myValue",
    288                            "second-header": "secondValue" },
    289                 allowHeaders: "x-my-header, second-header, unused-header",
    290               },
    291               { pass: 0,
    292                 method: "GET",
    293                 headers: { "x-my-header": "myValue",
    294                            "y-my-header": "secondValue" },
    295                 allowHeaders: "x-my-header",
    296               },
    297               { pass: 0,
    298                 method: "GET",
    299                 headers: { "x-my-header": "",
    300                            "y-my-header": "" },
    301                 allowHeaders: "x-my-header",
    302               },
    303 
    304               // HEAD requests
    305               { pass: 1,
    306                 method: "HEAD",
    307                 noAllowPreflight: 1,
    308               },
    309 
    310               // HEAD with safe headers
    311               { pass: 1,
    312                 method: "HEAD",
    313                 headers: { "Content-Type": "text/plain",
    314                            "Accept": "foo/bar",
    315                            "Accept-Language": "sv-SE" },
    316                 noAllowPreflight: 1,
    317               },
    318               { pass: 0,
    319                 method: "HEAD",
    320                 headers: { "Content-Type": "foo/bar",
    321                            "Accept": "foo/bar",
    322                            "Accept-Language": "sv-SE" },
    323                 noAllowPreflight: 1,
    324               },
    325               { pass: 0,
    326                 method: "HEAD",
    327                 headers: { "Content-Type": "foo/bar, text/plain" },
    328                 noAllowPreflight: 1,
    329               },
    330               { pass: 0,
    331                 method: "HEAD",
    332                 headers: { "Content-Type": "foo/bar, text/plain, garbage" },
    333                 noAllowPreflight: 1,
    334               },
    335 
    336               // HEAD with custom headers
    337               { pass: 1,
    338                 method: "HEAD",
    339                 headers: { "x-my-header": "myValue" },
    340                 allowHeaders: "x-my-header",
    341               },
    342               { pass: 0,
    343                 method: "HEAD",
    344                 headers: { "x-my-header": "myValue" },
    345               },
    346               { pass: 0,
    347                 method: "HEAD",
    348                 headers: { "x-my-header": "myValue" },
    349                 allowHeaders: "",
    350               },
    351               { pass: 0,
    352                 method: "HEAD",
    353                 headers: { "x-my-header": "myValue" },
    354                 allowHeaders: "y-my-header",
    355               },
    356               { pass: 0,
    357                 method: "HEAD",
    358                 headers: { "x-my-header": "myValue" },
    359                 allowHeaders: "x-my-header y-my-header",
    360               },
    361 
    362               // POST tests
    363               { pass: 1,
    364                 method: "POST",
    365                 body: "hi there",
    366                 noAllowPreflight: 1,
    367               },
    368               { pass: 1,
    369                 method: "POST",
    370               },
    371               { pass: 1,
    372                 method: "POST",
    373                 noAllowPreflight: 1,
    374               },
    375 
    376               // POST with standard headers
    377               { pass: 1,
    378                 method: "POST",
    379                 body: "hi there",
    380                 headers: { "Content-Type": "text/plain" },
    381                 noAllowPreflight: 1,
    382               },
    383               { pass: 1,
    384                 method: "POST",
    385                 body: "hi there",
    386                 headers: { "Content-Type": "multipart/form-data" },
    387                 noAllowPreflight: 1,
    388               },
    389               { pass: 1,
    390                 method: "POST",
    391                 body: "hi there",
    392                 headers: { "Content-Type": "application/x-www-form-urlencoded" },
    393                 noAllowPreflight: 1,
    394               },
    395               { pass: 0,
    396                 method: "POST",
    397                 body: "hi there",
    398                 headers: { "Content-Type": "foo/bar" },
    399               },
    400               { pass: 0,
    401                 method: "POST",
    402                 headers: { "Content-Type": "foo/bar" },
    403               },
    404               { pass: 1,
    405                 method: "POST",
    406                 body: "hi there",
    407                 headers: { "Content-Type": "text/plain",
    408                            "Accept": "foo/bar",
    409                            "Accept-Language": "sv-SE" },
    410                 noAllowPreflight: 1,
    411               },
    412               { pass: 0,
    413                 method: "POST",
    414                 body: "hi there",
    415                 headers: { "Content-Type": "foo/bar, text/plain" },
    416                 noAllowPreflight: 1,
    417               },
    418               { pass: 0,
    419                 method: "POST",
    420                 body: "hi there",
    421                 headers: { "Content-Type": "foo/bar, text/plain, garbage" },
    422                 noAllowPreflight: 1,
    423               },
    424 
    425               // POST with custom headers
    426               { pass: 1,
    427                 method: "POST",
    428                 body: "hi there",
    429                 headers: { "Accept": "foo/bar",
    430                            "Accept-Language": "sv-SE",
    431                            "x-my-header": "myValue" },
    432                 allowHeaders: "x-my-header",
    433               },
    434               { pass: 1,
    435                 method: "POST",
    436                 headers: { "Content-Type": "text/plain",
    437                            "x-my-header": "myValue" },
    438                 allowHeaders: "x-my-header",
    439               },
    440               { pass: 1,
    441                 method: "POST",
    442                 body: "hi there",
    443                 headers: { "Content-Type": "text/plain",
    444                            "x-my-header": "myValue" },
    445                 allowHeaders: "x-my-header",
    446               },
    447               { pass: 1,
    448                 method: "POST",
    449                 body: "hi there",
    450                 headers: { "Content-Type": "foo/bar",
    451                            "x-my-header": "myValue" },
    452                 allowHeaders: "x-my-header, content-type",
    453               },
    454               { pass: 0,
    455                 method: "POST",
    456                 body: "hi there",
    457                 headers: { "Content-Type": "foo/bar" },
    458                 noAllowPreflight: 1,
    459               },
    460               { pass: 0,
    461                 method: "POST",
    462                 body: "hi there",
    463                 headers: { "Content-Type": "foo/bar",
    464                            "x-my-header": "myValue" },
    465                 allowHeaders: "x-my-header",
    466               },
    467               { pass: 1,
    468                 method: "POST",
    469                 headers: { "x-my-header": "myValue" },
    470                 allowHeaders: "x-my-header",
    471               },
    472               { pass: 1,
    473                 method: "POST",
    474                 body: "hi there",
    475                 headers: { "x-my-header": "myValue" },
    476                 allowHeaders: "x-my-header, $_%",
    477               },
    478 
    479               // Test cases for "Access-Control-Allow-Headers" containing "*".
    480               { pass: 1,
    481                 method: "POST",
    482                 body: "hi there",
    483                 headers: { "x-my-header": "myValue" },
    484                 allowHeaders: "*",
    485               },
    486               { pass: 1,
    487                 method: "POST",
    488                 body: "hi there",
    489                 headers: { "x-my-header": "myValue",
    490                            "Authorization": "12345" },
    491                 allowHeaders: "*, Authorization",
    492               },
    493               { pass: 1,
    494                 method: "POST",
    495                 body: "hi there",
    496                 headers: { "x-my-header": "myValue",
    497                            "Authorization": "12345" },
    498                 allowHeaders: "Authorization, *",
    499               },
    500               { pass: 0,
    501                 method: "POST",
    502                 body: "hi there",
    503                 headers: { "x-my-header": "myValue",
    504                            "Authorization": "12345" },
    505                 allowHeaders: "*",
    506               },
    507               { pass: 0,
    508                 method: "POST",
    509                 body: "hi there",
    510                 headers: { "x-my-header": "myValue",
    511                            "Authorization": "12345" },
    512                 allowHeaders: "x-my-header",
    513               },
    514               { pass: 1,
    515                 method: "POST",
    516                 body: "hi there",
    517                 headers: { "*": "myValue" },
    518                 allowHeaders: "*",
    519                 withCred: 1,
    520                 allowCred: 1,
    521               },
    522               { pass: 0,
    523                 method: "POST",
    524                 body: "hi there",
    525                 headers: { "x-my-header": "myValue" },
    526                 allowHeaders: "*",
    527                 withCred: 1,
    528                 allowCred: 1,
    529               },
    530 
    531               // Other methods
    532               { pass: 1,
    533                 method: "DELETE",
    534                 allowMethods: "DELETE",
    535               },
    536               { pass: 0,
    537                 method: "DELETE",
    538                 allowHeaders: "DELETE",
    539               },
    540               { pass: 0,
    541                 method: "DELETE",
    542               },
    543               { pass: 0,
    544                 method: "DELETE",
    545                 allowMethods: "",
    546               },
    547               { pass: 1,
    548                 method: "DELETE",
    549                 allowMethods: "POST, PUT, DELETE",
    550               },
    551               { pass: 1,
    552                 method: "DELETE",
    553                 allowMethods: "POST, DELETE, PUT",
    554               },
    555               { pass: 1,
    556                 method: "DELETE",
    557                 allowMethods: "DELETE, POST, PUT",
    558               },
    559               { pass: 1,
    560                 method: "DELETE",
    561                 allowMethods: "POST ,PUT ,DELETE",
    562               },
    563               { pass: 1,
    564                 method: "DELETE",
    565                 allowMethods: "POST,PUT,DELETE",
    566               },
    567               { pass: 1,
    568                 method: "DELETE",
    569                 allowMethods: "POST , PUT , DELETE",
    570               },
    571               { pass: 1,
    572                 method: "DELETE",
    573                 allowMethods: "  ,,  PUT ,,  ,    , DELETE  ,  ,",
    574               },
    575               { pass: 0,
    576                 method: "DELETE",
    577                 allowMethods: "PUT",
    578               },
    579               { pass: 0,
    580                 method: "DELETE",
    581                 allowMethods: "DELETEZ",
    582               },
    583               { pass: 0,
    584                 method: "DELETE",
    585                 allowMethods: "DELETE PUT",
    586               },
    587               { pass: 0,
    588                 method: "DELETE",
    589                 allowMethods: "DELETE, PUT Z",
    590               },
    591               { pass: 0,
    592                 method: "DELETE",
    593                 allowMethods: "DELETE, PU(T",
    594               },
    595               { pass: 0,
    596                 method: "DELETE",
    597                 allowMethods: "PUT DELETE",
    598               },
    599               { pass: 0,
    600                 method: "DELETE",
    601                 allowMethods: "PUT Z, DELETE",
    602               },
    603               { pass: 0,
    604                 method: "DELETE",
    605                 allowMethods: "PU(T, DELETE",
    606               },
    607               { pass: 0,
    608                 method: "MYMETHOD",
    609                 allowMethods: "myMethod",
    610               },
    611               { pass: 0,
    612                 method: "PUT",
    613                 allowMethods: "put",
    614               },
    615 
    616               // Progress events
    617               { pass: 1,
    618                 method: "POST",
    619                 body: "hi there",
    620                 headers: { "Content-Type": "text/plain" },
    621                 uploadProgress: "progress",
    622               },
    623               { pass: 0,
    624                 method: "POST",
    625                 body: "hi there",
    626                 headers: { "Content-Type": "text/plain" },
    627                 uploadProgress: "progress",
    628                 noAllowPreflight: 1,
    629               },
    630 
    631               // Status messages
    632               { pass: 1,
    633                 method: "GET",
    634                 noAllowPreflight: 1,
    635                 status: 404,
    636                 statusMessage: "nothin' here",
    637               },
    638               { pass: 1,
    639                 method: "GET",
    640                 noAllowPreflight: 1,
    641                 status: 401,
    642                 statusMessage: "no can do",
    643               },
    644               { pass: 1,
    645                 method: "POST",
    646                 body: "hi there",
    647                 headers: { "Content-Type": "foo/bar" },
    648                 allowHeaders: "content-type",
    649                 status: 500,
    650                 statusMessage: "server boo",
    651               },
    652               { pass: 1,
    653                 method: "GET",
    654                 noAllowPreflight: 1,
    655                 status: 200,
    656                 statusMessage: "Yes!!",
    657               },
    658               { pass: 0,
    659                 method: "GET",
    660                 headers: { "x-my-header": "header value" },
    661                 allowHeaders: "x-my-header",
    662                 preflightStatus: 400
    663               },
    664               { pass: 1,
    665                 method: "GET",
    666                 headers: { "x-my-header": "header value" },
    667                 allowHeaders: "x-my-header",
    668                 preflightStatus: 200
    669               },
    670               { pass: 1,
    671                 method: "GET",
    672                 headers: { "x-my-header": "header value" },
    673                 allowHeaders: "x-my-header",
    674                 preflightStatus: 204
    675               },
    676 
    677               // exposed headers
    678               { pass: 1,
    679                 method: "GET",
    680                 responseHeaders: { "x-my-header": "x header" },
    681                 exposeHeaders: "x-my-header",
    682                 expectedResponseHeaders: ["x-my-header"],
    683               },
    684               { pass: 0,
    685                 method: "GET",
    686                 origin: "https://invalid",
    687                 responseHeaders: { "x-my-header": "x header" },
    688                 exposeHeaders: "x-my-header",
    689                 expectedResponseHeaders: [],
    690               },
    691               { pass: 1,
    692                 method: "GET",
    693                 responseHeaders: { "x-my-header": "x header" },
    694                 expectedResponseHeaders: [],
    695               },
    696               { pass: 1,
    697                 method: "GET",
    698                 responseHeaders: { "x-my-header": "x header" },
    699                 exposeHeaders: "x-my-header y",
    700                 expectedResponseHeaders: [],
    701               },
    702               { pass: 1,
    703                 method: "GET",
    704                 responseHeaders: { "x-my-header": "x header" },
    705                 exposeHeaders: "y x-my-header",
    706                 expectedResponseHeaders: [],
    707               },
    708               { pass: 1,
    709                 method: "GET",
    710                 responseHeaders: { "x-my-header": "x header" },
    711                 exposeHeaders: "x-my-header, y-my-header z",
    712                 expectedResponseHeaders: [],
    713               },
    714               { pass: 1,
    715                 method: "GET",
    716                 responseHeaders: { "x-my-header": "x header" },
    717                 exposeHeaders: "x-my-header, y-my-hea(er",
    718                 expectedResponseHeaders: [],
    719               },
    720               { pass: 1,
    721                 method: "GET",
    722                 responseHeaders: { "x-my-header": "x header",
    723                                    "y-my-header": "y header" },
    724                 exposeHeaders: "  ,  ,,y-my-header,z-my-header,  ",
    725                 expectedResponseHeaders: ["y-my-header"],
    726               },
    727               { pass: 1,
    728                 method: "GET",
    729                 responseHeaders: { "Cache-Control": "cacheControl header",
    730                                    "Content-Language": "contentLanguage header",
    731                                    "Expires":"expires header",
    732                                    "Last-Modified":"lastModified header",
    733                                    "Pragma":"pragma header",
    734                                    "Unexpected":"unexpected header" },
    735                 expectedResponseHeaders: ["Cache-Control","Content-Language","Content-Type","Expires","Last-Modified","Pragma"],
    736               },
    737               // Check that sending a body in the OPTIONS response works
    738               { pass: 1,
    739                 method: "DELETE",
    740                 allowMethods: "DELETE",
    741                 preflightBody: "I'm a preflight response body",
    742               },
    743               ];
    744 
    745  if (!runPreflightTests) {
    746    tests = [];
    747  }
    748 
    749  for (test of tests) {
    750    var req = {
    751      url: baseURL + "allowOrigin=" + escape(test.origin || origin),
    752      method: test.method,
    753      headers: test.headers,
    754      uploadProgress: test.uploadProgress,
    755      body: test.body,
    756      responseHeaders: test.responseHeaders,
    757      withCred: test.withCred ? test.withCred : 0,
    758    };
    759 
    760    if (test.pass) {
    761       req.url += "&origin=" + escape(origin) +
    762                  "&requestMethod=" + test.method;
    763    }
    764 
    765    if ("username" in test) {
    766      req.username = test.username;
    767    }
    768 
    769    if ("password" in test) {
    770      req.password = test.password;
    771    }
    772 
    773    if (test.noAllowPreflight)
    774      req.url += "&noAllowPreflight";
    775 
    776    if (test.allowCred)
    777      req.url += "&allowCred";
    778 
    779    if (test.pass && "headers" in test) {
    780      function isUnsafeHeader(name) {
    781        lName = name.toLowerCase();
    782        return lName != "accept" &&
    783               lName != "accept-language" &&
    784               (lName != "content-type" ||
    785                !["text/plain",
    786                 "multipart/form-data",
    787                 "application/x-www-form-urlencoded"]
    788                   .includes(test.headers[name].toLowerCase()));
    789      }
    790      req.url += "&headers=" + escape(JSON.stringify(test.headers));
    791      reqHeaders =
    792        escape(Object.keys(test.headers)
    793               .filter(isUnsafeHeader)
    794               .map(s => s.toLowerCase())
    795               .sort()
    796               .join(","));
    797      req.url += reqHeaders ? "&requestHeaders=" + reqHeaders : "";
    798    }
    799    if ("allowHeaders" in test)
    800      req.url += "&allowHeaders=" + escape(test.allowHeaders);
    801    if ("allowMethods" in test)
    802      req.url += "&allowMethods=" + escape(test.allowMethods);
    803    if (test.body)
    804      req.url += "&body=" + escape(test.body);
    805    if (test.status) {
    806      req.url += "&status=" + test.status;
    807      req.url += "&statusMessage=" + escape(test.statusMessage);
    808    }
    809    if (test.preflightStatus)
    810      req.url += "&preflightStatus=" + test.preflightStatus;
    811    if (test.responseHeaders)
    812      req.url += "&responseHeaders=" + escape(JSON.stringify(test.responseHeaders));
    813    if (test.exposeHeaders)
    814      req.url += "&exposeHeaders=" + escape(test.exposeHeaders);
    815    if (test.preflightBody)
    816      req.url += "&preflightBody=" + escape(test.preflightBody);
    817 
    818    loaderWindow.postMessage(JSON.stringify(req), origin);
    819    res = JSON.parse(yield);
    820 
    821    if (test.pass) {
    822      is(res.didFail, false,
    823        "shouldn't have failed in test for " + JSON.stringify(test));
    824      if (test.status) {
    825        is(res.status, test.status, "wrong status in test for " + JSON.stringify(test));
    826        is(res.statusText, test.statusMessage, "wrong status text for " + JSON.stringify(test));
    827      }
    828      else {
    829        is(res.status, 200, "wrong status in test for " + JSON.stringify(test));
    830        is(res.statusText, "OK", "wrong status text for " + JSON.stringify(test));
    831      }
    832      if (test.method !== "HEAD") {
    833        is(res.responseXML, "<res>hello pass</res>",
    834           "wrong responseXML in test for " + JSON.stringify(test));
    835        is(res.responseText, "<res>hello pass</res>\n",
    836           "wrong responseText in test for " + JSON.stringify(test));
    837        is(res.events.join(","),
    838           "opening,rs1,sending,loadstart,rs2,rs3,rs4,load,loadend",
    839           "wrong responseText in test for " + JSON.stringify(test));
    840      }
    841      else {
    842        is(res.responseXML, null,
    843           "wrong responseXML in test for " + JSON.stringify(test));
    844        is(res.responseText, "",
    845           "wrong responseText in test for " + JSON.stringify(test));
    846        is(res.events.join(","),
    847           "opening,rs1,sending,loadstart,rs2,rs4,load,loadend",
    848           "wrong responseText in test for " + JSON.stringify(test));
    849      }
    850      if (test.responseHeaders) {
    851        for (header in test.responseHeaders) {
    852          if (!test.expectedResponseHeaders.includes(header)) {
    853            is(res.responseHeaders[header], null,
    854               "|xhr.getResponseHeader()|wrong response header (" + header + ") in test for " +
    855               JSON.stringify(test));
    856            is(res.allResponseHeaders[header], undefined,
    857              "|xhr.getAllResponseHeaderss()|wrong response header (" + header + ") in test for " +
    858              JSON.stringify(test));
    859          }
    860          else {
    861            is(res.responseHeaders[header], test.responseHeaders[header],
    862               "|xhr.getResponseHeader()|wrong response header (" + header + ") in test for " +
    863               JSON.stringify(test));
    864            is(res.allResponseHeaders[header.toLowerCase()], test.responseHeaders[header],
    865              "|xhr.getAllResponseHeaderss()|wrong response header (" + header + ") in test for " +
    866              JSON.stringify(test));
    867          }
    868        }
    869      }
    870    }
    871    else {
    872      is(res.didFail, true,
    873        "should have failed in test for " + JSON.stringify(test));
    874      is(res.status, 0, "wrong status in test for " + JSON.stringify(test));
    875      is(res.statusText, "", "wrong status text for " + JSON.stringify(test));
    876      is(res.responseXML, null,
    877         "wrong responseXML in test for " + JSON.stringify(test));
    878      is(res.responseText, "",
    879         "wrong responseText in test for " + JSON.stringify(test));
    880      if (!res.sendThrew) {
    881        is(res.events.join(","),
    882           "opening,rs1,sending,loadstart,rs4,error,loadend",
    883           "wrong events in test for " + JSON.stringify(test));
    884      }
    885      is(res.progressEvents, 0,
    886         "wrong events in test for " + JSON.stringify(test));
    887      if (test.responseHeaders) {
    888        for (header in test.responseHeaders) {
    889          is(res.responseHeaders[header], null,
    890             "wrong response header (" + header + ") in test for " +
    891             JSON.stringify(test));
    892        }
    893      }
    894    }
    895  }
    896 
    897  // Test cookie behavior
    898  tests = [{ pass: 1,
    899             method: "GET",
    900             withCred: 1,
    901             allowCred: 1,
    902           },
    903           { pass: 0,
    904             method: "GET",
    905             withCred: 1,
    906             allowCred: 0,
    907           },
    908           { pass: 0,
    909             method: "GET",
    910             withCred: 1,
    911             allowCred: 1,
    912             origin: "*",
    913           },
    914           { pass: 1,
    915             method: "GET",
    916             withCred: 0,
    917             allowCred: 1,
    918             origin: "*",
    919           },
    920           { pass: 1,
    921             method: "GET",
    922             setCookie: "a=1; Partitioned; Secure; SameSite=None",
    923             withCred: 1,
    924             allowCred: 1,
    925           },
    926           { pass: 1,
    927             method: "GET",
    928             cookie: "a=1",
    929             withCred: 1,
    930             allowCred: 1,
    931           },
    932           { pass: 1,
    933             method: "GET",
    934             noCookie: 1,
    935             withCred: 0,
    936             allowCred: 1,
    937           },
    938           { pass: 0,
    939             method: "GET",
    940             noCookie: 1,
    941             withCred: 1,
    942             allowCred: 1,
    943           },
    944           { pass: 1,
    945             method: "GET",
    946             setCookie: "a=2; Partitioned; Secure; SameSite=None",
    947             withCred: 0,
    948             allowCred: 1,
    949           },
    950           { pass: 1,
    951             method: "GET",
    952             cookie: "a=1",
    953             withCred: 1,
    954             allowCred: 1,
    955           },
    956           { pass: 1,
    957             method: "GET",
    958             setCookie: "a=2; Partitioned; Secure; SameSite=None",
    959             withCred: 1,
    960             allowCred: 1,
    961           },
    962           { pass: 1,
    963             method: "GET",
    964             cookie: "a=2",
    965             withCred: 1,
    966             allowCred: 1,
    967           },
    968           ];
    969 
    970  if (!runCookieTests) {
    971    tests = [];
    972  }
    973 
    974  for (test of tests) {
    975    req = {
    976      url: baseURL + "allowOrigin=" + escape(test.origin || origin),
    977      method: test.method,
    978      headers: test.headers,
    979      withCred: test.withCred,
    980    };
    981 
    982    if (test.allowCred)
    983      req.url += "&allowCred";
    984 
    985    if (test.setCookie)
    986      req.url += "&setCookie=" + escape(test.setCookie);
    987    if (test.cookie)
    988      req.url += "&cookie=" + escape(test.cookie);
    989    if (test.noCookie)
    990      req.url += "&noCookie";
    991 
    992    if ("allowHeaders" in test)
    993      req.url += "&allowHeaders=" + escape(test.allowHeaders);
    994    if ("allowMethods" in test)
    995      req.url += "&allowMethods=" + escape(test.allowMethods);
    996 
    997    loaderWindow.postMessage(JSON.stringify(req), origin);
    998 
    999    res = JSON.parse(yield);
   1000    if (test.pass) {
   1001      is(res.didFail, false,
   1002        "shouldn't have failed in test for " + JSON.stringify(test));
   1003      is(res.status, 200, "wrong status in test for " + JSON.stringify(test));
   1004      is(res.statusText, "OK", "wrong status text for " + JSON.stringify(test));
   1005      is(res.responseXML, "<res>hello pass</res>",
   1006         "wrong responseXML in test for " + JSON.stringify(test));
   1007      is(res.responseText, "<res>hello pass</res>\n",
   1008         "wrong responseText in test for " + JSON.stringify(test));
   1009      is(res.events.join(","),
   1010         "opening,rs1,sending,loadstart,rs2,rs3,rs4,load,loadend",
   1011         "wrong responseText in test for " + JSON.stringify(test));
   1012    }
   1013    else {
   1014      is(res.didFail, true,
   1015        "should have failed in test for " + JSON.stringify(test));
   1016      is(res.status, 0, "wrong status in test for " + JSON.stringify(test));
   1017      is(res.statusText, "", "wrong status text for " + JSON.stringify(test));
   1018      is(res.responseXML, null,
   1019         "wrong responseXML in test for " + JSON.stringify(test));
   1020      is(res.responseText, "",
   1021         "wrong responseText in test for " + JSON.stringify(test));
   1022      is(res.events.join(","),
   1023         "opening,rs1,sending,loadstart,rs4,error,loadend",
   1024         "wrong events in test for " + JSON.stringify(test));
   1025      is(res.progressEvents, 0,
   1026         "wrong events in test for " + JSON.stringify(test));
   1027    }
   1028  }
   1029 
   1030  // Make sure to clear cookies to avoid affecting other tests
   1031  document.cookie = "a=; partitioned; secure; samesite=none; path=/; expires=Thu, 01-Jan-1970 00:00:01 GMT"
   1032  is(document.cookie, "", "No cookies should be left over");
   1033 
   1034  var otherURL = "https://example.net";
   1035 
   1036  // Test redirects
   1037  tests = [{ pass: 1,
   1038             method: "GET",
   1039             hops: [{ server: otherURL,
   1040                      allowOrigin: origin
   1041                    },
   1042                    ],
   1043           },
   1044           { pass: 0,
   1045             method: "GET",
   1046             hops: [{ server:  otherURL,
   1047                      allowOrigin: origin
   1048                    },
   1049                    { server: origin,
   1050                      allowOrigin: origin
   1051                    },
   1052                    ],
   1053           },
   1054           { pass: 1,
   1055             method: "GET",
   1056             hops: [{ server:  otherURL,
   1057                      allowOrigin: origin
   1058                    },
   1059                    { server: origin,
   1060                      allowOrigin: "*"
   1061                    },
   1062                    ],
   1063           },
   1064           { pass: 0,
   1065             method: "GET",
   1066             hops: [{ server:  otherURL,
   1067                      allowOrigin: origin
   1068                    },
   1069                    { server: origin,
   1070                    },
   1071                    ],
   1072           },
   1073           { pass: 1,
   1074             method: "GET",
   1075             hops: [{ server: origin,
   1076                    },
   1077                    { server: origin,
   1078                    },
   1079                    { server:  otherURL,
   1080                      allowOrigin: origin
   1081                    },
   1082                    ],
   1083           },
   1084           { pass: 0,
   1085             method: "GET",
   1086             hops: [{ server: origin,
   1087                    },
   1088                    { server: origin,
   1089                    },
   1090                    { server: otherURL,
   1091                      allowOrigin: origin
   1092                    },
   1093                    { server: origin,
   1094                    },
   1095                    ],
   1096           },
   1097           { pass: 0,
   1098             method: "GET",
   1099             hops: [{ server: otherURL,
   1100                      allowOrigin: origin
   1101                    },
   1102                    { server: "https://test3." + originHost + ":443",
   1103                      allowOrigin: origin
   1104                    },
   1105                    { server: "https://sub2.test2." + originHost,
   1106                      allowOrigin: origin
   1107                    },
   1108                    { server: "https://sub1.test1." + originHost,
   1109                      allowOrigin: origin
   1110                    },
   1111                    ],
   1112           },
   1113           { pass: 0,
   1114             method: "GET",
   1115             hops: [{ server: otherURL,
   1116                      allowOrigin: origin
   1117                    },
   1118                    { server: "https://test3." + originHost + ":443",
   1119                      allowOrigin: origin
   1120                    },
   1121                    { server: "https://sub2.test2." + originHost,
   1122                      allowOrigin: "*"
   1123                    },
   1124                    { server: "https://sub1.test1." + originHost,
   1125                      allowOrigin: "*"
   1126                    },
   1127                    ],
   1128           },
   1129           { pass: 1,
   1130             method: "GET",
   1131             hops: [{ server: otherURL,
   1132                      allowOrigin: origin
   1133                    },
   1134                    { server: "https://test3." + originHost + ":443",
   1135                      allowOrigin: "*"
   1136                    },
   1137                    { server: "https://sub2.test2." + originHost,
   1138                      allowOrigin: "*"
   1139                    },
   1140                    { server: "https://sub1.test1." + originHost,
   1141                      allowOrigin: "*"
   1142                    },
   1143                    ],
   1144           },
   1145           { pass: 0,
   1146             method: "GET",
   1147             hops: [{ server: otherURL,
   1148                      allowOrigin: origin
   1149                    },
   1150                    { server: "https://test3." + originHost + ":443",
   1151                      allowOrigin: origin
   1152                    },
   1153                    { server: "https://sub2.test2." + originHost,
   1154                      allowOrigin: "x"
   1155                    },
   1156                    { server: "https://sub1.test1." + originHost,
   1157                      allowOrigin: origin
   1158                    },
   1159                    ],
   1160           },
   1161           { pass: 0,
   1162             method: "GET",
   1163             hops: [{ server: otherURL,
   1164                      allowOrigin: origin
   1165                    },
   1166                    { server: "https://test3." + originHost + ":443",
   1167                      allowOrigin: origin
   1168                    },
   1169                    { server: "https://sub2.test2." + originHost,
   1170                      allowOrigin: "*"
   1171                    },
   1172                    { server: "https://sub1.test1." + originHost,
   1173                      allowOrigin: origin
   1174                    },
   1175                    ],
   1176           },
   1177           { pass: 0,
   1178             method: "GET",
   1179             hops: [{ server: otherURL,
   1180                      allowOrigin: origin
   1181                    },
   1182                    { server: "https://test3." + originHost + ":443",
   1183                      allowOrigin: origin
   1184                    },
   1185                    { server: "https://sub2.test2." + originHost,
   1186                      allowOrigin: "*"
   1187                    },
   1188                    { server: "https://sub1.test1." + originHost },
   1189                    ],
   1190           },
   1191           { pass: 1,
   1192             method: "POST",
   1193             body: "hi there",
   1194             headers: { "Content-Type": "text/plain" },
   1195             hops: [{ server: origin,
   1196                    },
   1197                    { server: otherURL,
   1198                      allowOrigin: origin,
   1199                    },
   1200                    ],
   1201           },
   1202           { pass: 1,
   1203             method: "POST",
   1204             body: "hi there",
   1205             headers: { "Content-Type": "text/plain",
   1206                        "my-header": "myValue",
   1207                      },
   1208             hops: [{ server: origin,
   1209                    },
   1210                    { server: otherURL,
   1211                      allowOrigin: origin,
   1212                      allowHeaders: "my-header",
   1213                    },
   1214                    ],
   1215           },
   1216           { pass: 0,
   1217             method: "POST",
   1218             body: "hi there",
   1219             headers: { "Content-Type": "text/plain",
   1220                        "my-header": "myValue",
   1221                      },
   1222             hops: [{ server: origin,
   1223                    },
   1224                    { server: otherURL,
   1225                      allowOrigin: origin,
   1226                      allowHeaders: "my-header",
   1227                    },
   1228                    { server: "https://sub1.test1." + originHost,
   1229                      allowOrigin: origin,
   1230                      allowHeaders: "my-header",
   1231                    },
   1232                    ],
   1233           },
   1234           { pass: 1,
   1235             method: "POST",
   1236             body: "hi there",
   1237             headers: { "Content-Type": "text/plain",
   1238                        "my-header": "myValue",
   1239                      },
   1240             hops: [{ server: origin,
   1241                    },
   1242                    { server: otherURL,
   1243                      allowOrigin: origin,
   1244                      allowHeaders: "my-header",
   1245                    },
   1246                    { server: "https://sub1.test1." + originHost,
   1247                      allowOrigin: "*",
   1248                      allowHeaders: "my-header",
   1249                    },
   1250                    ],
   1251           },
   1252           { pass: 1,
   1253             method: "POST",
   1254             body: "hi there",
   1255             headers: { "Content-Type": "text/plain",
   1256                        "my-header": "myValue",
   1257                      },
   1258             hops: [{ server: origin,
   1259                    },
   1260                    { server: otherURL,
   1261                      allowOrigin: origin,
   1262                      allowHeaders: "my-header",
   1263                    },
   1264                    { server: otherURL,
   1265                      allowOrigin: origin,
   1266                      allowHeaders: "my-header",
   1267                    },
   1268                    ],
   1269           },
   1270           { pass: 0,
   1271             method: "POST",
   1272             body: "hi there",
   1273             headers: { "Content-Type": "text/plain",
   1274                        "my-header": "myValue",
   1275                      },
   1276             hops: [{ server: origin,
   1277                    },
   1278                    { server: otherURL,
   1279                      allowOrigin: origin,
   1280                      allowHeaders: "my-header",
   1281                    },
   1282                    { server: origin,
   1283                      allowOrigin: origin,
   1284                      allowHeaders: "my-header",
   1285                    },
   1286                    ],
   1287           },
   1288           { pass: 0,
   1289             method: "POST",
   1290             body: "hi there",
   1291             headers: { "Content-Type": "text/plain",
   1292                        "my-header": "myValue",
   1293                      },
   1294             hops: [{ server: origin,
   1295                    },
   1296                    { server: otherURL,
   1297                      allowOrigin: origin,
   1298                      noAllowPreflight: 1,
   1299                    },
   1300                    ],
   1301           },
   1302           { pass: 1,
   1303             method: "DELETE",
   1304             hops: [{ server: origin,
   1305                    },
   1306                    { server: otherURL,
   1307                      allowOrigin: origin,
   1308                      allowMethods: "DELETE",
   1309                    },
   1310                    ],
   1311           },
   1312           { pass: 0,
   1313             method: "DELETE",
   1314             hops: [{ server: origin,
   1315                    },
   1316                    { server: otherURL,
   1317                      allowOrigin: origin,
   1318                      allowMethods: "DELETE",
   1319                    },
   1320                    { server: "https://sub1.test1." + originHost,
   1321                      allowOrigin: origin,
   1322                      allowMethods: "DELETE",
   1323                    },
   1324                    ],
   1325           },
   1326           { pass: 1,
   1327             method: "DELETE",
   1328             hops: [{ server: origin,
   1329                    },
   1330                    { server: otherURL,
   1331                      allowOrigin: origin,
   1332                      allowMethods: "DELETE",
   1333                    },
   1334                    { server: "https://sub1.test1." + originHost,
   1335                      allowOrigin: "*",
   1336                      allowMethods: "DELETE",
   1337                    },
   1338                    ],
   1339           },
   1340           { pass: 1,
   1341             method: "DELETE",
   1342             hops: [{ server: origin,
   1343                    },
   1344                    { server: otherURL,
   1345                      allowOrigin: origin,
   1346                      allowMethods: "DELETE",
   1347                    },
   1348                    { server: otherURL,
   1349                      allowOrigin: origin,
   1350                      allowMethods: "DELETE",
   1351                    },
   1352                    ],
   1353           },
   1354           { pass: 0,
   1355             method: "DELETE",
   1356             hops: [{ server: origin,
   1357                    },
   1358                    { server: otherURL,
   1359                      allowOrigin: origin,
   1360                      allowMethods: "DELETE",
   1361                    },
   1362                    { server: origin,
   1363                      allowOrigin: origin,
   1364                      allowMethods: "DELETE",
   1365                    },
   1366                    ],
   1367           },
   1368           { pass: 0,
   1369             method: "DELETE",
   1370             hops: [{ server: origin,
   1371                    },
   1372                    { server: otherURL,
   1373                      allowOrigin: origin,
   1374                      allowMethods: "DELETE",
   1375                      noAllowPreflight: 1,
   1376                    },
   1377                    ],
   1378           },
   1379           { pass: 0,
   1380             method: "POST",
   1381             body: "hi there",
   1382             headers: { "Content-Type": "text/plain",
   1383                        "my-header": "myValue",
   1384                      },
   1385             hops: [{ server: otherURL,
   1386                      allowOrigin: origin,
   1387                    },
   1388                    { server: "https://sub1.test1." + originHost,
   1389                      allowOrigin: origin,
   1390                    },
   1391                    ],
   1392           },
   1393           { pass: 0,
   1394             method: "DELETE",
   1395             hops: [{ server: otherURL,
   1396                      allowOrigin: origin,
   1397                    },
   1398                    { server: "https://sub1.test1." + originHost,
   1399                      allowOrigin: origin,
   1400                    },
   1401                    ],
   1402           },
   1403           { pass: 0,
   1404             method: "POST",
   1405             body: "hi there",
   1406             headers: { "Content-Type": "text/plain",
   1407                        "my-header": "myValue",
   1408                      },
   1409             hops: [{ server: otherURL,
   1410                    },
   1411                    { server: "https://sub1.test1." + originHost,
   1412                      allowOrigin: origin,
   1413                      allowHeaders: "my-header",
   1414                    },
   1415                    ],
   1416           },
   1417           { pass: 1,
   1418             method: "POST",
   1419             body: "hi there",
   1420             headers: { "Content-Type": "text/plain" },
   1421             hops: [{ server: origin,
   1422                    },
   1423                    { server: otherURL,
   1424                      allowOrigin: origin,
   1425                    },
   1426                    ],
   1427           },
   1428           { pass: 0,
   1429             method: "POST",
   1430             body: "hi there",
   1431             headers: { "Content-Type": "text/plain",
   1432                        "my-header": "myValue",
   1433                      },
   1434             hops: [{ server: otherURL,
   1435                      allowOrigin: origin,
   1436                      allowHeaders: "my-header",
   1437                    },
   1438                    { server: origin,
   1439                      allowOrigin: origin,
   1440                      allowHeaders: "my-header",
   1441                    },
   1442                    ],
   1443           },
   1444 
   1445           // test redirects with different credentials settings
   1446           {
   1447             // Initialize by setting a cookies for same- and cross- origins.
   1448             pass: 1,
   1449             method: "GET",
   1450             hops: [{ server: origin,
   1451                      setCookie: escape("a=1; Partitioned; Secure; SameSite=None"),
   1452                    },
   1453                    { server: otherURL,
   1454                      allowOrigin: origin,
   1455                      allowCred: 1,
   1456                      setCookie: escape("a=2; Partitioned; Secure; SameSite=None"),
   1457                    },
   1458                    ],
   1459             withCred: 1,
   1460           },
   1461           { pass: 1,
   1462             method: "GET",
   1463             hops: [{ server: origin,
   1464                      cookie: escape("a=1"),
   1465                    },
   1466                    { server: origin,
   1467                      cookie: escape("a=1"),
   1468                    },
   1469                    { server: otherURL,
   1470                      allowOrigin: origin,
   1471                      noCookie: 1,
   1472                    },
   1473                    ],
   1474             withCred: 0,
   1475           },
   1476           { pass: 1,
   1477             method: "GET",
   1478             hops: [{ server: origin,
   1479                      cookie: escape("a=1"),
   1480                    },
   1481                    { server: origin,
   1482                      cookie: escape("a=1"),
   1483                    },
   1484                    { server: otherURL,
   1485                      allowOrigin: origin,
   1486                      allowCred: 1,
   1487                      cookie: escape("a=2"),
   1488                    },
   1489                    ],
   1490             withCred: 1,
   1491           },
   1492           // expected fail because allow-credentials CORS header is not set
   1493           { pass: 0,
   1494             method: "GET",
   1495             hops: [{ server: origin,
   1496                      cookie: escape("a=1"),
   1497                    },
   1498                    { server: origin,
   1499                      cookie: escape("a=1"),
   1500                    },
   1501                    { server: otherURL,
   1502                      allowOrigin: origin,
   1503                      cookie: escape("a=2"),
   1504                    },
   1505                    ],
   1506             withCred: 1,
   1507           },
   1508           { pass: 1,
   1509             method: "GET",
   1510             hops: [{ server: origin,
   1511                      cookie: escape("a=1"),
   1512                    },
   1513                    { server: origin,
   1514                      cookie: escape("a=1"),
   1515                    },
   1516                    { server: otherURL,
   1517                      allowOrigin: '*',
   1518                      noCookie: 1,
   1519                    },
   1520                    ],
   1521             withCred: 0,
   1522           },
   1523           { pass: 0,
   1524             method: "GET",
   1525             hops: [{ server: origin,
   1526                      cookie: escape("a=1"),
   1527                    },
   1528                    { server: origin,
   1529                      cookie: escape("a=1"),
   1530                    },
   1531                    { server: otherURL,
   1532                      allowOrigin: '*',
   1533                      allowCred: 1,
   1534                      cookie: escape("a=2"),
   1535                    },
   1536                    ],
   1537             withCred: 1,
   1538           },
   1539           ];
   1540 
   1541  if (!runRedirectTests) {
   1542    tests = [];
   1543  }
   1544 
   1545  for (test of tests) {
   1546    req = {
   1547      url: test.hops[0].server + basePath + "hop=1&hops=" +
   1548           escape(JSON.stringify(test.hops)),
   1549      method: test.method,
   1550      headers: test.headers,
   1551      body: test.body,
   1552      withCred: test.withCred,
   1553    };
   1554 
   1555    if (test.pass) {
   1556      if (test.body)
   1557        req.url += "&body=" + escape(test.body);
   1558    }
   1559 
   1560    loaderWindow.postMessage(JSON.stringify(req), origin);
   1561 
   1562    res = JSON.parse(yield);
   1563    if (test.pass) {
   1564      is(res.didFail, false,
   1565        "shouldn't have failed in test for " + JSON.stringify(test));
   1566      is(res.status, 200, "wrong status in test for " + JSON.stringify(test));
   1567      is(res.statusText, "OK", "wrong status text for " + JSON.stringify(test));
   1568      is(res.responseXML, "<res>hello pass</res>",
   1569         "wrong responseXML in test for " + JSON.stringify(test));
   1570      is(res.responseText, "<res>hello pass</res>\n",
   1571         "wrong responseText in test for " + JSON.stringify(test));
   1572      is(res.events.join(","),
   1573         "opening,rs1,sending,loadstart,rs2,rs3,rs4,load,loadend",
   1574         "wrong responseText in test for " + JSON.stringify(test));
   1575    }
   1576    else {
   1577      is(res.didFail, true,
   1578        "should have failed in test for " + JSON.stringify(test));
   1579      is(res.status, 0, "wrong status in test for " + JSON.stringify(test));
   1580      is(res.statusText, "", "wrong status text for " + JSON.stringify(test));
   1581      is(res.responseXML, null,
   1582         "wrong responseXML in test for " + JSON.stringify(test));
   1583      is(res.responseText, "",
   1584         "wrong responseText in test for " + JSON.stringify(test));
   1585      is(res.events.join(","),
   1586         "opening,rs1,sending,loadstart,rs4,error,loadend",
   1587         "wrong events in test for " + JSON.stringify(test));
   1588      is(res.progressEvents, 0,
   1589         "wrong progressevents in test for " + JSON.stringify(test));
   1590    }
   1591  }
   1592 
   1593  SpecialPowers.clearUserPref("network.cookie.sameSite.laxByDefault");
   1594  SpecialPowers.clearUserPref("browser.contentblocking.category");
   1595 
   1596  clearCORSPreflightCacheTest();
   1597 }
   1598 
   1599 </script>
   1600 </pre>
   1601 </body>
   1602 </html>