1
0
Fork 0
mirror of https://github.com/denoland/deno.git synced 2024-12-22 07:14:47 -05:00

fix(websocket): spec conformance & WPT (#11010)

This commit is contained in:
Leo K 2021-06-21 12:15:08 +02:00 committed by GitHub
parent 952caa79b3
commit afe89e8850
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
4 changed files with 400 additions and 116 deletions

View file

@ -579,6 +579,10 @@
converters.ByteString, converters.ByteString,
); );
converters["sequence<DOMString>"] = createSequenceConverter(
converters.DOMString,
);
function requiredArguments(length, required, opts = {}) { function requiredArguments(length, required, opts = {}) {
if (length < required) { if (length < required) {
const errMsg = `${ const errMsg = `${

View file

@ -3,28 +3,41 @@
((window) => { ((window) => {
const core = window.Deno.core; const core = window.Deno.core;
// provided by "deno_web"
const { URL } = window.__bootstrap.url; const { URL } = window.__bootstrap.url;
const webidl = window.__bootstrap.webidl;
const { HTTP_TOKEN_CODE_POINT_RE } = window.__bootstrap.infra;
webidl.converters["sequence<DOMString> or DOMString"] = (V, opts) => {
// Union for (sequence<DOMString> or DOMString)
if (webidl.type(V) === "Object" && V !== null) {
if (V[Symbol.iterator] !== undefined) {
return webidl.converters["sequence<DOMString>"](V, opts);
}
}
return webidl.converters.DOMString(V, opts);
};
webidl.converters["WebSocketSend"] = (V, opts) => {
// Union for (Blob or ArrayBufferView or ArrayBuffer or USVString)
if (V instanceof Blob) {
return webidl.converters["Blob"](V, opts);
}
if (typeof V === "object") {
if (V instanceof ArrayBuffer || V instanceof SharedArrayBuffer) {
return webidl.converters["ArrayBuffer"](V, opts);
}
if (ArrayBuffer.isView(V)) {
return webidl.converters["ArrayBufferView"](V, opts);
}
}
return webidl.converters["USVString"](V, opts);
};
const CONNECTING = 0; const CONNECTING = 0;
const OPEN = 1; const OPEN = 1;
const CLOSING = 2; const CLOSING = 2;
const CLOSED = 3; const CLOSED = 3;
function requiredArguments(
name,
length,
required,
) {
if (length < required) {
const errMsg = `${name} requires at least ${required} argument${
required === 1 ? "" : "s"
}, but only ${length} present`;
throw new TypeError(errMsg);
}
}
/** /**
* Tries to close the resource (and ignores BadResource errors). * Tries to close the resource (and ignores BadResource errors).
* @param {number} rid * @param {number} rid
@ -74,14 +87,104 @@
}); });
} }
const _readyState = Symbol("[[readyState]]");
const _url = Symbol("[[url]]");
const _rid = Symbol("[[rid]]");
const _extensions = Symbol("[[extensions]]");
const _protocol = Symbol("[[protocol]]");
const _binaryType = Symbol("[[binaryType]]");
const _bufferedAmount = Symbol("[[bufferedAmount]]");
class WebSocket extends EventTarget { class WebSocket extends EventTarget {
#readyState = CONNECTING; [_rid];
[_readyState] = CONNECTING;
get readyState() {
webidl.assertBranded(this, WebSocket);
return this[_readyState];
}
get CONNECTING() {
webidl.assertBranded(this, WebSocket);
return CONNECTING;
}
get OPEN() {
webidl.assertBranded(this, WebSocket);
return OPEN;
}
get CLOSING() {
webidl.assertBranded(this, WebSocket);
return CLOSING;
}
get CLOSED() {
webidl.assertBranded(this, WebSocket);
return CLOSED;
}
[_extensions] = "";
get extensions() {
webidl.assertBranded(this, WebSocket);
return this[_extensions];
}
[_protocol] = "";
get protocol() {
webidl.assertBranded(this, WebSocket);
return this[_protocol];
}
[_url] = "";
get url() {
webidl.assertBranded(this, WebSocket);
return this[_url];
}
[_binaryType] = "blob";
get binaryType() {
webidl.assertBranded(this, WebSocket);
return this[_binaryType];
}
set binaryType(value) {
webidl.assertBranded(this, WebSocket);
value = webidl.converters.DOMString(value, {
prefix: "Failed to set 'binaryType' on 'WebSocket'",
});
if (value === "blob" || value === "arraybuffer") {
this[_binaryType] = value;
}
}
[_bufferedAmount] = 0;
get bufferedAmount() {
webidl.assertBranded(this, WebSocket);
return this[_bufferedAmount];
}
constructor(url, protocols = []) { constructor(url, protocols = []) {
super(); super();
requiredArguments("WebSocket", arguments.length, 1); this[webidl.brand] = webidl.brand;
const prefix = "Failed to construct 'WebSocket'";
webidl.requiredArguments(arguments.length, 1, {
prefix,
});
url = webidl.converters.USVString(url, {
prefix,
context: "Argument 1",
});
protocols = webidl.converters["sequence<DOMString> or DOMString"](
protocols,
{
prefix,
context: "Argument 2",
},
);
const wsURL = new URL(url); let wsURL;
try {
wsURL = new URL(url);
} catch (e) {
throw new DOMException(e.message, "SyntaxError");
}
if (wsURL.protocol !== "ws:" && wsURL.protocol !== "wss:") { if (wsURL.protocol !== "ws:" && wsURL.protocol !== "wss:") {
throw new DOMException( throw new DOMException(
@ -97,16 +200,16 @@
); );
} }
this.#url = wsURL.href; this[_url] = wsURL.href;
core.opSync("op_ws_check_permission", this.#url); core.opSync("op_ws_check_permission", this[_url]);
if (protocols && typeof protocols === "string") { if (typeof protocols === "string") {
protocols = [protocols]; protocols = [protocols];
} }
if ( if (
protocols.some((x) => protocols.indexOf(x) !== protocols.lastIndexOf(x)) protocols.length !== new Set(protocols.map((p) => p.toLowerCase())).size
) { ) {
throw new DOMException( throw new DOMException(
"Can't supply multiple times the same protocol.", "Can't supply multiple times the same protocol.",
@ -114,19 +217,28 @@
); );
} }
if (
protocols.some((protocol) => !HTTP_TOKEN_CODE_POINT_RE.test(protocol))
) {
throw new DOMException(
"Invalid protocol value.",
"SyntaxError",
);
}
core.opAsync("op_ws_create", { core.opAsync("op_ws_create", {
url: wsURL.href, url: wsURL.href,
protocols: protocols.join(", "), protocols: protocols.join(", "),
}).then((create) => { }).then((create) => {
this.#rid = create.rid; this[_rid] = create.rid;
this.#extensions = create.extensions; this[_extensions] = create.extensions;
this.#protocol = create.protocol; this[_protocol] = create.protocol;
if (this.#readyState === CLOSING) { if (this[_readyState] === CLOSING) {
core.opAsync("op_ws_close", { core.opAsync("op_ws_close", {
rid: this.#rid, rid: this[_rid],
}).then(() => { }).then(() => {
this.#readyState = CLOSED; this[_readyState] = CLOSED;
const errEvent = new ErrorEvent("error"); const errEvent = new ErrorEvent("error");
errEvent.target = this; errEvent.target = this;
@ -135,10 +247,10 @@
const event = new CloseEvent("close"); const event = new CloseEvent("close");
event.target = this; event.target = this;
this.dispatchEvent(event); this.dispatchEvent(event);
tryClose(this.#rid); tryClose(this[_rid]);
}); });
} else { } else {
this.#readyState = OPEN; this[_readyState] = OPEN;
const event = new Event("open"); const event = new Event("open");
event.target = this; event.target = this;
this.dispatchEvent(event); this.dispatchEvent(event);
@ -146,7 +258,7 @@
this.#eventLoop(); this.#eventLoop();
} }
}).catch((err) => { }).catch((err) => {
this.#readyState = CLOSED; this[_readyState] = CLOSED;
const errorEv = new ErrorEvent( const errorEv = new ErrorEvent(
"error", "error",
@ -161,67 +273,29 @@
}); });
} }
get CONNECTING() {
return CONNECTING;
}
get OPEN() {
return OPEN;
}
get CLOSING() {
return CLOSING;
}
get CLOSED() {
return CLOSED;
}
get readyState() {
return this.#readyState;
}
#extensions = "";
#protocol = "";
#url = "";
#rid;
get extensions() {
return this.#extensions;
}
get protocol() {
return this.#protocol;
}
#binaryType = "blob";
get binaryType() {
return this.#binaryType;
}
set binaryType(value) {
if (value === "blob" || value === "arraybuffer") {
this.#binaryType = value;
}
}
#bufferedAmount = 0;
get bufferedAmount() {
return this.#bufferedAmount;
}
get url() {
return this.#url;
}
send(data) { send(data) {
requiredArguments("WebSocket.send", arguments.length, 1); webidl.assertBranded(this, WebSocket);
const prefix = "Failed to execute 'send' on 'WebSocket'";
if (this.#readyState != OPEN) { webidl.requiredArguments(arguments.length, 1, {
throw Error("readyState not OPEN"); prefix,
});
data = webidl.converters.WebSocketSend(data, {
prefix,
context: "Argument 1",
});
if (this[_readyState] !== OPEN) {
throw new DOMException("readyState not OPEN", "InvalidStateError");
} }
const sendTypedArray = (ta) => { const sendTypedArray = (ta) => {
this.#bufferedAmount += ta.size; this[_bufferedAmount] += ta.byteLength;
core.opAsync("op_ws_send", { core.opAsync("op_ws_send", {
rid: this.#rid, rid: this[_rid],
kind: "binary", kind: "binary",
}, ta).then(() => { }, ta).then(() => {
this.#bufferedAmount -= ta.size; this[_bufferedAmount] -= ta.byteLength;
}); });
}; };
@ -229,80 +303,94 @@
data.slice().arrayBuffer().then((ab) => data.slice().arrayBuffer().then((ab) =>
sendTypedArray(new DataView(ab)) sendTypedArray(new DataView(ab))
); );
} else if ( } else if (ArrayBuffer.isView(data)) {
data instanceof Int8Array || data instanceof Int16Array ||
data instanceof Int32Array || data instanceof Uint8Array ||
data instanceof Uint16Array || data instanceof Uint32Array ||
data instanceof Uint8ClampedArray || data instanceof Float32Array ||
data instanceof Float64Array || data instanceof DataView
) {
sendTypedArray(data); sendTypedArray(data);
} else if (data instanceof ArrayBuffer) { } else if (data instanceof ArrayBuffer) {
sendTypedArray(new DataView(data)); sendTypedArray(new DataView(data));
} else { } else {
const string = String(data); const string = String(data);
const d = core.encode(string); const d = core.encode(string);
this.#bufferedAmount += d.size; this[_bufferedAmount] += d.byteLength;
core.opAsync("op_ws_send", { core.opAsync("op_ws_send", {
rid: this.#rid, rid: this[_rid],
kind: "text", kind: "text",
text: string, text: string,
}).then(() => { }).then(() => {
this.#bufferedAmount -= d.size; this[_bufferedAmount] -= d.byteLength;
}); });
} }
} }
close(code, reason) { close(code = undefined, reason = undefined) {
if (code && !(code === 1000 || (3000 <= code && code < 5000))) { webidl.assertBranded(this, WebSocket);
const prefix = "Failed to execute 'close' on 'WebSocket'";
if (code !== undefined) {
code = webidl.converters["unsigned short"](code, {
prefix,
clamp: true,
context: "Argument 1",
});
}
if (reason !== undefined) {
reason = webidl.converters.USVString(reason, {
prefix,
context: "Argument 2",
});
}
if (
code !== undefined && !(code === 1000 || (3000 <= code && code < 5000))
) {
throw new DOMException( throw new DOMException(
"The close code must be either 1000 or in the range of 3000 to 4999.", "The close code must be either 1000 or in the range of 3000 to 4999.",
"NotSupportedError", "InvalidAccessError",
); );
} }
if (reason && core.encode(reason).byteLength > 123) { if (reason !== undefined && core.encode(reason).byteLength > 123) {
throw new DOMException( throw new DOMException(
"The close reason may not be longer than 123 bytes.", "The close reason may not be longer than 123 bytes.",
"SyntaxError", "SyntaxError",
); );
} }
if (this.#readyState === CONNECTING) { if (this[_readyState] === CONNECTING) {
this.#readyState = CLOSING; this[_readyState] = CLOSING;
} else if (this.#readyState === OPEN) { } else if (this[_readyState] === OPEN) {
this.#readyState = CLOSING; this[_readyState] = CLOSING;
core.opAsync("op_ws_close", { core.opAsync("op_ws_close", {
rid: this.#rid, rid: this[_rid],
code, code,
reason, reason,
}).then(() => { }).then(() => {
this.#readyState = CLOSED; this[_readyState] = CLOSED;
const event = new CloseEvent("close", { const event = new CloseEvent("close", {
wasClean: true, wasClean: true,
code, code: code ?? 1005,
reason, reason,
}); });
event.target = this; event.target = this;
this.dispatchEvent(event); this.dispatchEvent(event);
tryClose(this.#rid); tryClose(this[_rid]);
}); });
} }
} }
async #eventLoop() { async #eventLoop() {
while (this.#readyState === OPEN) { while (this[_readyState] === OPEN) {
const { kind, value } = await core.opAsync( const { kind, value } = await core.opAsync(
"op_ws_next_event", "op_ws_next_event",
this.#rid, this[_rid],
); );
switch (kind) { switch (kind) {
case "string": { case "string": {
const event = new MessageEvent("message", { const event = new MessageEvent("message", {
data: value, data: value,
origin: this.#url, origin: this[_url],
}); });
event.target = this; event.target = this;
this.dispatchEvent(event); this.dispatchEvent(event);
@ -319,7 +407,7 @@
const event = new MessageEvent("message", { const event = new MessageEvent("message", {
data, data,
origin: this.#url, origin: this[_url],
}); });
event.target = this; event.target = this;
this.dispatchEvent(event); this.dispatchEvent(event);
@ -327,13 +415,13 @@
} }
case "ping": { case "ping": {
core.opAsync("op_ws_send", { core.opAsync("op_ws_send", {
rid: this.#rid, rid: this[_rid],
kind: "pong", kind: "pong",
}); });
break; break;
} }
case "close": { case "close": {
this.#readyState = CLOSED; this[_readyState] = CLOSED;
const event = new CloseEvent("close", { const event = new CloseEvent("close", {
wasClean: true, wasClean: true,
@ -342,11 +430,11 @@
}); });
event.target = this; event.target = this;
this.dispatchEvent(event); this.dispatchEvent(event);
tryClose(this.#rid); tryClose(this[_rid]);
break; break;
} }
case "error": { case "error": {
this.#readyState = CLOSED; this[_readyState] = CLOSED;
const errorEv = new ErrorEvent("error", { const errorEv = new ErrorEvent("error", {
message: value, message: value,
@ -357,7 +445,7 @@
const closeEv = new CloseEvent("close"); const closeEv = new CloseEvent("close");
closeEv.target = this; closeEv.target = this;
this.dispatchEvent(closeEv); this.dispatchEvent(closeEv);
tryClose(this.#rid); tryClose(this[_rid]);
break; break;
} }
} }
@ -385,5 +473,7 @@
defineEventHandler(WebSocket.prototype, "close"); defineEventHandler(WebSocket.prototype, "close");
defineEventHandler(WebSocket.prototype, "open"); defineEventHandler(WebSocket.prototype, "open");
webidl.configurePrototype(WebSocket);
window.__bootstrap.webSocket = { WebSocket }; window.__bootstrap.webSocket = { WebSocket };
})(this); })(this);

View file

@ -1,6 +1,11 @@
{ {
"check_subdomains": false, "check_subdomains": false,
"ssl": { "ssl": {
"type": "pregenerated" "type": "pregenerated",
"pregenerated": {
"ca_cert_path": "../../tools/wpt/certs/cacert.pem",
"host_cert_path": "../../tools/wpt/certs/web-platform.test.pem",
"host_key_path": "../../tools/wpt/certs/web-platform.test.key"
}
} }
} }

View file

@ -1023,5 +1023,190 @@
"set-blob.any.html": true, "set-blob.any.html": true,
"set.any.html": true "set.any.html": true
} }
},
"websockets": {
"Close-1000-reason.any.html": true,
"Close-1000-reason.any.html?wpt_flags=h2": false,
"Close-1000-reason.any.html?wss": true,
"Close-1000-verify-code.any.html": true,
"Close-1000-verify-code.any.html?wpt_flags=h2": false,
"Close-1000-verify-code.any.html?wss": true,
"Close-1000.any.html": true,
"Close-1000.any.html?wpt_flags=h2": false,
"Close-1000.any.html?wss": true,
"Close-1005-verify-code.any.html": true,
"Close-1005-verify-code.any.html?wpt_flags=h2": false,
"Close-1005-verify-code.any.html?wss": true,
"Close-1005.any.html": true,
"Close-1005.any.html?wpt_flags=h2": false,
"Close-1005.any.html?wss": true,
"Close-2999-reason.any.html": true,
"Close-2999-reason.any.html?wpt_flags=h2": false,
"Close-2999-reason.any.html?wss": true,
"Close-3000-reason.any.html": true,
"Close-3000-reason.any.html?wpt_flags=h2": false,
"Close-3000-reason.any.html?wss": true,
"Close-3000-verify-code.any.html": true,
"Close-3000-verify-code.any.html?wpt_flags=h2": false,
"Close-3000-verify-code.any.html?wss": true,
"Close-4999-reason.any.html": true,
"Close-4999-reason.any.html?wpt_flags=h2": false,
"Close-4999-reason.any.html?wss": true,
"Close-Reason-124Bytes.any.html": true,
"Close-Reason-124Bytes.any.html?wpt_flags=h2": false,
"Close-Reason-124Bytes.any.html?wss": true,
"Close-onlyReason.any.html": true,
"Close-onlyReason.any.html?wpt_flags=h2": false,
"Close-onlyReason.any.html?wss": true,
"Close-readyState-Closed.any.html": true,
"Close-readyState-Closed.any.html?wpt_flags=h2": false,
"Close-readyState-Closed.any.html?wss": true,
"Close-readyState-Closing.any.html": true,
"Close-readyState-Closing.any.html?wpt_flags=h2": false,
"Close-readyState-Closing.any.html?wss": true,
"Close-reason-unpaired-surrogates.any.html": true,
"Close-reason-unpaired-surrogates.any.html?wpt_flags=h2": false,
"Close-reason-unpaired-surrogates.any.html?wss": true,
"Close-server-initiated-close.any.html": true,
"Close-server-initiated-close.any.html?wpt_flags=h2": false,
"Close-server-initiated-close.any.html?wss": true,
"Close-undefined.any.html": true,
"Close-undefined.any.html?wpt_flags=h2": false,
"Close-undefined.any.html?wss": true,
"Create-asciiSep-protocol-string.any.html": true,
"Create-asciiSep-protocol-string.any.html?wpt_flags=h2": true,
"Create-asciiSep-protocol-string.any.html?wss": true,
"Create-blocked-port.any.html": true,
"Create-blocked-port.any.html?wpt_flags=h2": [
"Basic check"
],
"Create-blocked-port.any.html?wss": true,
"Create-extensions-empty.any.html": true,
"Create-extensions-empty.any.html?wpt_flags=h2": false,
"Create-extensions-empty.any.html?wss": true,
"Create-invalid-urls.any.html": true,
"Create-invalid-urls.any.html?wpt_flags=h2": true,
"Create-invalid-urls.any.html?wss": true,
"Create-non-absolute-url.any.html": true,
"Create-non-absolute-url.any.html?wpt_flags=h2": true,
"Create-non-absolute-url.any.html?wss": true,
"Create-nonAscii-protocol-string.any.html": true,
"Create-nonAscii-protocol-string.any.html?wpt_flags=h2": true,
"Create-nonAscii-protocol-string.any.html?wss": true,
"Create-on-worker-shutdown.any.html": false,
"Create-protocol-with-space.any.html": true,
"Create-protocol-with-space.any.html?wpt_flags=h2": true,
"Create-protocol-with-space.any.html?wss": true,
"Create-protocols-repeated-case-insensitive.any.html": true,
"Create-protocols-repeated-case-insensitive.any.html?wpt_flags=h2": true,
"Create-protocols-repeated-case-insensitive.any.html?wss": true,
"Create-protocols-repeated.any.html": true,
"Create-protocols-repeated.any.html?wpt_flags=h2": true,
"Create-protocols-repeated.any.html?wss": true,
"Create-url-with-space.any.html": true,
"Create-url-with-space.any.html?wpt_flags=h2": true,
"Create-url-with-space.any.html?wss": true,
"Create-valid-url-array-protocols.any.html": true,
"Create-valid-url-array-protocols.any.html?wpt_flags=h2": false,
"Create-valid-url-array-protocols.any.html?wss": true,
"Create-valid-url-binaryType-blob.any.html": true,
"Create-valid-url-binaryType-blob.any.html?wpt_flags=h2": false,
"Create-valid-url-binaryType-blob.any.html?wss": true,
"Create-valid-url-protocol-empty.any.html": true,
"Create-valid-url-protocol-empty.any.html?wpt_flags=h2": true,
"Create-valid-url-protocol-empty.any.html?wss": true,
"Create-valid-url-protocol-setCorrectly.any.html": true,
"Create-valid-url-protocol-setCorrectly.any.html?wpt_flags=h2": false,
"Create-valid-url-protocol-setCorrectly.any.html?wss": true,
"Create-valid-url-protocol-string.any.html": true,
"Create-valid-url-protocol-string.any.html?wpt_flags=h2": false,
"Create-valid-url-protocol-string.any.html?wss": true,
"Create-valid-url-protocol.any.html": true,
"Create-valid-url-protocol.any.html?wpt_flags=h2": false,
"Create-valid-url-protocol.any.html?wss": true,
"Create-valid-url.any.html": true,
"Create-valid-url.any.html?wpt_flags=h2": false,
"Create-valid-url.any.html?wss": true,
"Create-wrong-scheme.any.html": true,
"Create-wrong-scheme.any.html?wpt_flags=h2": true,
"Create-wrong-scheme.any.html?wss": true,
"Send-0byte-data.any.html": true,
"Send-0byte-data.any.html?wpt_flags=h2": false,
"Send-0byte-data.any.html?wss": true,
"Send-65K-data.any.html": true,
"Send-65K-data.any.html?wpt_flags=h2": false,
"Send-65K-data.any.html?wss": true,
"Send-before-open.any.html": true,
"Send-before-open.any.html?wpt_flags=h2": true,
"Send-before-open.any.html?wss": true,
"Send-binary-65K-arraybuffer.any.html": true,
"Send-binary-65K-arraybuffer.any.html?wpt_flags=h2": false,
"Send-binary-65K-arraybuffer.any.html?wss": true,
"Send-binary-arraybuffer.any.html": true,
"Send-binary-arraybuffer.any.html?wpt_flags=h2": false,
"Send-binary-arraybuffer.any.html?wss": true,
"Send-binary-arraybufferview-float32.any.html": true,
"Send-binary-arraybufferview-float32.any.html?wpt_flags=h2": false,
"Send-binary-arraybufferview-float32.any.html?wss": true,
"Send-binary-arraybufferview-float64.any.html": true,
"Send-binary-arraybufferview-float64.any.html?wpt_flags=h2": false,
"Send-binary-arraybufferview-float64.any.html?wss": true,
"Send-binary-arraybufferview-int16-offset.any.html": true,
"Send-binary-arraybufferview-int16-offset.any.html?wpt_flags=h2": false,
"Send-binary-arraybufferview-int16-offset.any.html?wss": true,
"Send-binary-arraybufferview-int32.any.html": true,
"Send-binary-arraybufferview-int32.any.html?wpt_flags=h2": false,
"Send-binary-arraybufferview-int32.any.html?wss": true,
"Send-binary-arraybufferview-int8.any.html": true,
"Send-binary-arraybufferview-int8.any.html?wpt_flags=h2": false,
"Send-binary-arraybufferview-int8.any.html?wss": true,
"Send-binary-arraybufferview-uint16-offset-length.any.html": true,
"Send-binary-arraybufferview-uint16-offset-length.any.html?wpt_flags=h2": false,
"Send-binary-arraybufferview-uint16-offset-length.any.html?wss": true,
"Send-binary-arraybufferview-uint32-offset.any.html": true,
"Send-binary-arraybufferview-uint32-offset.any.html?wpt_flags=h2": false,
"Send-binary-arraybufferview-uint32-offset.any.html?wss": true,
"Send-binary-arraybufferview-uint8-offset-length.any.html": true,
"Send-binary-arraybufferview-uint8-offset-length.any.html?wpt_flags=h2": false,
"Send-binary-arraybufferview-uint8-offset-length.any.html?wss": true,
"Send-binary-arraybufferview-uint8-offset.any.html": true,
"Send-binary-arraybufferview-uint8-offset.any.html?wpt_flags=h2": false,
"Send-binary-arraybufferview-uint8-offset.any.html?wss": true,
"Send-binary-blob.any.html": true,
"Send-binary-blob.any.html?wpt_flags=h2": false,
"Send-binary-blob.any.html?wss": true,
"Send-data.any.html": true,
"Send-data.any.html?wpt_flags=h2": false,
"Send-data.any.html?wss": true,
"Send-null.any.html": true,
"Send-null.any.html?wpt_flags=h2": false,
"Send-null.any.html?wss": true,
"Send-paired-surrogates.any.html": true,
"Send-paired-surrogates.any.html?wpt_flags=h2": false,
"Send-paired-surrogates.any.html?wss": true,
"Send-unicode-data.any.html": true,
"Send-unicode-data.any.html?wpt_flags=h2": false,
"Send-unicode-data.any.html?wss": true,
"Send-unpaired-surrogates.any.html": true,
"Send-unpaired-surrogates.any.html?wpt_flags=h2": false,
"Send-unpaired-surrogates.any.html?wss": true,
"basic-auth.any.html?wpt_flags=h2": false,
"basic-auth.any.html?wss": false,
"binaryType-wrong-value.any.html": true,
"binaryType-wrong-value.any.html?wpt_flags=h2": false,
"binaryType-wrong-value.any.html?wss": true,
"bufferedAmount-unchanged-by-sync-xhr.any.html": false,
"bufferedAmount-unchanged-by-sync-xhr.any.html?wpt_flags=h2": false,
"bufferedAmount-unchanged-by-sync-xhr.any.html?wss": false,
"close-invalid.any.html": true,
"close-invalid.any.html?wpt_flags=h2": true,
"close-invalid.any.html?wss": true,
"constructor.any.html": true,
"constructor.any.html?wpt_flags=h2": true,
"constructor.any.html?wss": true,
"eventhandlers.any.html": false,
"eventhandlers.any.html?wpt_flags=h2": false,
"eventhandlers.any.html?wss": false,
"referrer.any.html": true
} }
} }