tor-browser

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

webtransport-test-helpers.sub.js (4136B)


      1 // The file including this must also include /common/get-host-info.sub.js to
      2 // pick up the necessary constants.
      3 
      4 const HOST = get_host_info().ORIGINAL_HOST;
      5 const PORT = '{{ports[webtransport-h3][0]}}';
      6 const BASE = `https://${HOST}:${PORT}`;
      7 
      8 // Wait for the given number of milliseconds (ms).
      9 function wait(ms) { return new Promise(res => step_timeout(res, ms)); }
     10 
     11 // Create URL for WebTransport session.
     12 function webtransport_url(handler) {
     13  return `${BASE}/webtransport/handlers/${handler}`;
     14 }
     15 
     16 // Converts WebTransport stream error code to HTTP/3 error code.
     17 // https://ietf-wg-webtrans.github.io/draft-ietf-webtrans-http3/draft-ietf-webtrans-http3.html#section-4.3
     18 function webtransport_code_to_http_code(n) {
     19  const first = 0x52e4a40fa8db;
     20  return first + n + Math.floor(n / 0x1e);
     21 }
     22 
     23 // Read all chunks from |readable_stream| and return as an array of arrays
     24 async function read_stream(readable_stream) {
     25  const reader = readable_stream.getReader();
     26 
     27  let chunks = [];
     28  while (true) {
     29    const {value: chunk, done} = await reader.read();
     30    if (done) {
     31      break;
     32    }
     33    chunks.push(chunk);
     34  }
     35  reader.releaseLock();
     36 
     37  return chunks;
     38 }
     39 
     40 // Read all chunks from |readable_stream|, decode chunks to a utf-8 string, then
     41 // return the string.
     42 async function read_stream_as_string(readable_stream) {
     43  const decoder = new TextDecoderStream();
     44  const decode_stream = readable_stream.pipeThrough(decoder);
     45  const reader = decode_stream.getReader();
     46 
     47  let chunks = '';
     48  while (true) {
     49    const {value: chunk, done} = await reader.read();
     50    if (done) {
     51      break;
     52    }
     53    chunks += chunk;
     54  }
     55  reader.releaseLock();
     56 
     57  return chunks;
     58 }
     59 
     60 // Decode all chunks in a given ReadableStream, and parse the data using JSON.
     61 async function read_stream_as_json(readable_stream) {
     62  const text = await read_stream_as_string(readable_stream);
     63  return JSON.parse(text);
     64 }
     65 
     66 // Check the standard request headers and delete them, leaving any "unique"
     67 // headers to check in the test.
     68 function check_and_remove_standard_headers(headers) {
     69  assert_equals(headers[':scheme'], 'https');
     70  delete headers[':scheme'];
     71  assert_equals(headers[':method'], 'CONNECT');
     72  delete headers[':method'];
     73  assert_equals(headers[':authority'], `${HOST}:${PORT}`);
     74  delete headers[':authority'];
     75  assert_equals(headers[':path'], '/webtransport/handlers/echo-request-headers.py');
     76  delete headers[':path'];
     77  assert_equals(headers[':protocol'], 'webtransport');
     78  delete headers[':protocol'];
     79  assert_equals(headers['origin'], `${get_host_info().ORIGIN}`);
     80  delete headers['origin'];
     81 }
     82 
     83 async function query(token) {
     84  const wt = new WebTransport(webtransport_url(`query.py?token=${token}`));
     85  try {
     86    await wt.ready;
     87    const streams = await wt.incomingUnidirectionalStreams;
     88    const streams_reader = streams.getReader();
     89    const { value: readable } = await streams_reader.read();
     90    streams_reader.releaseLock();
     91 
     92    return await read_stream_as_json(readable);
     93  } finally {
     94    wt.close();
     95  }
     96 }
     97 
     98 async function readInto(reader, buffer) {
     99  let offset = 0;
    100 
    101  while (offset < buffer.byteLength) {
    102    const {value: view, done} = await reader.read(
    103        new Uint8Array(buffer, offset, buffer.byteLength - offset));
    104    buffer = view.buffer;
    105    if (done) {
    106      break;
    107    }
    108    offset += view.byteLength;
    109  }
    110 
    111  return buffer;
    112 }
    113 
    114 // Opens a new WebTransport connection.
    115 async function openWebTransport(remoteContextHelper) {
    116  const url = webtransport_url('custom-response.py?:status=200');
    117  await remoteContextHelper.executeScript((url) => {
    118    window.testWebTransport = new WebTransport(url);
    119    return window.testWebTransport.ready;
    120  }, [url]);
    121 }
    122 
    123 // Opens a new WebTransport connection and then close it.
    124 async function openThenCloseWebTransport(remoteContextHelper) {
    125  const url = webtransport_url('custom-response.py?:status=200');
    126  await remoteContextHelper.executeScript((url) => {
    127    window.testWebTransport = new WebTransport(url);
    128    return window.testWebTransport.ready.then(async () => {
    129      window.testWebTransport.close();
    130      await window.testWebTransport.closed;
    131    });
    132  }, [url]);
    133 }