summaryrefslogtreecommitdiffstats
path: root/testing/web-platform/tests/webtransport/resources/webtransport-test-helpers.sub.js
blob: 36788699e8bbbef020db6620c3e1ac142d6d74b8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
// The file including this must also include /common/get-host-info.sub.js to
// pick up the necessary constants.

const HOST = get_host_info().ORIGINAL_HOST;
const PORT = '{{ports[webtransport-h3][0]}}';
const BASE = `https://${HOST}:${PORT}`;

// Wait for the given number of milliseconds (ms).
function wait(ms) { return new Promise(res => step_timeout(res, ms)); }

// Create URL for WebTransport session.
function webtransport_url(handler) {
  return `${BASE}/webtransport/handlers/${handler}`;
}

// Converts WebTransport stream error code to HTTP/3 error code.
// https://ietf-wg-webtrans.github.io/draft-ietf-webtrans-http3/draft-ietf-webtrans-http3.html#section-4.3
function webtransport_code_to_http_code(n) {
  const first = 0x52e4a40fa8db;
  return first + n + Math.floor(n / 0x1e);
}

// Read all chunks from |readable_stream| and return as an array of arrays
async function read_stream(readable_stream) {
  const reader = readable_stream.getReader();

  let chunks = [];
  while (true) {
    const {value: chunk, done} = await reader.read();
    if (done) {
      break;
    }
    chunks.push(chunk);
  }
  reader.releaseLock();

  return chunks;
}

// Read all chunks from |readable_stream|, decode chunks to a utf-8 string, then
// return the string.
async function read_stream_as_string(readable_stream) {
  const decoder = new TextDecoderStream();
  const decode_stream = readable_stream.pipeThrough(decoder);
  const reader = decode_stream.getReader();

  let chunks = '';
  while (true) {
    const {value: chunk, done} = await reader.read();
    if (done) {
      break;
    }
    chunks += chunk;
  }
  reader.releaseLock();

  return chunks;
}

// Decode all chunks in a given ReadableStream, and parse the data using JSON.
async function read_stream_as_json(readable_stream) {
  const text = await read_stream_as_string(readable_stream);
  return JSON.parse(text);
}

// Check the standard request headers and delete them, leaving any "unique"
// headers to check in the test.
function check_and_remove_standard_headers(headers) {
  assert_equals(headers[':scheme'], 'https');
  delete headers[':scheme'];
  assert_equals(headers[':method'], 'CONNECT');
  delete headers[':method'];
  assert_equals(headers[':authority'], `${HOST}:${PORT}`);
  delete headers[':authority'];
  assert_equals(headers[':path'], '/webtransport/handlers/echo-request-headers.py');
  delete headers[':path'];
  assert_equals(headers[':protocol'], 'webtransport');
  delete headers[':protocol'];
  assert_equals(headers['origin'], `${get_host_info().ORIGIN}`);
  delete headers['origin'];
}

async function query(token) {
  const wt = new WebTransport(webtransport_url(`query.py?token=${token}`));
  try {
    await wt.ready;
    const streams = await wt.incomingUnidirectionalStreams;
    const streams_reader = streams.getReader();
    const { value: readable } = await streams_reader.read();
    streams_reader.releaseLock();

    return await read_stream_as_json(readable);
  } finally {
    wt.close();
  }
}

async function readInto(reader, buffer) {
  let offset = 0;

  while (offset < buffer.byteLength) {
    const {value: view, done} = await reader.read(
        new Uint8Array(buffer, offset, buffer.byteLength - offset));
    buffer = view.buffer;
    if (done) {
      break;
    }
    offset += view.byteLength;
  }

  return buffer;
}

// Opens a new WebTransport connection.
async function openWebTransport(remoteContextHelper) {
  const url = webtransport_url('custom-response.py?:status=200');
  await remoteContextHelper.executeScript((url) => {
    window.testWebTransport = new WebTransport(url);
    return window.testWebTransport.ready;
  }, [url]);
}

// Opens a new WebTransport connection and then close it.
async function openThenCloseWebTransport(remoteContextHelper) {
  const url = webtransport_url('custom-response.py?:status=200');
  await remoteContextHelper.executeScript((url) => {
    window.testWebTransport = new WebTransport(url);
    return window.testWebTransport.ready.then(async () => {
      window.testWebTransport.close();
      await window.testWebTransport.closed;
    });
  }, [url]);
}