Unfortunately, there’s still no fix in sight for https://github.com/golang/go/issues/67226.
tlsConf.NextProtos = []string{http3.NextProtoH3}
tr := &http3.Transport{TLSClientConfig: tlsConf}
defer tr.Close()
+ addDialCallback(t, tr)
cl := &http.Client{Transport: tr}
req, err := http.NewRequestWithContext(ctx, http.MethodGet, u.String(), nil)
require.NoError(t, err)
// the following values will be ignored when using ServeListener
TLSConfig: tlsConf,
QUICConfig: getQuicConfig(nil),
- Addr: "127.0.0.1:47283",
+ Addr: "127.0.0.1:0",
}
serveChan := make(chan error, 1)
go func() { serveChan <- server.ServeListener(ln) }()
} else {
go func() { serveChan <- server.ListenAndServe() }()
- host = server.Addr
+ // The server is listening on a random port, and the only way to get the port
+ // is to parse the Alt-Svc header.
+ var port int
+ require.Eventually(t, func() bool {
+ hdr := make(http.Header)
+ server.SetQUICHeaders(hdr)
+ altSvc := hdr.Get("Alt-Svc")
+ n, err := fmt.Sscanf(altSvc, `h3=":%d"`, &port)
+ return err == nil && n == 1
+ }, time.Second, 10*time.Millisecond)
+ host = fmt.Sprintf("127.0.0.1:%d", port)
}
u := &url.URL{Scheme: "https", Host: host, Path: "/ok"}
for range 2 {
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
- err := dial(t, ctx, u)
- var h3Err *http3.Error
- require.ErrorAs(t, err, &h3Err)
- require.Equal(t, http3.ErrCode(1337), h3Err.ErrorCode)
+ require.ErrorIs(t, dial(t, ctx, u), &http3.Error{ErrorCode: 1337, Remote: true})
select {
case err := <-errChan:
require.NoError(t, err)
QUICConfig: getQuicConfig(&quic.Config{MaxIdleTimeout: 10 * time.Second}),
DisableCompression: true,
}
+ addDialCallback(t, tr)
t.Cleanup(func() { tr.Close() })
return &http.Client{Transport: tr}
}
})
port := startHTTPServer(t, mux)
- cl := newHTTP3Client(t)
+ tr := &http3.Transport{
+ TLSClientConfig: getTLSClientConfigWithoutServerName(),
+ QUICConfig: getQuicConfig(nil),
+ }
+ t.Cleanup(func() { tr.Close() })
+ cl := &http.Client{Transport: tr}
+
resp, err := cl.Get(fmt.Sprintf("https://localhost:%d/remote-addr", port))
require.NoError(t, err)
require.Equal(t, http.StatusOK, resp.StatusCode)
DisableCompression: true,
}
defer tr.Close()
+ addDialCallback(t, tr)
proxyPort := proxy.LocalAddr().(*net.UDPAddr).Port
req, err := http.NewRequest(http3.MethodGet0RTT, fmt.Sprintf("https://localhost:%d/0rtt", proxyPort), nil)
DisableCompression: true,
}
defer tr2.Close()
+ addDialCallback(t, tr2)
rsp, err = tr2.RoundTrip(req)
require.NoError(t, err)
require.Equal(t, 200, rsp.StatusCode)
require.NoError(t, err)
defer conn.CloseWithError(0, "")
tr := http3.Transport{}
+ addDialCallback(t, &tr)
cc := tr.NewClientConn(conn)
str, err := cc.OpenRequestStream(ctx)
require.NoError(t, err)
"testing"
"time"
+ "github.com/quic-go/quic-go/http3"
"github.com/stretchr/testify/require"
)
}
ctx := httptrace.WithClientTrace(context.Background(), &trace)
- cl := newHTTP3Client(t)
+ tr := &http3.Transport{
+ TLSClientConfig: getTLSClientConfigWithoutServerName(),
+ QUICConfig: getQuicConfig(nil),
+ }
+ t.Cleanup(func() { tr.Close() })
+ cl := &http.Client{Transport: tr}
+
req, err := http.NewRequestWithContext(ctx, http.MethodGet, fmt.Sprintf("https://localhost:%d/client-trace", port), nil)
require.NoError(t, err)
resp, err := cl.Do(req)
"math/rand/v2"
"net"
"os"
+ "runtime"
"strconv"
"testing"
"time"
"github.com/quic-go/quic-go"
+ "github.com/quic-go/quic-go/http3"
"github.com/quic-go/quic-go/integrationtests/tools"
"github.com/quic-go/quic-go/internal/protocol"
"github.com/quic-go/quic-go/internal/wire"
}
return false
}
+
+// addDialCallback explicitly adds the http3.Transport's Dial callback.
+// This is needed since dialing on dual-stack sockets is flaky on macOS,
+// see https://github.com/golang/go/issues/67226.
+func addDialCallback(t *testing.T, tr *http3.Transport) {
+ t.Helper()
+
+ if runtime.GOOS != "darwin" {
+ return
+ }
+
+ require.Nil(t, tr.Dial)
+ tr.Dial = func(ctx context.Context, addr string, tlsConf *tls.Config, conf *quic.Config) (quic.EarlyConnection, error) {
+ a, err := net.ResolveUDPAddr("udp", addr)
+ if err != nil {
+ return nil, err
+ }
+ return quic.DialEarly(ctx, newUDPConnLocalhost(t), a, tlsConf, conf)
+ }
+}