streams-close.https.any.js (8719B)
1 // META: global=window,worker 2 // META: script=/common/get-host-info.sub.js 3 // META: script=/common/utils.js 4 // META: script=resources/webtransport-test-helpers.sub.js 5 6 // Note: There is no aioquic event for STOP_SENDING yet, so the server does 7 // not support checking this yet. Hence, tests checking from the STOP_SENDING 8 // signal cannot be tested yet. 9 10 promise_test(async t => { 11 const id = token(); 12 const wt = new WebTransport(webtransport_url(`client-close.py?token=${id}`)); 13 add_completion_callback(() => wt.close()); 14 await wt.ready; 15 16 const bidi_stream = await wt.createBidirectionalStream(); 17 18 const writable = bidi_stream.writable; 19 writable.close(); 20 21 await wait(10); 22 const data = await query(id); 23 24 assert_own_property(data, 'stream-close-info'); 25 const info = data['stream-close-info']; 26 27 assert_equals(info.source, 'FIN', 'source'); 28 }, 'Close outgoing stream / bidi-1'); 29 30 promise_test(async t => { 31 const id = token(); 32 const wt = new WebTransport(webtransport_url(`client-close.py?token=${id}`)); 33 add_completion_callback(() => wt.close()); 34 await wt.ready; 35 36 const streams_reader = wt.incomingBidirectionalStreams.getReader(); 37 const {value: bidi} = await streams_reader.read(); 38 39 const writable = bidi.writable; 40 writable.close(); 41 42 await wait(10); 43 const data = await query(id); 44 45 assert_own_property(data, 'stream-close-info'); 46 const info = data['stream-close-info']; 47 48 assert_equals(info.source, 'FIN', 'source'); 49 }, 'Close outgoing stream / bidi-2'); 50 51 promise_test(async t => { 52 const id = token(); 53 const wt = new WebTransport(webtransport_url(`client-close.py?token=${id}`)); 54 add_completion_callback(() => wt.close()); 55 await wt.ready; 56 57 const writable = await wt.createUnidirectionalStream(); 58 writable.close(); 59 60 await wait(10); 61 const data = await query(id); 62 63 assert_own_property(data, 'stream-close-info'); 64 const info = data['stream-close-info']; 65 66 assert_equals(info.source, 'FIN', 'source'); 67 }, 'Close outgoing stream / uni'); 68 69 promise_test(async t => { 70 const id = token(); 71 const wt = new WebTransport(webtransport_url(`client-close.py?token=${id}`)); 72 add_completion_callback(() => wt.close()); 73 await wt.ready; 74 75 const bidi_stream = await wt.createBidirectionalStream(); 76 77 const writable = bidi_stream.writable; 78 79 const WT_CODE = 139; 80 const HTTP_CODE = webtransport_code_to_http_code(WT_CODE); 81 await writable.abort( 82 new WebTransportError({streamErrorCode: WT_CODE})); 83 84 await wait(10); 85 const data = await query(id); 86 87 // Check that stream is aborted with RESET_STREAM with the code and reason 88 assert_own_property(data, 'stream-close-info'); 89 const info = data['stream-close-info']; 90 91 assert_equals(info.source, 'reset', 'reset stream'); 92 assert_equals(info.code, HTTP_CODE, 'code'); 93 }, 'Abort client-created bidirectional stream'); 94 95 promise_test(async t => { 96 const id = token(); 97 const wt = new WebTransport(webtransport_url(`client-close.py?token=${id}`)); 98 add_completion_callback(() => wt.close()); 99 await wt.ready; 100 101 const stream_reader = wt.incomingBidirectionalStreams.getReader(); 102 const { value: bidi_stream } = await stream_reader.read(); 103 stream_reader.releaseLock(); 104 105 const writer = bidi_stream.writable.getWriter(); 106 107 const WT_CODE = 52; 108 const HTTP_CODE = webtransport_code_to_http_code(WT_CODE); 109 await writer.abort( 110 new WebTransportError({streamErrorCode: WT_CODE})); 111 112 await wait(10); 113 const data = await query(id); 114 115 // Check that stream is aborted with RESET_STREAM with the code and reason 116 assert_own_property(data, 'stream-close-info'); 117 const info = data['stream-close-info']; 118 119 assert_equals(info.source, 'reset', 'reset_stream'); 120 assert_equals(info.code, HTTP_CODE, 'code'); 121 }, 'Abort server-initiated bidirectional stream'); 122 123 promise_test(async t => { 124 const id = token(); 125 const wt = new WebTransport(webtransport_url(`client-close.py?token=${id}`)); 126 add_completion_callback(() => wt.close()); 127 await wt.ready; 128 129 const writable = await wt.createUnidirectionalStream(); 130 131 const WT_CODE = 95; 132 const HTTP_CODE = webtransport_code_to_http_code(WT_CODE); 133 await writable.abort( 134 new WebTransportError({streamErrorCode: WT_CODE})); 135 136 await wait(10); 137 const data = await query(id); 138 139 // Check that stream is aborted with RESET_STREAM with the code and reason 140 assert_own_property(data, 'stream-close-info'); 141 const info = data['stream-close-info']; 142 143 assert_equals(info.source, 'reset', 'reset_stream'); 144 assert_equals(info.code, HTTP_CODE, 'code'); 145 }, 'Abort unidirectional stream with WebTransportError'); 146 147 promise_test(async t => { 148 const id = token(); 149 const wt = new WebTransport(webtransport_url(`client-close.py?token=${id}`)); 150 add_completion_callback(() => wt.close()); 151 await wt.ready; 152 153 const writable = await wt.createUnidirectionalStream(); 154 const writer = writable.getWriter(); 155 156 const WT_CODE = 134; 157 const HTTP_CODE = webtransport_code_to_http_code(WT_CODE); 158 159 // We use a large chunk so that sending the FIN signal takes time. 160 const chunk = new Uint8Array(64 * 1024); 161 const e = new WebTransportError({streamErrorCode: WT_CODE}); 162 // Write a chunk, close the stream, and then abort the stream immediately to 163 // abort the closing operation. 164 // TODO: Check that the abort promise is correctly rejected/resolved based on 165 // the spec discussion at https://github.com/whatwg/streams/issues/1203. 166 await writer.write(chunk); 167 const close_promise = writer.close(); 168 const abort_promise = writer.abort(e); 169 170 await promise_rejects_exactly(t, e, close_promise, 'close_promise'); 171 await promise_rejects_exactly(t, e, writer.closed, '.closed'); 172 await promise_rejects_exactly(t, e, abort_promise, 'abort_promise'); 173 writer.releaseLock(); 174 175 await wait(10); 176 const data = await query(id); 177 178 // Check that stream is aborted with RESET_STREAM with the code and reason 179 assert_own_property(data, 'stream-close-info'); 180 const info = data['stream-close-info']; 181 182 assert_equals(info.source, 'reset', 'reset_stream'); 183 assert_equals(info.code, HTTP_CODE, 'code'); 184 }, 'Close and abort unidirectional stream'); 185 186 promise_test(async t => { 187 const id = token(); 188 const wt = new WebTransport(webtransport_url(`client-close.py?token=${id}`)); 189 add_completion_callback(() => wt.close()); 190 await wt.ready; 191 192 const writable = await wt.createUnidirectionalStream(); 193 await writable.abort(); 194 195 await wait(10); 196 const data = await query(id); 197 198 // Check that stream is aborted with RESET_STREAM with the code and reason 199 assert_own_property(data, 'stream-close-info'); 200 const info = data['stream-close-info']; 201 202 assert_equals(info.source, 'reset', 'reset_stream'); 203 assert_equals(info.code, webtransport_code_to_http_code(0), 'code'); 204 }, 'Abort unidirectional stream with default error code'); 205 206 promise_test(async t => { 207 const WT_CODE = 0; 208 const HTTP_CODE = webtransport_code_to_http_code(WT_CODE); 209 const wt = new WebTransport( 210 webtransport_url(`abort-stream-from-server.py?code=${HTTP_CODE}`)); 211 add_completion_callback(() => wt.close()); 212 await wt.ready; 213 214 const writable = await wt.createUnidirectionalStream(); 215 const writer = writable.getWriter(); 216 217 // Write something, to make the stream visible to the server side. 218 await writer.write(new Uint8Array([64])); 219 220 // Sadly we cannot use promise_rejects_dom as the error constructor is 221 // WebTransportError rather than DOMException. Ditto below. 222 // We get a possible error, and then make sure wt.closed is rejected with it. 223 const e = await writer.closed.catch(e => e); 224 await promise_rejects_exactly( 225 t, e, writer.closed, 'closed promise should be rejected'); 226 assert_true(e instanceof WebTransportError); 227 assert_equals(e.source, 'stream', 'source'); 228 assert_equals(e.streamErrorCode, WT_CODE, 'streamErrorCode'); 229 }, 'STOP_SENDING coming from server'); 230 231 promise_test(async t => { 232 const WT_CODE = 0xffffffff; 233 const HTTP_CODE = webtransport_code_to_http_code(WT_CODE); 234 const wt = new WebTransport( 235 webtransport_url(`abort-stream-from-server.py?code=${HTTP_CODE}`)); 236 add_completion_callback(() => wt.close()); 237 await wt.ready; 238 239 const bidi = await wt.createBidirectionalStream(); 240 const writer = bidi.writable.getWriter(); 241 242 // Write something, to make the stream visible to the server side. 243 await writer.write(new Uint8Array([64])); 244 245 const reader = bidi.readable.getReader(); 246 const e = await reader.closed.catch(e => e); 247 await promise_rejects_exactly( 248 t, e, reader.closed, 'closed promise should be rejected'); 249 assert_true(e instanceof WebTransportError); 250 assert_equals(e.source, 'stream', 'source'); 251 assert_equals(e.streamErrorCode, WT_CODE, 'streamErrorCode'); 252 }, 'RESET_STREAM coming from server');