-
Notifications
You must be signed in to change notification settings - Fork 31
Open
Description
During testing.
Server. bun build --target=browser --packages=bundle ./node_modules/@fails-components/webtransport/lib/index.node.js --outfile=webtransport-bundle.js. Add node: specifiers where they don't exist in
import { Http3Server } from "./webtransport-bundle.js";
import certificates from "../cert.json" with { type: "json" };
let requests = 0;
const server = new Http3Server({
port: 8080,
host: "127.0.0.1",
secret: certificates[0].secret,
cert: certificates[0].pem,
privKey: certificates[0].privateKey,
});
await server.startServer();
await server.ready;
console.info("server started");
const address = server.address();
const sessionStream = server.sessionStream("/");
const sessionReader = sessionStream.getReader();
while (true) {
const { value: session, done } = await sessionReader.read();
if (done) {
break;
}
console.log(session.closed);
let incomingTotalLength = 0;
let incomingCurrentLength = 0;
const buffer = new ArrayBuffer(0, { maxByteLength: 4 });
const view = new DataView(buffer);
const encoder = new TextEncoder();
const decoder = new TextDecoder();
for await (
const { readable, writable } of session.incomingBidirectionalStreams
) {
const writer = writable.getWriter();
await readable
.pipeTo(
new WritableStream({
async write(value) {
if (incomingTotalLength === 0 && incomingCurrentLength === 0) {
buffer.resize(4);
for (let i = 0; i < 4; i++) {
view.setUint8(i, value[i]);
}
incomingTotalLength = view.getUint32(0, true);
console.log(value.length, incomingTotalLength);
value = value.subarray(4);
}
const encoded = encoder.encode(
decoder.decode(value).toUpperCase(),
);
await writer.ready;
await writer.write(encoded);
await writer.ready; //.then(() => console.log(`Done writing ${encoded.length} to writable, ${} total bytes written.`));
incomingCurrentLength += encoded.length;
console.log(
`Done writing ${encoded.length} bytes to writable, ${incomingCurrentLength} of ${incomingTotalLength} bytes written.`,
);
},
close() {
console.log("readable closed");
},
}),
).then(() => console.log("pipeTo() done"))
.catch((e) => console.log(e));
buffer.resize(0);
incomingTotalLength = 0;
incomingCurrentLength = 0;
}
await session.closed.then(() => ({
code: 5000,
reason: `Done streaming request ${requests++}`,
})).then((res) => console.log(res)).catch((e) => e.message);
}
Client (Chromium 137). One session, multiple streams. Starting with 7 MB. When done with session execute client.close({ closeCode: 5000, reason: "Done streaming" });
const serverCertificateHashes = [{
"algorithm": "sha-256",
"value": Uint8Array.of(1,2,3,4,... ), // Hard coded, once
}, ];
// Use Deno's WebTransport client in Deno, which doesn't support webtransport.node
if (!/Deno|Chrome|Firefox/i.test(navigator.userAgent)) {
let {WebTransport, quicheLoaded} = await import("./node_modules/@fails-components/webtransport/lib/index.node.js");
await quicheLoaded;
globalThis.WebTransport = WebTransport;
}
async function createStream(wt, data) {
const abortable = new AbortController();
const {signal} = abortable;
const {readable, writable} = await wt.createBidirectionalStream();
let header = new Uint8Array(Uint32Array.from({
length: 4,
}, (_, index) => (data.length >> (index * 8)) & 0xff, ));
let view = new DataView(header.buffer);
let outgoingTotalLength = view.getUint32(0, true);
console.log({
outgoingTotalLength
});
let incomingTotalLength = 0;
const writer = writable.getWriter();
await writer.ready;
await writer.write(header).then( () => console.log(`Outgoing total length ${outgoingTotalLength} written.`));
await writer.ready;
await writer.write(data).then( () => console.log(`${data.length} bytes written.`)).catch( (e) => console.log(e));
await writer.ready;
for await(const value of readable.pipeThrough(new TextDecoderStream())) {
console.log(incomingTotalLength += value.length);
if (incomingTotalLength === outgoingTotalLength) {
await writer.ready;
await writer.close().catch( (e) => {}
);
await writer.closed;
writer.releaseLock();
break;
}
}
console.log(readable.locked);
return "Session done";
}
const client = new WebTransport(`https://127.0.0.1:8080`,{
serverCertificateHashes,
},);
client.closed.then(console.log).catch(console.log);
await client.ready;
const encoder = new TextEncoder();
var data = encoder.encode("x".repeat((1024 ** 2) * 7)); // 7MB
var res = await createStream(client, data); // "Session done"
// client.close({ closeCode: 5000, reason: "Done streaming" });
console.log(res);
Everything works as expected.
Write an empty Uint8Array
var res = await createStream(client, new Uint8Array());
// client.close({ closeCode: 5000, reason: "Done streaming" });
console.log(res);
What happens in the server
E0418 03:33:32.101059 46669 quic_stream.cc:823] quic_bug_10586_6: span.empty() && !fin
Thereafter the session is frozen.
Write 1 MB
var res = await createStream(client, new Uint8Array(1024**2));
// client.close({ closeCode: 5000, reason: "Done streaming" });
console.log(res);
Nothing happens in the server
Metadata
Metadata
Assignees
Labels
No labels


