close.https.any.js (6863B)
1 // META: global=window,worker 2 // META: script=/common/get-host-info.sub.js 3 // META: script=resources/webtransport-test-helpers.sub.js 4 // META: script=/common/utils.js 5 6 promise_test(async t => { 7 const id = token(); 8 const wt = new WebTransport(webtransport_url(`client-close.py?token=${id}`)); 9 add_completion_callback(() => wt.close()); 10 await wt.ready; 11 12 wt.close(); 13 14 const close_info = await wt.closed; 15 16 assert_equals(close_info.closeCode, 0, 'code'); 17 assert_equals(close_info.reason, '', 'reason'); 18 19 await wait(10); 20 const data = await query(id); 21 22 assert_own_property(data, 'session-close-info'); 23 const info = data['session-close-info'] 24 25 assert_false(info.abruptly, 'abruptly'); 26 assert_equals(info.close_info.code, 0, 'code'); 27 assert_equals(info.close_info.reason, '', 'reason'); 28 }, 'close'); 29 30 promise_test(async t => { 31 const wt = new WebTransport(webtransport_url('echo.py')); 32 wt.close(); 33 try { 34 await wt.closed; 35 } catch(e) { 36 await promise_rejects_exactly(t, e, wt.ready, 'ready promise should be rejected'); 37 assert_true(e instanceof WebTransportError); 38 assert_equals(e.source, 'session', 'source'); 39 assert_equals(e.streamErrorCode, null, 'streamErrorCode'); 40 } 41 }, 'close without waiting for ready'); 42 43 promise_test(async t => { 44 const id = token(); 45 const wt = new WebTransport(webtransport_url(`client-close.py?token=${id}`)); 46 add_completion_callback(() => wt.close()); 47 await wt.ready; 48 49 wt.close({closeCode: 99, reason: 'reason X'}); 50 51 const close_info = await wt.closed; 52 53 assert_equals(close_info.closeCode, 99, 'code'); 54 assert_equals(close_info.reason, 'reason X', 'reason'); 55 56 await wait(10); 57 const data = await query(id); 58 59 assert_own_property(data, 'session-close-info'); 60 const info = data['session-close-info'] 61 62 assert_false(info.abruptly, 'abruptly'); 63 assert_equals(info.close_info.code, 99, 'code'); 64 assert_equals(info.close_info.reason, 'reason X', 'reason'); 65 }, 'close with code and reason'); 66 67 promise_test(async t => { 68 const id = token(); 69 const wt = new WebTransport(webtransport_url(`client-close.py?token=${id}`)); 70 add_completion_callback(() => wt.close()); 71 await wt.ready; 72 const reason = 'あいうえお'.repeat(1000); 73 74 wt.close({closeCode: 11, reason}); 75 76 const close_info = await wt.closed; 77 78 assert_equals(close_info.closeCode, 11, 'code'); 79 // `close_info.reason` should report the original, non-truncated reason as 80 // step 9 of https://w3c.github.io/webtransport/#dom-webtransport-close 81 // uses the original `closeInfo` to perform `Cleanup`. 82 assert_equals(close_info.reason, reason, 'reason'); 83 84 await wait(10); 85 const data = await query(id); 86 87 assert_own_property(data, 'session-close-info'); 88 const info = data['session-close-info'] 89 90 // Server should have received truncated reason as step 6 of 91 // https://w3c.github.io/webtransport/#dom-webtransport-close specifies. 92 const expected_reason = 93 new TextDecoder().decode( 94 new TextEncoder().encode(reason).slice(0, 1024)).replaceAll('\ufffd', ''); 95 assert_false(info.abruptly, 'abruptly'); 96 assert_equals(info.close_info.code, 11, 'code'); 97 assert_equals(info.close_info.reason, expected_reason, 'reason'); 98 }, 'close with code and long reason'); 99 100 promise_test(async t => { 101 const wt = new WebTransport(webtransport_url('server-close.py')); 102 103 const close_info = await wt.closed; 104 assert_equals(close_info.closeCode, 0, 'code'); 105 assert_equals(close_info.reason, '', 'reason'); 106 }, 'server initiated closure without code and reason'); 107 108 promise_test(async t => { 109 const code = 32; 110 const reason = 'abc'; 111 const wt = new WebTransport( 112 webtransport_url(`server-close.py?code=${code}&reason=${reason}`)); 113 add_completion_callback(() => wt.close()); 114 115 const close_info = await wt.closed; 116 assert_equals(close_info.closeCode, code, 'code'); 117 assert_equals(close_info.reason, reason, 'reason'); 118 }, 'server initiated closure with code and reason'); 119 120 promise_test(async t => { 121 const wt = new WebTransport(webtransport_url('server-connection-close.py')); 122 add_completion_callback(() => wt.close()); 123 124 const streams_reader = wt.incomingBidirectionalStreams.getReader(); 125 const { value: bidi } = await streams_reader.read(); 126 const writer = bidi.writable.getWriter(); 127 const reader = bidi.readable.getReader(); 128 try { 129 writer.write(new Uint8Array([65])); 130 } catch (e) { 131 } 132 133 // Sadly we cannot use promise_rejects_dom as the error constructor is 134 // WebTransportError rather than DOMException. 135 // We get a possible error, and then make sure wt.closed is rejected with it. 136 const e = await wt.closed.catch(e => e); 137 await promise_rejects_exactly(t, e, wt.closed, 'wt.closed'); 138 await promise_rejects_exactly(t, e, writer.closed, 'writer.closed'); 139 await promise_rejects_exactly(t, e, reader.closed, 'reader.closed'); 140 assert_true(e instanceof WebTransportError); 141 assert_equals(e.source, 'session', 'source'); 142 assert_equals(e.streamErrorCode, null, 'streamErrorCode'); 143 }, 'server initiated connection closure'); 144 145 promise_test(async t => { 146 const wt = new WebTransport(webtransport_url('echo.py')); 147 const stream = await wt.createUnidirectionalStream(); 148 await wt.ready; 149 }, 'opening unidirectional stream before ready'); 150 151 promise_test(async t => { 152 const wt = new WebTransport(webtransport_url('echo.py')); 153 const stream = await wt.createBidirectionalStream(); 154 await wt.ready; 155 }, 'opening bidirectional stream before ready'); 156 157 promise_test(async t => { 158 const wt = new WebTransport(webtransport_url('server-close.py')); 159 await promise_rejects_dom(t, "InvalidStateError", 160 wt.createUnidirectionalStream()); 161 }, 'server initiated closure while opening unidirectional stream before ready'); 162 163 promise_test(async t => { 164 const wt = new WebTransport(webtransport_url('server-close.py')); 165 await promise_rejects_dom(t, "InvalidStateError", 166 wt.createBidirectionalStream()); 167 }, 'server initiated closure while opening bidirectional stream before ready'); 168 169 // Regression test for https://crbug.com/347710668. 170 promise_test(async t => { 171 const wt = new WebTransport(webtransport_url('server-read-then-close.py')); 172 add_completion_callback(() => wt.close()); 173 await wt.ready; 174 175 const bidi_reader = wt.incomingBidirectionalStreams.getReader(); 176 const { value: bidi } = await bidi_reader.read(); 177 178 bidi.writable.getWriter().write(new TextEncoder().encode('some data')); 179 const reader = bidi.readable.getReader(); 180 await reader.closed.catch(t.step_func( 181 e => assert_true(e instanceof WebTransportError))); 182 183 // The WebTransport session will already be closed. 184 const {reason, closeCode} = await wt.closed; 185 186 assert_equals(reason, '', 'reason should be default'); 187 assert_equals(closeCode, 0, 'closeCode should be default'); 188 }, 'reading closed property after close should work');