tor-browser

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

RTCPeerConnection-setRemoteDescription.html (6077B)


      1 <!doctype html>
      2 <meta charset=utf-8>
      3 <title>RTCPeerConnection.prototype.setRemoteDescription</title>
      4 <script src="/resources/testharness.js"></script>
      5 <script src="/resources/testharnessreport.js"></script>
      6 <script src="RTCPeerConnection-helper.js"></script>
      7 <script>
      8  'use strict';
      9 
     10  // Test is based on the following editor draft:
     11  // https://w3c.github.io/webrtc-pc/archives/20170605/webrtc.html
     12 
     13  // The following helper functions are called from RTCPeerConnection-helper.js:
     14  //   assert_session_desc_not_similar()
     15  //   assert_session_desc_similar()
     16 
     17  /*
     18    4.3.2.  Interface Definition
     19      [Constructor(optional RTCConfiguration configuration)]
     20      interface RTCPeerConnection : EventTarget {
     21        Promise<void>                      setRemoteDescription(
     22            RTCSessionDescriptionInit description);
     23 
     24        readonly attribute RTCSessionDescription? remoteDescription;
     25        readonly attribute RTCSessionDescription? currentRemoteDescription;
     26        readonly attribute RTCSessionDescription? pendingRemoteDescription;
     27        ...
     28      };
     29 
     30    4.6.2.  RTCSessionDescription Class
     31      dictionary RTCSessionDescriptionInit {
     32        required RTCSdpType type;
     33                 DOMString  sdp = "";
     34      };
     35 
     36    4.6.1.  RTCSdpType
     37      enum RTCSdpType {
     38        "offer",
     39        "pranswer",
     40        "answer",
     41        "rollback"
     42      };
     43   */
     44 
     45  /*
     46    4.6.1.  enum RTCSdpType
     47   */
     48  promise_test(async t => {
     49    const pc = new RTCPeerConnection();
     50    t.add_cleanup(() => pc.close());
     51 
     52    // SDP is validated after WebIDL validation
     53    try {
     54      await pc.setRemoteDescription({ type: 'bogus', sdp: 'bogus' });
     55      t.unreached_func("Should have rejected.");
     56    } catch (e) {
     57      assert_throws_js(TypeError, () => { throw e });
     58    }
     59  }, 'setRemoteDescription with invalid type and invalid SDP should reject with TypeError');
     60 
     61  promise_test(async t => {
     62    const pc = new RTCPeerConnection();
     63    t.add_cleanup(() => pc.close());
     64 
     65    // SDP is validated after validating type
     66    try {
     67      await pc.setRemoteDescription({ type: 'answer', sdp: 'invalid' });
     68      t.unreached_func("Should have rejected.");
     69    } catch (e) {
     70      assert_throws_dom('InvalidStateError', () => { throw e });
     71    }
     72  }, 'setRemoteDescription() with invalid SDP and stable state should reject with InvalidStateError');
     73 
     74  /* Dedicated signalingstate events test. */
     75 
     76  promise_test(async t => {
     77    const pc = new RTCPeerConnection();
     78    const pc2 = new RTCPeerConnection();
     79    t.add_cleanup(() => pc.close());
     80    t.add_cleanup(() => pc2.close());
     81 
     82    let eventCount = 0;
     83    const states = [
     84      'stable', 'have-local-offer', 'stable', 'have-remote-offer',
     85    ];
     86    pc.onsignalingstatechange = t.step_func(() =>
     87        assert_equals(pc.signalingState, states[++eventCount]));
     88 
     89    const assert_state = state => {
     90      assert_equals(state, pc.signalingState);
     91      assert_equals(state, states[eventCount]);
     92    };
     93 
     94    const offer = await generateAudioReceiveOnlyOffer(pc);
     95    assert_state('stable');
     96    await pc.setLocalDescription(offer);
     97    assert_state('have-local-offer');
     98    await pc2.setRemoteDescription(offer);
     99    await exchangeAnswer(pc, pc2);
    100    assert_state('stable');
    101    await exchangeOffer(pc2, pc);
    102    assert_state('have-remote-offer');
    103  }, 'Negotiation should fire signalingsstate events');
    104 
    105  /* Operations after returning to stable state */
    106 
    107  promise_test(async t => {
    108    const pc = new RTCPeerConnection();
    109    const pc2 = new RTCPeerConnection();
    110    t.add_cleanup(() => pc.close());
    111    t.add_cleanup(() => pc2.close());
    112 
    113    const offer1 = await generateAudioReceiveOnlyOffer(pc2);
    114    await pc2.setLocalDescription(offer1);
    115    await pc.setRemoteDescription(offer1);
    116    await exchangeAnswer(pc2, pc);
    117    const offer2 = await generateVideoReceiveOnlyOffer(pc2);
    118    await pc2.setLocalDescription(offer2);
    119    await pc.setRemoteDescription(offer2);
    120    assert_session_desc_not_similar(offer1, offer2);
    121    assert_session_desc_similar(pc.remoteDescription, offer2);
    122    assert_session_desc_similar(pc.currentRemoteDescription, offer1);
    123    assert_session_desc_similar(pc.pendingRemoteDescription, offer2);
    124  }, 'Calling setRemoteDescription() again after one round of remote-offer/local-answer should succeed');
    125 
    126  promise_test(async t => {
    127    const pc = new RTCPeerConnection();
    128    const pc2 = new RTCPeerConnection();
    129    t.add_cleanup(() => pc.close());
    130    t.add_cleanup(() => pc2.close());
    131 
    132    const offer = await generateAudioReceiveOnlyOffer(pc);
    133    await pc.setLocalDescription(offer);
    134    await pc2.setRemoteDescription(offer);
    135    const answer = await pc2.createAnswer();
    136    await pc2.setLocalDescription(answer);
    137    await pc.setRemoteDescription(answer);
    138    await exchangeOffer(pc2, pc);
    139    assert_equals(pc.remoteDescription, pc.pendingRemoteDescription);
    140    assert_session_desc_similar(pc.remoteDescription, offer);
    141    assert_session_desc_similar(pc.currentRemoteDescription, answer);
    142  }, 'Switching role from offerer to answerer after going back to stable state should succeed');
    143 
    144  promise_test(async t => {
    145    const pc = new RTCPeerConnection();
    146    t.add_cleanup(() => pc.close());
    147    const offer = await pc.createOffer();
    148    const p = Promise.race([
    149      pc.setRemoteDescription(offer),
    150      new Promise(r => t.step_timeout(() => r("timeout"), 200))
    151    ]);
    152    pc.close();
    153    assert_equals(await p, "timeout");
    154    assert_equals(pc.signalingState, "closed", "In closed state");
    155  }, 'Closing on setRemoteDescription() neither resolves nor rejects');
    156 
    157  promise_test(async t => {
    158    const pc = new RTCPeerConnection();
    159    t.add_cleanup(() => pc.close());
    160    const offer = await pc.createOffer();
    161    await pc.setLocalDescription(offer);
    162    const p = Promise.race([
    163      pc.setRemoteDescription(offer),
    164      new Promise(r => t.step_timeout(() => r("timeout"), 200))
    165    ]);
    166    pc.close();
    167    assert_equals(await p, "timeout");
    168    assert_equals(pc.signalingState, "closed", "In closed state");
    169  }, 'Closing on rollback neither resolves nor rejects');
    170 
    171 </script>