tor-browser

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

RTCDataChannel-bufferedAmount.html (11653B)


      1 <!doctype html>
      2 <meta charset=utf-8>
      3 <meta name="timeout" content="long">
      4 <title>RTCDataChannel.prototype.bufferedAmount</title>
      5 <script src="/resources/testharness.js"></script>
      6 <script src="/resources/testharnessreport.js"></script>
      7 <script src="RTCPeerConnection-helper.js"></script>
      8 <script>
      9 'use strict';
     10 
     11 // Test is based on the following revision:
     12 // https://rawgit.com/w3c/webrtc-pc/1cc5bfc3ff18741033d804c4a71f7891242fb5b3/webrtc.html
     13 
     14 // The following helper functions are called from RTCPeerConnection-helper.js:
     15 //  createDataChannelPair
     16 //  awaitMessage
     17 
     18 /*
     19  6.2.  RTCDataChannel
     20    interface RTCDataChannel : EventTarget {
     21      ...
     22      readonly  attribute unsigned long       bufferedAmount;
     23      void send(USVString data);
     24      void send(Blob data);
     25      void send(ArrayBuffer data);
     26      void send(ArrayBufferView data);
     27    };
     28 
     29    bufferedAmount
     30      The bufferedAmount attribute must return the number of bytes of application
     31      data (UTF-8 text and binary data) that have been queued using send() but that,
     32      as of the last time the event loop started executing a task, had not yet been
     33      transmitted to the network. (This thus includes any text sent during the
     34      execution of the current task, regardless of whether the user agent is able
     35      to transmit text asynchronously with script execution.) This does not include
     36      framing overhead incurred by the protocol, or buffering done by the operating
     37      system or network hardware. The value of the [[BufferedAmount]] slot will only
     38      increase with each call to the send() method as long as the [[ReadyState]] slot
     39      is open; however, the slot does not reset to zero once the channel closes. When
     40      the underlying data transport sends data from its queue, the user agent MUST
     41      queue a task that reduces [[BufferedAmount]] with the number of bytes that was
     42      sent.
     43 
     44 
     45  [WebMessaging]
     46  interface MessageEvent : Event {
     47    readonly attribute any data;
     48    ...
     49  };
     50 */
     51 
     52 // Simple ASCII encoded string
     53 const helloString = 'hello';
     54 // ASCII encoded buffer representation of the string
     55 const helloBuffer = Uint8Array.of(0x68, 0x65, 0x6c, 0x6c, 0x6f);
     56 const helloBlob = new Blob([helloBuffer]);
     57 
     58 const emptyBuffer = Uint8Array.of();
     59 const emptyBlob = new Blob([emptyBuffer]);
     60 
     61 // Unicode string with multiple code units
     62 const unicodeString = '世界你好';
     63 // UTF-8 encoded buffer representation of the string
     64 const unicodeBuffer = Uint8Array.of(
     65  0xe4, 0xb8, 0x96, 0xe7, 0x95, 0x8c,
     66  0xe4, 0xbd, 0xa0, 0xe5, 0xa5, 0xbd);
     67 
     68 for (const options of [{}, {negotiated: true, id: 0}]) {
     69  const mode = `${options.negotiated? "negotiated " : ""}datachannel`;
     70 
     71  /*
     72    Ensure .bufferedAmount is 0 initially for both sides.
     73   */
     74  promise_test(async (t) => {
     75    const [dc1, dc2] = await createDataChannelPair(t, options);
     76 
     77    assert_equals(dc1.bufferedAmount, 0, 'Expect bufferedAmount to be 0');
     78    assert_equals(dc2.bufferedAmount, 0, 'Expect bufferedAmount to be 0');
     79  }, `${mode} bufferedAmount initial value should be 0 for both peers`);
     80 
     81  /*
     82    6.2.  send()
     83      3.  Execute the sub step that corresponds to the type of the methods argument:
     84 
     85          string object
     86            Let data be the object and increase the bufferedAmount attribute
     87            by the number of bytes needed to express data as UTF-8.
     88   */
     89  promise_test(async (t) => {
     90    const [dc1, dc2] = await createDataChannelPair(t, options);
     91 
     92    dc1.send(unicodeString);
     93    assert_equals(dc1.bufferedAmount, unicodeBuffer.byteLength,
     94      'Expect bufferedAmount to be the byte length of the unicode string');
     95 
     96    await awaitMessage(dc2);
     97    assert_equals(dc1.bufferedAmount, 0,
     98      'Expect sender bufferedAmount to be reduced after message is sent');
     99  }, `${mode} bufferedAmount should increase to byte length of encoded` +
    100     `unicode string sent`);
    101 
    102  promise_test(async (t) => {
    103    const [dc1, dc2] = await createDataChannelPair(t, options);
    104 
    105    dc1.send("");
    106    assert_equals(dc1.bufferedAmount, 0,
    107      'Expect bufferedAmount to stay at zero after sending empty string');
    108 
    109    await awaitMessage(dc2);
    110    assert_equals(dc1.bufferedAmount, 0, 'Expect sender bufferedAmount unchanged');
    111  }, `${mode} bufferedAmount should stay at zero for empty string sent`);
    112 
    113  /*
    114    6.2. send()
    115      3.  Execute the sub step that corresponds to the type of the methods argument:
    116          ArrayBuffer object
    117            Let data be the data stored in the buffer described by the ArrayBuffer
    118            object and increase the bufferedAmount attribute by the length of the
    119            ArrayBuffer in bytes.
    120   */
    121  promise_test(async (t) => {
    122    const [dc1, dc2] = await createDataChannelPair(t, options);
    123 
    124    dc1.send(helloBuffer.buffer);
    125    assert_equals(dc1.bufferedAmount, helloBuffer.byteLength,
    126      'Expect bufferedAmount to increase to byte length of sent buffer');
    127 
    128    await awaitMessage(dc2);
    129    assert_equals(dc1.bufferedAmount, 0,
    130      'Expect sender bufferedAmount to be reduced after message is sent');
    131  }, `${mode} bufferedAmount should increase to byte length of buffer sent`);
    132 
    133  promise_test(async (t) => {
    134    const [dc1, dc2] = await createDataChannelPair(t, options);
    135 
    136    dc1.send(emptyBuffer.buffer);
    137    assert_equals(dc1.bufferedAmount, 0,
    138      'Expect bufferedAmount to stay at zero after sending empty buffer');
    139 
    140    await awaitMessage(dc2);
    141    assert_equals(dc1.bufferedAmount, 0,
    142                  'Expect sender bufferedAmount unchanged');
    143  }, `${mode} bufferedAmount should stay at zero for empty buffer sent`);
    144 
    145  /*
    146    6.2. send()
    147      3.  Execute the sub step that corresponds to the type of the methods argument:
    148          Blob object
    149            Let data be the raw data represented by the Blob object and increase
    150            the bufferedAmount attribute by the size of data, in bytes.
    151   */
    152  promise_test(async (t) => {
    153    const [dc1, dc2] = await createDataChannelPair(t, options);
    154 
    155    dc1.send(helloBlob);
    156    assert_equals(dc1.bufferedAmount, helloBlob.size,
    157      'Expect bufferedAmount to increase to size of sent blob');
    158 
    159    await awaitMessage(dc2);
    160    assert_equals(dc1.bufferedAmount, 0,
    161      'Expect sender bufferedAmount to be reduced after message is sent');
    162  }, `${mode} bufferedAmount should increase to size of blob sent`);
    163 
    164  promise_test(async (t) => {
    165    const [dc1, dc2] = await createDataChannelPair(t, options);
    166 
    167    dc1.send(emptyBlob);
    168    assert_equals(dc1.bufferedAmount, 0,
    169      'Expect bufferedAmount to stay at zero after sending empty blob');
    170 
    171    await awaitMessage(dc2);
    172    assert_equals(dc1.bufferedAmount, 0,
    173      'Expect sender bufferedAmount unchanged');
    174  }, `${mode} bufferedAmount should stay at zero for empty blob sent`);
    175 
    176  // Test sending 3 messages: helloBuffer, unicodeString, helloBlob
    177  promise_test(async (t) => {
    178    const resolver = new Resolver();
    179    let messageCount = 0;
    180 
    181    const [dc1, dc2] = await createDataChannelPair(t, options);
    182    dc2.onmessage = t.step_func(() => {
    183      if (++messageCount === 3) {
    184        assert_equals(dc1.bufferedAmount, 0,
    185          'Expect sender bufferedAmount to be reduced after message is sent');
    186        resolver.resolve();
    187      }
    188    });
    189 
    190    dc1.send(helloBuffer);
    191    assert_equals(dc1.bufferedAmount, helloString.length,
    192      'Expect bufferedAmount to be the total length of all messages queued to send');
    193 
    194    dc1.send(unicodeString);
    195    assert_equals(dc1.bufferedAmount,
    196      helloString.length + unicodeBuffer.byteLength,
    197      'Expect bufferedAmount to be the total length of all messages queued to send');
    198 
    199    dc1.send(helloBlob);
    200    assert_equals(dc1.bufferedAmount,
    201      helloString.length*2 + unicodeBuffer.byteLength,
    202      'Expect bufferedAmount to be the total length of all messages queued to send');
    203 
    204    await resolver;
    205  }, `${mode} bufferedAmount should increase by byte length for each message sent`);
    206 
    207  promise_test(async (t) => {
    208    const [dc1] = await createDataChannelPair(t, options);
    209 
    210    dc1.send(helloBuffer.buffer);
    211    assert_equals(dc1.bufferedAmount, helloBuffer.byteLength,
    212      'Expect bufferedAmount to increase to byte length of sent buffer');
    213 
    214    dc1.close();
    215    assert_equals(dc1.bufferedAmount, helloBuffer.byteLength,
    216      'Expect bufferedAmount to not decrease immediately after closing the channel');
    217  }, `${mode} bufferedAmount should not decrease immediately after initiating closure`);
    218 
    219  promise_test(async (t) => {
    220    const pc1 = new RTCPeerConnection();
    221    t.add_cleanup(() => pc1.close());
    222    const [dc1] = await createDataChannelPair(t, options, pc1);
    223 
    224    dc1.send(helloBuffer.buffer);
    225    assert_equals(dc1.bufferedAmount, helloBuffer.byteLength,
    226      'Expect bufferedAmount to increase to byte length of sent buffer');
    227 
    228    pc1.close();
    229    assert_equals(dc1.bufferedAmount, helloBuffer.byteLength,
    230      'Expect bufferedAmount to not decrease after closing the peer connection');
    231  }, `${mode} bufferedAmount should not decrease after closing the peer connection`);
    232 
    233  promise_test(async t => {
    234    const [channel1, channel2] = await createDataChannelPair(t, options);
    235    channel1.addEventListener('bufferedamountlow', t.step_func_done(() => {
    236      assert_true(channel1.bufferedAmount <= channel1.bufferedAmountLowThreshold);
    237    }));
    238    const eventWatcher = new EventWatcher(t, channel1, ['bufferedamountlow']);
    239    channel1.send(helloString);
    240    await eventWatcher.wait_for(['bufferedamountlow']);
    241  }, `${mode} bufferedamountlow event fires after send() is complete`);
    242 
    243  promise_test(async t => {
    244    const [channel1, channel2] = await createDataChannelPair(t, options);
    245    channel1.send(helloString);
    246    assert_equals(channel1.bufferedAmount, helloString.length);
    247    await awaitMessage(channel2);
    248    assert_equals(channel1.bufferedAmount, 0);
    249  }, `${mode} bufferedamount is data.length on send(data)`);
    250 
    251  promise_test(async t => {
    252    const [channel1, channel2] = await createDataChannelPair(t, options);
    253    channel1.send(helloString);
    254    assert_equals(channel1.bufferedAmount, helloString.length);
    255    assert_equals(channel1.bufferedAmount, helloString.length);
    256  }, `${mode} bufferedamount returns the same amount if no more data is`);
    257 
    258  promise_test(async t => {
    259    const [channel1, channel2] = await createDataChannelPair(t, options);
    260    let eventFireCount = 0;
    261    channel1.addEventListener('bufferedamountlow', t.step_func(() => {
    262      assert_true(channel1.bufferedAmount <= channel1.bufferedAmountLowThreshold);
    263      assert_equals(++eventFireCount, 1);
    264    }));
    265    const eventWatcher = new EventWatcher(t, channel1, ['bufferedamountlow']);
    266    channel1.send(helloString);
    267    assert_equals(channel1.bufferedAmount, helloString.length);
    268    channel1.send(helloString);
    269    assert_equals(channel1.bufferedAmount, 2 * helloString.length);
    270    await eventWatcher.wait_for(['bufferedamountlow']);
    271  }, `${mode} bufferedamountlow event fires only once after multiple` +
    272     ` consecutive send() calls`);
    273 
    274  promise_test(async t => {
    275    const [channel1, channel2] = await createDataChannelPair(t, options);
    276    const eventWatcher = new EventWatcher(t, channel1, ['bufferedamountlow']);
    277    channel1.send(helloString);
    278    assert_equals(channel1.bufferedAmount, helloString.length);
    279    await eventWatcher.wait_for(['bufferedamountlow']);
    280    assert_equals(await awaitMessage(channel2), helloString);
    281    channel1.send(helloString);
    282    assert_equals(channel1.bufferedAmount, helloString.length);
    283    await eventWatcher.wait_for(['bufferedamountlow']);
    284    assert_equals(await awaitMessage(channel2), helloString);
    285  }, `${mode} bufferedamountlow event fires after each sent message`);
    286 }
    287 </script>