Skip to content

Commit 3e84bf0

Browse files
floatdropclaude
andauthored
fix(relay): default interop image to WebTransport at root path (#34)
* fix(relay): default interop image to WebTransport at root path The moq-interop-runner's docker harness dials the relay at a path-less https://relay:4443 (WebTransport, ALPN "h3") and provides no env knob to select the relay's transport. The interop relay image defaulted to raw QUIC (MOQT_TRANSPORT=quic), so it advertised only the moqt-* ALPNs and rejected every h3 ClientHello with "tls: no application protocol" — every client connecting to a moq-go relay in docker failed, including moq-go -> moq-go (0/6). Default the interop entrypoint/Dockerfile to MOQT_TRANSPORT=webtransport and MOQT_WEBTRANSPORT_PATH=/ to match the harness, and skip the relay's "/" catch-all 404 handler when the WebTransport path is "/" (registering two handlers for the same pattern panics the ServeMux; a root-mounted upgrade already covers every request). The -webtransport and -webtransport-path binary flag defaults are unchanged, so local `go run ./cmd/relay` is unaffected. Verified through the runner's compose: moq-go -> moq-go docker goes from 0/6 to 6/6. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> * fix(interop): pin client-direction loopback relay to raw QUIC Flipping the relay image default to WebTransport (so the external moq-interop-runner, which has no transport knob, can reach it) broke this repo's own "our client → our relay" CI job: `make interop-client` defaults to a raw-QUIC loopback (moqt://relay:4443), and its relay relied on the image's old quic default. With the relay now defaulting to WebTransport it advertised only h3, so the moqt:// client failed with "tls: no application protocol". docker-compose.client.yml now defaults the relay's MOQT_TRANSPORT to quic (matching the moqt:// loopback URL), and the Makefile derives it from CLIENT_RELAY_URL's scheme so an https:// override stays consistent. Third-party relay images ignore MOQT_TRANSPORT. interop/docker-compose.yml already forwarded MOQT_TRANSPORT, so interop-quic/interop-webtransport are unaffected. Verified: `make interop-client` loopback passes 6/6 with the relay in QUIC mode. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> --------- Co-authored-by: Claude Opus 4.8 <noreply@anthropic.com>
1 parent d49a924 commit 3e84bf0

5 files changed

Lines changed: 50 additions & 16 deletions

File tree

Makefile

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,12 @@ CLIENT_RELAY_IMAGE ?= moq-relay:latest
8383
CLIENT_RELAY_URL ?= moqt://relay:4443
8484
CLIENT_COMPOSE := docker compose -f interop/docker-compose.client.yml
8585

86+
# Transport our loopback relay must speak, derived from the URL scheme so the
87+
# default moqt:// loopback uses raw QUIC and an https:// override uses
88+
# WebTransport. Only consumed by our own relay image (third-party relays ignore
89+
# MOQT_TRANSPORT); see interop/docker-compose.client.yml.
90+
CLIENT_RELAY_TRANSPORT ?= $(if $(filter https://%,$(CLIENT_RELAY_URL)),webtransport,quic)
91+
8692
# Build our test-client image from this repo's sources.
8793
interop-client-build:
8894
docker build -f cmd/interop-client/Dockerfile.client -t moq-interop-client:latest .
@@ -91,7 +97,8 @@ interop-client-build:
9197
# loopback works out of the box; harmless when targeting a third-party relay.
9298
interop-client: interop-build interop-certs
9399
@echo ">> interop-client: moq-interop-client -> $(CLIENT_RELAY_IMAGE) ($(CLIENT_RELAY_URL))"
94-
RELAY_IMAGE=$(CLIENT_RELAY_IMAGE) RELAY_URL=$(CLIENT_RELAY_URL) $(CLIENT_ENV) \
100+
RELAY_IMAGE=$(CLIENT_RELAY_IMAGE) RELAY_URL=$(CLIENT_RELAY_URL) \
101+
MOQT_TRANSPORT=$(CLIENT_RELAY_TRANSPORT) $(CLIENT_ENV) \
95102
$(CLIENT_COMPOSE) up --build --abort-on-container-exit --exit-code-from test-client; \
96103
status=$$?; $(CLIENT_COMPOSE) down -v >/dev/null 2>&1; exit $$status
97104

cmd/relay/Dockerfile

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -41,10 +41,14 @@ COPY cmd/relay/entrypoint-relay.sh /app/run_endpoint.sh
4141
RUN chmod +x /app/run_endpoint.sh && mkdir -p /certs /mlog
4242

4343
# Defaults follow the runner conventions; override at `docker run`/compose time.
44+
# MOQT_TRANSPORT defaults to webtransport: the runner's docker harness always
45+
# dials the relay at https://relay:4443 (WebTransport / ALPN "h3") and exposes
46+
# no knob to set MOQT_TRANSPORT, so a raw-QUIC default makes every client fail
47+
# the TLS handshake with "no application protocol".
4448
ENV MOQT_ROLE=relay \
4549
MOQT_PORT=4443 \
46-
MOQT_TRANSPORT=quic \
47-
MOQT_WEBTRANSPORT_PATH=/moq
50+
MOQT_TRANSPORT=webtransport \
51+
MOQT_WEBTRANSPORT_PATH=/
4852

4953
EXPOSE 4443/udp
5054

cmd/relay/entrypoint-relay.sh

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,17 @@
77
# MOQT_PORT UDP port to listen on (default: 4443)
88
# MOQT_CERT TLS certificate PEM (default: /certs/cert.pem)
99
# MOQT_KEY TLS private key PEM (default: /certs/priv.key)
10-
# MOQT_TRANSPORT "quic" (moqt://) or "webtransport" (https://) (default: quic)
11-
# MOQT_WEBTRANSPORT_PATH HTTP/3 CONNECT path for WebTransport (default: /moq)
10+
# MOQT_TRANSPORT "quic" (moqt://) or "webtransport" (https://) (default: webtransport)
11+
# The runner's docker harness always points the client
12+
# at https://relay:4443 (WebTransport / ALPN "h3") and
13+
# provides no way to set MOQT_TRANSPORT, so the relay
14+
# must speak WebTransport by default or every handshake
15+
# fails with "tls: no application protocol".
16+
# MOQT_WEBTRANSPORT_PATH HTTP/3 CONNECT path for WebTransport (default: /)
17+
# The runner dials a path-less https://relay:4443, so
18+
# the CONNECT targets "/"; serving WebTransport at the
19+
# root is what lets the upgrade succeed (otherwise the
20+
# request 404s against the /moq handler).
1221
#
1322
# Mounts:
1423
# /certs/cert.pem, /certs/priv.key
@@ -21,8 +30,8 @@ ROLE="${MOQT_ROLE:-relay}"
2130
PORT="${MOQT_PORT:-4443}"
2231
CERT="${MOQT_CERT:-/certs/cert.pem}"
2332
KEY="${MOQT_KEY:-/certs/priv.key}"
24-
TRANSPORT="${MOQT_TRANSPORT:-quic}"
25-
WT_PATH="${MOQT_WEBTRANSPORT_PATH:-/moq}"
33+
TRANSPORT="${MOQT_TRANSPORT:-webtransport}"
34+
WT_PATH="${MOQT_WEBTRANSPORT_PATH:-/}"
2635

2736
if [ "$ROLE" != "relay" ]; then
2837
echo "role '$ROLE' not supported (only 'relay')" >&2

cmd/relay/main.go

Lines changed: 16 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -239,15 +239,22 @@ func webTransportListener(addr, path string, tlsCfg *tls.Config) (*wtconn.Listen
239239
mux := http.NewServeMux()
240240
// Catch-all so requests that don't hit `path` (wrong URL, missing
241241
// upgrade header, plain GET) get logged instead of silently 404'ing.
242-
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
243-
alpn := ""
244-
if r.TLS != nil {
245-
alpn = r.TLS.NegotiatedProtocol
246-
}
247-
log.Printf("http3: unmatched request %s %s%s proto=%s alpn=%q upgrade=%q",
248-
r.Method, r.Host, r.URL.Path, r.Proto, alpn, r.Header.Get(":protocol"))
249-
http.NotFound(w, r)
250-
})
242+
// Skip it when the upgrade handler itself owns "/" (path == "/"):
243+
// registering two handlers for the same pattern panics the ServeMux,
244+
// and a root-mounted upgrade already covers every request anyway. The
245+
// interop runner dials a path-less URL (https://relay:4443), so the
246+
// CONNECT targets "/" — see MOQT_WEBTRANSPORT_PATH in entrypoint-relay.sh.
247+
if path != "/" {
248+
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
249+
alpn := ""
250+
if r.TLS != nil {
251+
alpn = r.TLS.NegotiatedProtocol
252+
}
253+
log.Printf("http3: unmatched request %s %s%s proto=%s alpn=%q upgrade=%q",
254+
r.Method, r.Host, r.URL.Path, r.Proto, alpn, r.Header.Get(":protocol"))
255+
http.NotFound(w, r)
256+
})
257+
}
251258
h3 := &http3.Server{
252259
TLSConfig: tlsCfg,
253260
Handler: mux,

interop/docker-compose.client.yml

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,13 @@ services:
1919
environment:
2020
- MOQT_ROLE=relay
2121
- MOQT_PORT=4443
22+
# The default loopback (CLIENT_RELAY_IMAGE=moq-relay:latest, our own
23+
# image) dials moqt://relay:4443, so the relay must speak raw QUIC — our
24+
# image otherwise defaults to WebTransport (the external moq-interop-runner
25+
# drives it that way). Defaults to quic to match the moqt:// URL; the
26+
# Makefile derives it from CLIENT_RELAY_URL's scheme. Third-party relay
27+
# images ignore this var and use their own transport conventions.
28+
- MOQT_TRANSPORT=${MOQT_TRANSPORT:-quic}
2229
# No healthcheck override here: third-party relay images ship their own
2330
# (e.g. moq-rs uses `ss`, the moq-dev adapter greps /proc/net/udp6), and
2431
# some are shell-less so a `sh -c` override would never pass. We rely on the

0 commit comments

Comments
 (0)