WebTransport connection rejected using self-signed certificates
Categories
(Core :: Networking, defect, P3)
Tracking
()
People
(Reporter: guest271314, Unassigned)
References
(Blocks 1 open bug)
Details
(Whiteboard: [necko-triaged])
Attachments
(13 files)
|
4.91 KB,
text/plain
|
Details | |
|
140.37 KB,
image/png
|
Details | |
|
93.18 KB,
image/png
|
Details | |
|
64.76 KB,
image/png
|
Details | |
|
146.15 KB,
image/png
|
Details | |
|
3.09 KB,
text/plain
|
Details | |
|
2.45 KB,
text/plain
|
Details | |
|
73.46 KB,
image/png
|
Details | |
|
52.75 KB,
image/png
|
Details | |
|
512.30 KB,
text/javascript
|
Details | |
|
34.12 KB,
image/png
|
Details | |
|
719.25 KB,
application/octet-stream
|
Details | |
|
129.68 KB,
image/png
|
Details |
User Agent: Mozilla/5.0 (X11; Linux x86_64; rv:138.0) Gecko/20100101 Firefox/138.0
Steps to reproduce:
In about:config set
security.pki.certificate_transparency.disable_for_hosts https://localhost:4433/path
and
security.pki.certificate_transparency.disable_for_spki_hashes <hash>
In Chromium Version 136.0.7087.0 (Developer Build) (64-bit) I use the follow command line flag when launching chrome
--ignore-certificate-errors-spki-list=<hash>
Start local WebTransport server using self-signed certificates
deno -A --unstable-net wt-server.js
// Copyright 2018-2024 the Deno authors. All rights reserved. MIT license.
// https://raw.githubusercontent.com/denoland/deno/dce204af32e4b56681be4f9a034256d979a3ce4b/tests/specs/run/webtransport/main.ts
//import { decodeBase64 } from "jsr:@std/encoding/base64";
//import { assertEqual } from "jsr:@std/assert";
const cert = Deno.readTextFileSync("./certificate.pem");
const key = Deno.readTextFileSync("./certificate.key");
const certBase64 = cert.split("\n").slice(1, -2).join("");
const certBytes =
await (await fetch(`data:application/octet-stream;base64,${certBase64}`))
.bytes();
const certHash = await crypto.subtle.digest("SHA-256", certBytes);
const server = new Deno.QuicEndpoint({
hostname: "localhost",
port: 4433,
});
const listener = server.listen({
cert,
key,
alpnProtocols: ["h3"],
});
let requests = 0;
async function handle(wt) {
try {
console.log(wt);
const encoder = new TextEncoder();
await wt.ready;
for await (
const { readable, writable } of wt.incomingBidirectionalStreams
) {
for await (const value of readable.pipeThrough(new TextDecoderStream())) {
console.log(value);
await new Response(value.toUpperCase()).body
.pipeTo(writable, { preventClose: true });
}
await writable.close().then(() => console.log("writable close"));
console.log(writable);
await new Promise((r) => setTimeout(r));
wt.close();
break;
}
} catch (e) {
console.log(e);
console.trace();
} finally {
return wt.closed.then(() => ({
code: 0,
reason: `Done streaming request ${requests++}`,
}));
}
}
for await (const conn of listener) {
const wt = await Deno.upgradeWebTransport(conn);
try {
handle(wt)
.then((promise) => console.log(promise))
.catch(console.error);
} catch (e) {
console.log(e);
} finally {
continue;
}
}
server.close();
Make request from console
(async () => {
try {
const client = new WebTransport(
`https://localhost:4433/path`,
);
await client.ready;
const encoder = new TextEncoder();
let controller;
const abortable = new AbortController();
const {
signal,
} = abortable;
const {
readable,
writable
} = await client.createBidirectionalStream();
// const writer = writable.getWriter();
const stream = readable.pipeThrough(new TextDecoderStream())
.pipeTo(
new WritableStream({
start(c) {
controller = c;
},
write(value, c) {
//console.log(c.desiredSize);
console.log(value);
},
close() {
console.log("WritableStream close");
},
abort(reason) {
console.log({
reason
});
},
}, {
highWaterMark: 1
}), //,
{
signal
},
).catch((e) => e.message);
let str = "abcdefghijklmnopqrstuvwxyz";
/*
for (let i = 0; i < 26; i++) {
let preventClose = i < str.length - 1;
await new Response(encoder.encode(str.at(i))).body
.pipeTo(writable, { preventClose })
}
*/
await new Response(encoder.encode("x".repeat(1024 ** 2))).body
.pipeTo(writable);
if (!navigator.userAgent.includes("Deno")) {
await Promise.allSettled([client.closed, stream])
.then(console.log);
} else {
if (navigator.userAgent.includes("Deno")) {
// Deno doesn't close on writer.close()
await new Promise((r) => setTimeout(r, 7));
//console.log(abortable);
client.close();
await Promise.allSettled([client.closed, stream])
.then(console.log);
}
}
} catch (e) {
console.log(e);
}
})().catch(console.log);
Actual results:
Uncaught (in promise)
WebTransportError { source: "session", streamErrorCode: null, name: "WebTransportError", message: "WebTransport connection rejected", code: 0, result: 0, filename: "", lineNumber: 0, columnNumber: 0, data: null }
code: 0
columnNumber: 0
data: null
filename: ""
lineNumber: 0
message: "WebTransport connection rejected"
name: "WebTransportError"
result: 0
source: "session"
stack: ""
streamErrorCode: null
<prototype>: WebTransportErrorPrototype { source: Getter, streamErrorCode: Getter, stack: "", … }
Expected results:
Chromium 136 at console
... XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
VM37:30
{reason: WebTransportError: Connection lost.}
(2) [{…}, {…}]
0
:
{status: 'rejected', reason: WebTransportError: Connection lost.}
1
:
{status: 'fulfilled', value: 'Connection lost.'}
length
:
2
[[Prototype]]
:
Array(0)
Comment 1•9 months ago
|
||
The Bugbug bot thinks this bug should belong to the 'Core::Security: PSM' component, and is moving the bug to that component. Please correct in case you think the bot is wrong.
Comment 2•9 months ago
|
||
Firefox doesn't have an equivalent to Chrome's --ignore-certificate-errors-spki-list option. You'll need to use something like mkcert (https://github.com/FiloSottile/mkcert) to create a trusted certificate authority to issue your server's certificate.
| Reporter | ||
Comment 3•9 months ago
|
||
So there's basically no way to use WebTransport on Firefox for exclusive local usage without getting some remote "trusted certificate authority" involved?
| Reporter | ||
Comment 4•9 months ago
|
||
Using this https://github.com/achingbrain/webtransport-echo-server/blob/main/index.js#L2-L37 approach with Deno's WebTransport server
import certificates from "./cert.json" with {type:"json"};
const serverCertificateHashes = [{
algorithm: 'sha-256',
value: Uint8Array.from(atob(btoa(String.fromCodePoint(...certificates[0].hash.digest))), (m) => m.codePointAt(0))
}];
const server = new Deno.QuicEndpoint({
hostname: "localhost",
port: 4433,
});
const listener = server.listen({
cert: certificates[0].pem,
key: certificates[0].privateKey,
alpnProtocols: ["h3"],
});
const serverCertificateHashes = [{
algorithm: 'sha-256',
value: Uint8Array.from(atob(btoa(String.fromCodePoint(...certificates[0].hash.digest))), (m) => m.codePointAt(0))
}];
const client = new WebTransport(
`https://localhost:4433/path`,
{
serverCertificateHashes,
},
);
works just fine in Chromium Version 136.0.7088.0 (Developer Build) (64-bit). Not In Firefox Nightly 138.0a1 (2025-03-24) (64-bit).
WebTransport on Firefox appears to basically be unusable. At least without burrowing under or leaping over N hurdles.
| Comment hidden (off-topic) |
| Comment hidden (off-topic) |
| Reporter | ||
Comment 7•9 months ago
|
||
mkcert creates a local certificate authority on your device - it's not remote.
I did that. Using the code @fail-components/webtransport uses. Firefox still fails to do anything but hand communicating with a Deno WebTransport server. Screenshot.
See https://github.com/fails-components/webtransport/issues/265#issuecomment-2750190849.
After I compiled the certificates.js to a single bundle I converted the resulting JavaScript object to JSON, so I only have to do that once. E.g.,
const certificates = [
{
"privateKey": "-----BEGIN PRIVATE KEY ...
import certificates from "./cert.json" with { type: "json" };
const serverCertificateHashes = [{
algorithm: "sha-256",
value: Uint8Array.from(
atob(btoa(String.fromCodePoint(...certificates[0].hash.digest))),
(m) => m.codePointAt(0),
),
}];
const server = new Deno.QuicEndpoint({
hostname: "localhost",
port: 4433,
});
const listener = server.listen({
cert: certificates[0].pem,
key: certificates[0].privateKey,
alpnProtocols: ["h3"],
});
let requests = 0;
async function handle(wt) {
try {
console.log(wt);
const encoder = new TextEncoder();
await wt.ready;
for await (
const { readable, writable } of wt.incomingBidirectionalStreams
) {
for await (const value of readable.pipeThrough(new TextDecoderStream())) {
console.log(value);
await new Response(value.toUpperCase()).body
.pipeTo(writable, { preventClose: true });
}
await writable.close().then(() => console.log("writable close"));
console.log(writable);
await new Promise((r) => setTimeout(r));
wt.close();
break;
}
} catch (e) {
console.log(e);
console.trace();
} finally {
return wt.closed.then(() => ({
code: 0,
reason: `Done streaming request ${requests++}`,
}));
}
}
for await (const conn of listener) {
const wt = await Deno.upgradeWebTransport(conn);
try {
handle(wt)
.then((promise) => console.log(promise))
.catch(console.error);
} catch (e) {
console.log(e);
} finally {
continue;
}
}
server.close();
So, the issue is Firefox.
Well, you had to completely disable certificate verification in Chrome - I would call that a bit of a hurdle.
Well, yes. I'm using WebTransport locally, between the browser and local applications, so the certificate thing is N/A for my use cases.
| Comment hidden (off-topic) |
| Comment hidden (off-topic) |
| Reporter | ||
Comment 10•9 months ago
|
||
When you run mkcert -install (you ran that, right?)
No.
I located this repository which dynamically generates the certificates in JavaScript https://github.com/achingbrain/webtransport-echo-server.
@fails-components/webtransport with node index.js works for the base echo case, without logging the fulfillment from Promise.allSetlled() at the end, on Firefox Nightly 138.
Deno's WebTransport server using the same certificate generation means doesn't do anything on Firefox. The same code works on Chromium 136.
| Reporter | ||
Comment 11•9 months ago
|
||
| Reporter | ||
Comment 12•9 months ago
|
||
| Reporter | ||
Comment 13•9 months ago
|
||
Pardon, Promise.allSettled() is fulfilled on Nightly 138 (including closeCode and reason), when using @fails-components/webtransport and dynamically generating certificate in JavaScript.
I'll have to investigate why the Deno WebTransport server doesn't work on Firefox using the same certificate generation approach.
Comment 14•9 months ago
|
||
I'm sorry - I completely misunderstood what you were having problems with. If you use about:logging to log to a file with the log modules set to nsHttp:5, do you see any line with "AuthCertificateWithServerCertificateHashes failed"?
| Reporter | ||
Comment 15•9 months ago
|
||
No.
"Auth" appears 3 times.
2025-03-28 22:54:43.074618 UTC - [Parent 44535: Main Thread]: D/nsHttp nsHttpChannelAuthProvider::AddAuthorizationHeaders? [this=7f71d7d915e0 channel=7f71ce821ca0]
2025-03-28 22:54:43.074636 UTC - [Parent 44535: Main Thread]: D/nsHttp Skipping Authorization header for anonymous load
"webtransport" appears a few more times.
Really, this is unusable for local cases. Especially since Firefox blocks requests to localhost from console on most Web sites.
2025-03-28 22:54:43.075128 UTC - [Parent 44535: Main Thread]: V/nsHttp HttpBaseChannel::SetRequestHeader [this=7f71ce821600 header="Sec-Fetch-Dest" value="webtransport" merge=0]
2025-03-28 22:54:43.076702 UTC - [Parent 44535: Socket Thread]: D/nsSocketTransport PollableEvent::Clear PR_Read 1
2025-03-28 22:54:43.076729 UTC - [Parent 44535: Main Thread]: D/nsHttp triggering network rcwn=0
2025-03-28 22:54:43.076751 UTC - [Parent 44535: Main Thread]: D/nsHttp nsHttpChannel::DoConnect [this=7f71ce821600]
2025-03-28 22:54:43.076737 UTC - [Parent 44535: Socket Thread]: D/nsSocketTransport STS dispatch [7f71c6689640]
2025-03-28 22:54:43.076801 UTC - [Parent 44535: Socket Thread]: D/nsSocketTransport OnDispatchedEvent Same Thread Skip Signal
2025-03-28 22:54:43.076777 UTC - [Parent 44535: Main Thread]: D/nsHttp nsHttpChannel::DoConnectActual [this=7f71ce821600, aTransWithStickyConn=0]
2025-03-28 22:54:43.076847 UTC - [Parent 44535: Main Thread]: D/nsHttp nsHttpChannel::SetupChannelForTransaction [this=7f71ce821600, cos=0, inc=0 prio=0]
2025-03-28 22:54:43.076821 UTC - [Parent 44535: Socket Thread]: V/nsHttp nsHttpConnectionMgr::OnMsgSpeculativeConnect [ci=.SA......W[tlsflags0x00000000]localhost:4433 {NPN-TOKEN h3}{wId2}, mFetchHTTPSRR=1]
2025-03-28 22:54:43.076868 UTC - [Parent 44535: Main Thread]: V/nsHttp HttpBaseChannel::SetRequestHeader [this=7f71ce821600 header="Priority" value="u=4" merge=0]
2025-03-28 22:54:43.076894 UTC - [Parent 44535: Socket Thread]: V/nsHttp FindCoalescableConnection .SA......W[tlsflags0x00000000]localhost:4433 {NPN-TOKEN h3}{wId2}
2025-03-28 22:54:43.076953 UTC - [Parent 44535: Socket Thread]: V/nsHttp Don't coalesce a WebTransport conn
2025-03-28 22:54:43.076977 UTC - [Parent 44535: Socket Thread]: V/nsHttp GetH2orH3ActiveConn() request for ent 7f71ca129670 .SA......W[tlsflags0x00000000]localhost:4433 {NPN-TOKEN h3}{wId2} did not find an active connection
025-03-28 22:54:43.077173 UTC - [Parent 44535: Main Thread]: E/nsHttp http request [
2025-03-28 22:54:43.077192 UTC - [Parent 44535: Main Thread]: E/nsHttp GET /path HTTP/1.1
2025-03-28 22:54:43.077208 UTC - [Parent 44535: Main Thread]: E/nsHttp Host: localhost:4433
2025-03-28 22:54:43.077224 UTC - [Parent 44535: Main Thread]: E/nsHttp User-Agent: Mozilla/5.0 (X11; Linux x86_64; rv:138.0) Gecko/20100101 Firefox/138.0
2025-03-28 22:54:43.077240 UTC - [Parent 44535: Main Thread]: E/nsHttp Accept: /
2025-03-28 22:54:43.077255 UTC - [Parent 44535: Main Thread]: E/nsHttp Accept-Language: en-US,en;q=0.5
2025-03-28 22:54:43.077270 UTC - [Parent 44535: Main Thread]: E/nsHttp Accept-Encoding: gzip, deflate, br, zstd
2025-03-28 22:54:43.077285 UTC - [Parent 44535: Main Thread]: E/nsHttp Sec-Webtransport-Http3-Draft02: 1
2025-03-28 22:54:43.077300 UTC - [Parent 44535: Main Thread]: E/nsHttp Origin: https://example.com
2025-03-28 22:54:43.077315 UTC - [Parent 44535: Main Thread]: E/nsHttp Connection: keep-alive
2025-03-28 22:54:43.077330 UTC - [Parent 44535: Main Thread]: E/nsHttp Sec-Fetch-Dest: webtransport
2025-03-28 22:54:43.077344 UTC - [Parent 44535: Main Thread]: E/nsHttp Sec-Fetch-Mode: no-cors
2025-03-28 22:54:43.077360 UTC - [Parent 44535: Main Thread]: E/nsHttp Sec-Fetch-Site: cross-site
2025-03-28 22:54:43.077374 UTC - [Parent 44535: Main Thread]: E/nsHttp Priority: u=4
2025-03-28 22:54:43.077388 UTC - [Parent 44535: Main Thread]: E/nsHttp Pragma: no-cache
2025-03-28 22:54:43.077402 UTC - [Parent 44535: Main Thread]: E/nsHttp Cache-Control: no-cache
2025-03-28 22:54:43.077426 UTC - [Parent 44535: Main Thread]: E/nsHttp
2025-03-28 22:54:43.077446 UTC - [Parent 44535: Main Thread]: E/nsHttp ]
2025-03-28 22:54:43.077180 UTC - [Parent 44535: Socket Thread]: D/nsHostResolver Using port prefixed host name [_4433._https.localhost]
2025-03-28 22:54:43.077485 UTC - [Parent 44535: Socket Thread]: D/nsHostResolver Subdomain [localhost] of host [_4433._https.localhost] Is Excluded From TRR via pref
2025-03-28 22:54:43.077507 UTC - [Parent 44535: Socket Thread]: D/nsHostResolver No usable record in cache for host [_4433._https.localhost] type 65.
2025-03-28 22:54:43.077526 UTC - [Parent 44535: Socket Thread]: D/nsHostResolver NameLookup host:_4433._https.localhost af:0
2025-03-28 22:54:43.077516 UTC - [Parent 44535: Main Thread]: D/nsHostResolver Resolving host [localhost]<> type 65. [this=7f71da280200]
2025-03-28 22:54:43.077559 UTC - [Parent 44535: Socket Thread]: D/nsHostResolver Subdomain [localhost] of host [_4433._https.localhost] Is Excluded From TRR via pref
2025-03-28 22:54:43.077579 UTC - [Parent 44535: Socket Thread]: D/nsHostResolver NameLookup: _4433._https.localhost effectiveTRRmode: 1 flags: 20200
2025-03-28 22:54:43.077592 UTC - [Parent 44535: Socket Thread]: D/nsHostResolver TRR service not enabled - off or disabled
2025-03-28 22:54:43.077617 UTC - [Parent 44535: Socket Thread]: V/nsHttp FindCoalescableConnection .SA......W[tlsflags0x00000000]localhost:4433 {NPN-TOKEN h3}{wId2}
2025-03-28 22:54:43.077632 UTC - [Parent 44535: Socket Thread]: V/nsHttp Don't coalesce a WebTransport conn
2025-03-28 22:54:43.077648 UTC - [Parent 44535: Socket Thread]: V/nsHttp GetH2orH3ActiveConn() request for ent 7f71ca129670 .SA......W[tlsflags0x00000000]localhost:4433 {NPN-TOKEN h3}{wId2} did not find an active connection
2025-03-28 22:54:43.077666 UTC - [Parent 44535: Socket Thread]: V/nsHttp Creating DnsAndConnectSocket [this=7f71cb7f7480 trans=7f71cb180120 ent=localhost key=.SA......W[tlsflags0x00000000]localhost:4433 {NPN-TOKEN h3}{wId2}]
2025-03-28 22:54:43.077686 UTC - [Parent 44535: Socket Thread]: V/nsHttp DnsAndConnectSocket::SetupDnsFlags [this=7f71cb7f7480]
2025-03-28 22:54:43.077702 UTC - [Parent 44535: Socket Thread]: V/nsHttp DnsAndConnectSocket::SetupDnsFlags flags=8192 flagsBackup=8224 [this=7f71cb7f7480]
2025-03-28 22:54:43.077718 UTC - [Parent 44535: Socket Thread]: V/nsHttp DnsAndConnectSocket::SetupEvent state=0 event=0 this=7f71cb7f7480
2025-03-28 22:54:43.077735 UTC - [Parent 44535: Socket Thread]: V/nsHttp DnsAndConnectSocket::TransportSetup::ResolveHost [this=7f71cb7f74e0 localhost]
2025-03-28 22:54:43.077620 UTC - [Parent 44535: Main Thread]: D/nsHostResolver Using port prefixed host name [_4433._https.localhost]
2025-03-28 22:54:43.077774 UTC - [Parent 44535: Main Thread]: D/nsHostResolver Subdomain [localhost] of host [_4433._https.localhost] Is Excluded From TRR via pref
2025-03-28 22:54:43.077762 UTC - [Parent 44535: Socket Thread]: D/nsHostResolver Resolving host [localhost]<> type 0. [this=7f71da280200]
2025-03-28 22:54:43.077794 UTC - [Parent 44535: Main Thread]: D/nsHostResolver No usable record in cache for host [_4433._https.localhost] type 65.
2025-03-28 22:54:43.077840 UTC - [Parent 44535: Main Thread]: D/nsHostResolver NameLookup host:_4433._https.localhost af:0
2025-03-28 22:54:43.077854 UTC - [Parent 44535: Main Thread]: D/nsHostResolver Subdomain [localhost] of host [_4433._https.localhost] Is Excluded From TRR via pref
2025-03-28 22:54:43.077866 UTC - [Parent 44535: Main Thread]: D/nsHostResolver NameLookup: _4433._https.localhost effectiveTRRmode: 1 flags: 20200
2025-03-28 22:54:43.077879 UTC - [Parent 44535: Main Thread]: D/nsHostResolver TRR service not enabled - off or disabled
2025-03-28 22:54:43.077898 UTC - [Parent 44535: Main Thread]: V/nsHttp nsHttpConnectionMgr::AddTransaction [trans=7f71c975de10 0]
2025-03-28 22:54:43.077917 UTC - [Parent 44535: Main Thread]: D/nsSocketTransport STS dispatch [7f71c5dc7100]
2025-03-28 22:54:43.077935 UTC - [Parent 44535: Main Thread]: D/nsSocketTransport PollableEvent::Signal
2025-03-28 22:54:43.077951 UTC - [Parent 44535: Main Thread]: D/nsSocketTransport PollableEvent::MarkFirstSignalTimestamp
2025-03-28 22:54:43.077904 UTC - [Parent 44535: Socket Thread]: D/nsHostResolver Subdomain [localhost] of host [localhost] Is Excluded From TRR via pref
2025-03-28 22:54:43.078724 UTC - [Parent 44535: Socket Thread]: V/nsHttp Don't coalesce a WebTransport conn
2025-03-28 22:54:43.079198 UTC - [Parent 44535: Socket Thread]: I/nsHttp Http3Session::Init origin=localhost, alpn=h3, selfAddr=0.0.0.0, peerAddr=127.0.0.1, qpack table size=65536, max blocked streams=20 webtransport=1 [this=7f71c783e100]
2025-03-28 22:54:43.080200 UTC - [Parent 44535: Socket Thread]: V/nsHttp Don't coalesce a WebTransport conn
2025-03-28 22:54:43.080212 UTC - [Parent 44535: Socket Thread]: V/nsHttp GetH2orH3ActiveConn() request for ent 7f71ca129670 .SA......W[tlsflags0x00000000]localhost:4433 {NPN-TOKEN h3}{wId2} did not find an active connection
2025-03-28 22:54:43.080230 UTC - [Parent 44535: Socket Thread]: V/nsHttp DnsAndConnectSocket::SetupConn null transaction will be used to finish SSL handshake on conn 7f71c668a430
2025-03-28 22:54:43.080244 UTC - [Parent 44535: Socket Thread]: V/nsHttp nsHttpConnectionMgr::ActivateTimeoutTick() this=7f71eb548cc0 mTimeoutTick=7f71d79d3440
2025-03-28 22:54:43.080262 UTC - [Parent 44535: Socket Thread]: V/nsHttp nsHttpConnectionMgr::DispatchAbstractTransaction [ci=.SA......W[tlsflags0x00000000]localhost:4433 {NPN-TOKEN h3}{wId2} trans=7f71cb180120 caps=411 conn=7f71c668a430]
2025-03-28 22:54:43.080277 UTC - [Parent 44535: Socket Thread]: E/nsHttp HttpConnectionUDP::Activate [this=7f71c668a430 trans=7f71cb180120 caps=411]
2025-03-28 22:54:43.080293 UTC - [Parent 44535: Socket Thread]: I/nsHttp Http3Session::AddStream 7f71c783e100 atrans=7f71cb180120.
2025-03-28 22:54:43.082972 UTC - [Parent 44535: Socket Thread]: V/nsHttp Don't coalesce a WebTransport conn
2025-03-28 22:54:43.083008 UTC - [Parent 44535: Socket Thread]: V/nsHttp Don't coalesce a WebTransport conn
2025-03-28 22:54:43.083206 UTC - [Parent 44535: Socket Thread]: V/nsHttp Don't coalesce a WebTransport conn
2025-03-28 22:54:43.083280 UTC - [Parent 44535: Socket Thread]: V/nsHttp Don't coalesce a WebTransport conn
2025-03-28 22:54:43.084366 UTC - [Parent 44535: Socket Thread]: V/nsHttp Don't coalesce a WebTransport conn
Updated•9 months ago
|
Comment 16•9 months ago
|
||
I am not able to reproduce this with this demo server (https://github.com/achingbrain/webtransport-echo-server).
Unfortunately, the log in comment #15 is not complete. Could you try to capture the log and send it to necko@mozilla.com?
Thanks.
| Reporter | ||
Comment 17•9 months ago
|
||
| Reporter | ||
Comment 18•9 months ago
|
||
| Reporter | ||
Comment 19•9 months ago
|
||
The linked WebTransport echo server using @fails-components/webtransport does work, to an appreciable degree.
To an appreciable degree meaning Firefox Nightly 138 blocks WebTransport communication to the local server on arbitrary Web pages. On Chromium the connection is established and works as expected.
The Deno WebTransport implementation using the same certificate does not. Works as expected on Chromium 136 Developer Build from yesterday. I'm wondering why.
I sent the net log.
Here's the server and client. Here echoing 7 MB.
| Reporter | ||
Comment 21•9 months ago
|
||
Pardon. In the browser substitute this
let data = encoder.encode("x".repeat((1024 ** 2) * 7));
for this
let data = encoder.encode("x".repeat((1024 ** 2) * Deno.args.at(-1) || 1));
What I see in the console on Chromium 136 and Firefox Nightly 138
| Reporter | ||
Comment 22•9 months ago
|
||
Comment 23•9 months ago
|
||
Could you show me how to reproduce this locally?
Sorry that I am not sure how to run the server code in comment #17. It appears that cert.json is missing and I am not familiar with Deno at all.
| Reporter | ||
Comment 24•9 months ago
|
||
You used the linked echo server here
I am not able to reproduce this with this demo server (https://github.com/achingbrain/webtransport-echo-server).
Instead of dynamically creating the certificate every run, I converted the output certificate to JSON
[
{
"privateKey": "-----BEGIN PRIVATE KEY...",
"pem": "-----BEGIN CERTIFICATE-----\r\...",
"hash": {
"code": 18,
"size": 32,
"digest": [
242,
98,
...
],
"bytes": [...],
},
"secret": "super-secret-shhhhhh"
}
]
Thisis how I get Deno
wget --show-progress --progress=bar --output-document deno.zip https://dl.deno.land/canary/$(wget -qO- https://dl.deno.land/canary-latest.txt)/deno-x86_64-unknown-linux-gnu.zip && unzip deno.zip && rm deno.zip
This is how Irun the server
deno -A --unstable-net wt-server.js
Running the client using Deno
deno -A --unstable-net wt-client.js
| Reporter | ||
Comment 25•9 months ago
|
||
Here's the certificate bundling code from the linked echo server repository bundled to a single script with bun build.
| Reporter | ||
Comment 26•9 months ago
|
||
Here's how to use nodeto generate the certificate, once, to test the Deno WebTransport server. I'm using node nightly v24.0.0-nightly202504023db54912fa from today. If youare using node v23.11.0+ ECMAScript Modules are supported by default after syntax analyzation, see https://nodejs.org/api/cli.html#--input-typetype at
- Run the input as CommonJS.
- If step 1 fails, run the input as an ES module.
- If step 2 fails with a SyntaxError, strip the types.
- If step 3 fails with an error code ERR_UNSUPPORTED_TYPESCRIPT_SYNTAX or ERR_INVALID_TYPESCRIPT_SYNTAX, throw the error from step 2, including the TypeScript error in the message, else run as CommonJS.
- If step 4 fails, run the input as an ES module.
node generate-webtransport-certificate.js
import { writeFileSync } from "node:fs";
// https://github.com/achingbrain/webtransport-echo-server
import { generateWebTransportCertificates } from "./wt-certificate-bundle.js";
const certificates = await generateWebTransportCertificates([
{ shortName: "C", value: "US" },
{ shortName: "ST", value: "Los Angeles" },
{ shortName: "L", value: "Los Angeles" },
{ shortName: "O", value: "webtransport Test Server" },
{ shortName: "CN", value: "127.0.0.1" },
], [{
// can be max 14 days according to the spec
days: 13,
}]);
// Generate certificate, once, serialize to JSON, write to files ystem
certificates[0].hash.digest = [...new Uint8Array(certificates[0].hash.digest)];
certificates[0].hash.bytes = [...certificates[0].hash.bytes];
writeFileSync("cert.json", JSON.stringify(certificates, null, 2));
The use as demonstrated in the attached wt-server.js and wt-client.js
wt-server.js
import certificates from "./cert.json" with { type: "json" };
const serverCertificateHashes = [{
algorithm: "sha-256",
value: Uint8Array.from(
atob(btoa(String.fromCodePoint(...certificates[0].hash.digest))),
(m) => m.codePointAt(0),
),
}];
wt-client.js. I just hardcode the JSON from cert.json, where the values passed to Uint8Array.of() are the values of the "digest" array in cert.json. Use an anonymous async function, because Firefox will say top-level await is used if not, execute wt-client.js in console on a site where Firefox will not throw some kind of CSP/CORP/COOP/COEP error, e.g., maybe example.com.
(async () => {
try {
const serverCertificateHashes = [
{
"algorithm": "sha-256",
"value": Uint8Array.of(
0,
1,
2,
3,
...
),
},
];
const client = new WebTransport(
`https://localhost:4433/path`,
{
serverCertificateHashes,
},
);
// ...
})();
Updated•9 months ago
|
Comment 27•8 months ago
|
||
I've managed to reproduce this issue locally, and I believe it might be related to the speculative connections Firefox is making.
Could you try setting the pref network.http.speculative-parallel-limit to 0 and see if Firefox works as expected?
If it does, this might indicate a problem on the server side.
| Reporter | ||
Comment 28•8 months ago
|
||
Nothing changed. Firefox request doesn't succeed, nothing is logged.
Comment 29•8 months ago
|
||
Could you try capturing an HTTP log again with network.http.speculative-parallel-limit set to 0?
I'd suggest to set MOZ-LOG to timestamp,nsHttp:5,nsWebTransport:5,WebTransport:5,neqo_http3::*:5
Thanks!
| Reporter | ||
Comment 30•8 months ago
|
||
Got it working. Looks like the issue is setting the hostname to "localhost" instead of 127.0.0.1 in the server.
| Reporter | ||
Comment 31•8 months ago
|
||
| Reporter | ||
Comment 32•8 months ago
|
||
Can you reproduce successfully echoing data using Deno's WebTransport server on Firefox when the hostname is set to 127.0.0.1?
| Reporter | ||
Comment 33•8 months ago
|
||
Deno version 2.3.0-rc.0+5bee292 WebTrasnport server now only works as expected when Deno is the client. For an unknown reason Chromium and Firefox are not getting all the bytes from the server.
@fails-components/webtransport server works as expected.
Updated•8 months ago
|
Description
•