tor-browser

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

close.any.js (7617B)


      1 // META: script=../../constants.sub.js
      2 // META: script=resources/url-constants.js
      3 // META: global=window,worker
      4 // META: variant=?default
      5 // META: variant=?wss
      6 // META: variant=?wpt_flags=h2
      7 
      8 'use strict';
      9 
     10 promise_test(async () => {
     11  const wss = new WebSocketStream(ECHOURL);
     12  await wss.opened;
     13  wss.close({ closeCode: 3456, reason: 'pizza' });
     14  const { closeCode, reason } = await wss.closed;
     15  assert_equals(closeCode, 3456, 'code should match');
     16  assert_equals(reason, 'pizza', 'reason should match');
     17 }, 'close code should be sent to server and reflected back');
     18 
     19 promise_test(async () => {
     20  const wss = new WebSocketStream(ECHOURL);
     21  await wss.opened;
     22  wss.close();
     23  const { closeCode, reason } = await wss.closed;
     24  assert_equals(closeCode, 1005, 'code should be unset');
     25  assert_equals(reason, '', 'reason should be empty');
     26 }, 'no close argument should send empty Close frame');
     27 
     28 promise_test(async () => {
     29  const wss = new WebSocketStream(ECHOURL);
     30  await wss.opened;
     31  wss.close({});
     32  const { closeCode, reason } = await wss.closed;
     33  assert_equals(closeCode, 1005, 'code should be unset');
     34  assert_equals(reason, '', 'reason should be empty');
     35 }, 'unspecified close code should send empty Close frame');
     36 
     37 promise_test(async () => {
     38  const wss = new WebSocketStream(ECHOURL);
     39  await wss.opened;
     40  wss.close({reason: ''});
     41  const { closeCode, reason } = await wss.closed;
     42  assert_equals(closeCode, 1005, 'code should be unset');
     43  assert_equals(reason, '', 'reason should be empty');
     44 }, 'unspecified close code with empty reason should send empty Close frame');
     45 
     46 promise_test(async () => {
     47  const wss = new WebSocketStream(ECHOURL);
     48  await wss.opened;
     49  wss.close({reason: 'non-empty'});
     50  const { closeCode, reason } = await wss.closed;
     51  assert_equals(closeCode, 1000, 'code should be set');
     52  assert_equals(reason, 'non-empty', 'reason should match');
     53 }, 'unspecified close code with non-empty reason should set code to 1000');
     54 
     55 promise_test(async () => {
     56  const wss = new WebSocketStream(ECHOURL);
     57  await wss.opened;
     58  assert_throws_js(TypeError, () => wss.close(true),
     59                   'close should throw a TypeError');
     60 }, 'close(true) should throw a TypeError');
     61 
     62 promise_test(async () => {
     63  const wss = new WebSocketStream(ECHOURL);
     64  await wss.opened;
     65  const reason = '.'.repeat(124);
     66  assert_throws_dom('SyntaxError', () => wss.close({ reason }),
     67                    'close should throw a SyntaxError');
     68 }, 'close() with an overlong reason should throw');
     69 
     70 function IsWebSocketError(e) {
     71  return e.constructor == WebSocketError;
     72 }
     73 
     74 promise_test(t => {
     75  const wss = new WebSocketStream(ECHOURL);
     76  wss.close();
     77  return Promise.all([
     78    wss.opened.then(t.unreached_func('should have rejected')).catch(e => assert_true(IsWebSocketError(e))),
     79    wss.closed.then(t.unreached_func('should have rejected')).catch(e => assert_true(IsWebSocketError(e))),
     80  ]);
     81 }, 'close during handshake should work');
     82 
     83 for (const invalidCode of [999, 1001, 2999, 5000]) {
     84  promise_test(async () => {
     85    const wss = new WebSocketStream(ECHOURL);
     86    await wss.opened;
     87    assert_throws_dom('InvalidAccessError', () => wss.close({ closeCode: invalidCode }),
     88                      'close should throw an InvalidAccessError');
     89  }, `close() with invalid code ${invalidCode} should throw`);
     90 }
     91 
     92 promise_test(async () => {
     93  const wss = new WebSocketStream(ECHOURL);
     94  const { writable } = await wss.opened;
     95  writable.getWriter().close();
     96  const { closeCode, reason } = await wss.closed;
     97  assert_equals(closeCode, 1005, 'code should be unset');
     98  assert_equals(reason, '', 'reason should be empty');
     99 }, 'closing the writable should result in a clean close');
    100 
    101 promise_test(async () => {
    102  const wss = new WebSocketStream(`${BASEURL}/delayed-passive-close`);
    103  const { writable } = await wss.opened;
    104  const startTime = performance.now();
    105  await writable.getWriter().close();
    106  const elapsed = performance.now() - startTime;
    107  const jitterAllowance = 100;
    108  assert_greater_than_equal(elapsed, 1000 - jitterAllowance,
    109                            'one second should have elapsed');
    110 }, 'writer close() promise should not resolve until handshake completes');
    111 
    112 promise_test(async t => {
    113  const wss = new WebSocketStream(`${BASEURL}/passive-close-abort`);
    114  await wss.opened;
    115  wss.close({closeCode: 4000, reason: 'because'});
    116  const error = await wss.closed.then(t.unreached_func('closed should reject'), e => e);
    117  assert_equals(error.constructor, WebSocketError, 'error should be WebSocketError');
    118  assert_equals(error.closeCode, 1006, 'close code should be Abnormal Closure');
    119 }, 'incomplete closing handshake should be considered unclean close');
    120 
    121 const abortOrCancel = [
    122  {
    123    method: 'abort',
    124    voweling: 'aborting',
    125    stream: 'writable',
    126  },
    127  {
    128    method: 'cancel',
    129    voweling: 'canceling',
    130    stream: 'readable',
    131  },
    132 ];
    133 
    134 for (const { method, voweling, stream } of abortOrCancel) {
    135 
    136  promise_test(async () => {
    137    const wss = new WebSocketStream(ECHOURL);
    138    const info = await wss.opened;
    139    info[stream][method]();
    140    const { closeCode, reason } = await wss.closed;
    141    assert_equals(closeCode, 1005, 'code should be unset');
    142    assert_equals(reason, '', 'reason should be empty');
    143  }, `${voweling} the ${stream} should result in a clean close`);
    144 
    145  promise_test(async () => {
    146    const wss = new WebSocketStream(ECHOURL);
    147    const info = await wss.opened;
    148    info[stream][method]({ closeCode: 3333, reason: 'obsolete' });
    149    const { closeCode, reason } = await wss.closed;
    150    assert_equals(closeCode, 1005, 'code should be unset');
    151    assert_equals(reason, '', 'reason should be empty');
    152  }, `${voweling} the ${stream} with attributes not wrapped in a WebSocketError should be ignored`);
    153 
    154  promise_test(async () => {
    155    const wss = new WebSocketStream(ECHOURL);
    156    const info = await wss.opened;
    157    info[stream][method](new WebSocketError('', { closeCode: 3333 }));
    158    const { closeCode, reason } = await wss.closed;
    159    assert_equals(closeCode, 3333, 'code should be used');
    160    assert_equals(reason, '', 'reason should be empty');
    161  }, `${voweling} the ${stream} with a code should send that code`);
    162 
    163  promise_test(async () => {
    164    const wss = new WebSocketStream(ECHOURL);
    165    const info = await wss.opened;
    166    info[stream][method](new WebSocketError('', { closeCode: 3456, reason: 'set' }));
    167    const { closeCode, reason } = await wss.closed;
    168    assert_equals(closeCode, 3456, 'code should be used');
    169    assert_equals(reason, 'set', 'reason should be used');
    170  }, `${voweling} the ${stream} with a code and reason should use them`);
    171 
    172  promise_test(async () => {
    173    const wss = new WebSocketStream(ECHOURL);
    174    const info = await wss.opened;
    175    info[stream][method](new WebSocketError('', { reason: 'specified' }));
    176    const { closeCode, reason } = await wss.closed;
    177    assert_equals(closeCode, 1000, 'code should be defaulted');
    178    assert_equals(reason, 'specified', 'reason should be used');
    179  }, `${voweling} the ${stream} with a reason but no code should default the close code`);
    180 
    181  promise_test(async () => {
    182    const wss = new WebSocketStream(ECHOURL);
    183    const info = await wss.opened;
    184    const domException = new DOMException('yes', 'DataCloneError');
    185    domException.closeCode = 1000;
    186    domException.reason = 'should be ignored';
    187    info[stream][method](domException);
    188    const { closeCode, reason } = await wss.closed;
    189    assert_equals(closeCode, 1005, 'code should be unset');
    190    assert_equals(reason, '', 'reason should be empty');
    191  }, `${voweling} the ${stream} with a DOMException not set code or reason`);
    192 
    193 }