]> git.feebdaed.xyz Git - 0xmirror/quic-go.git/commitdiff
http3: remove dependency on quic internal packages (#5256)
authorRobin Thellend <rthellend@gmail.com>
Mon, 7 Jul 2025 11:41:23 +0000 (04:41 -0700)
committerGitHub <noreply@github.com>
Mon, 7 Jul 2025 11:41:23 +0000 (13:41 +0200)
* Remove http3 dependency on quic internal packages

Remove the dependency on internal/protocol from the http3 package. This
makes it possible for a forked http3 to use the mainline quic-go
package.

* Address review comments

* Fix syntax

* Use broader pattern for http3 directory

* Copy internal/testdata

* Replace perspective with bool

* clone the supported version slice

---------

Co-authored-by: Marten Seemann <martenseemann@gmail.com>
18 files changed:
.golangci.yml
http3/client.go
http3/conn.go
http3/conn_test.go
http3/http3_helper_test.go
http3/internal/testdata/ca.pem [new file with mode: 0644]
http3/internal/testdata/cert.go [new file with mode: 0644]
http3/internal/testdata/cert.pem [new file with mode: 0644]
http3/internal/testdata/cert_test.go [new file with mode: 0644]
http3/internal/testdata/generate_key.sh [new file with mode: 0755]
http3/internal/testdata/priv.key [new file with mode: 0644]
http3/server.go
http3/server_test.go
http3/stream.go
http3/stream_test.go
http3/transport.go
http3/transport_test.go
interface.go

index 0c9ecffa59c975c47a14e6769e48790911b91215..4a97047bafdfd5c12a2d139eb2596129e386d6fe 100644 (file)
@@ -46,6 +46,13 @@ linters:
               desc: "use standard Go tests"
             - pkg: github.com/onsi/gomega
               desc: "use standard Go tests"
+        http3-internal:
+          list-mode: lax
+          files:
+            - '**/http3/**'
+          deny:
+            - pkg: 'github.com/quic-go/quic-go/internal'
+              desc: 'no dependency on quic-go/internal'
     misspell:
       ignore-rules:
         - ect
index 7cd02bc3286baf49ccec04e683d8f45851f1dc4d..678f5bc7b11c30cbd28aeebf0bee208a4a0828a2 100644 (file)
@@ -12,7 +12,6 @@ import (
        "time"
 
        "github.com/quic-go/quic-go"
-       "github.com/quic-go/quic-go/internal/protocol"
        "github.com/quic-go/quic-go/quicvarint"
 
        "github.com/quic-go/qpack"
@@ -102,7 +101,7 @@ func newClientConn(
                conn.Context(),
                conn,
                c.enableDatagrams,
-               protocol.PerspectiveClient,
+               false, // client
                c.logger,
                0,
        )
index 63ac9cbe22ff7da7db4f6819da128c45600530e0..842664963c0e73a9f8302a04fd90252336afa1e4 100644 (file)
@@ -14,7 +14,6 @@ import (
        "time"
 
        "github.com/quic-go/quic-go"
-       "github.com/quic-go/quic-go/internal/protocol"
        "github.com/quic-go/quic-go/quicvarint"
 
        "github.com/quic-go/qpack"
@@ -24,6 +23,9 @@ const maxQuarterStreamID = 1<<60 - 1
 
 var errGoAway = errors.New("connection in graceful shutdown")
 
+// invalidStreamID is a stream ID that is invalid. The first valid stream ID in QUIC is 0.
+const invalidStreamID = quic.StreamID(-1)
+
 // Conn is an HTTP/3 connection.
 // It has all methods from the quic.Conn expect for AcceptStream, AcceptUniStream,
 // SendDatagram and ReceiveDatagram.
@@ -32,17 +34,17 @@ type Conn struct {
 
        ctx context.Context
 
-       perspective protocol.Perspective
-       logger      *slog.Logger
+       isServer bool
+       logger   *slog.Logger
 
        enableDatagrams bool
 
        decoder *qpack.Decoder
 
        streamMx     sync.Mutex
-       streams      map[protocol.StreamID]*stateTrackingStream
-       lastStreamID protocol.StreamID
-       maxStreamID  protocol.StreamID
+       streams      map[quic.StreamID]*stateTrackingStream
+       lastStreamID quic.StreamID
+       maxStreamID  quic.StreamID
 
        settings         *Settings
        receivedSettings chan struct{}
@@ -55,22 +57,22 @@ func newConnection(
        ctx context.Context,
        quicConn *quic.Conn,
        enableDatagrams bool,
-       perspective protocol.Perspective,
+       isServer bool,
        logger *slog.Logger,
        idleTimeout time.Duration,
 ) *Conn {
        c := &Conn{
                ctx:              ctx,
                conn:             quicConn,
-               perspective:      perspective,
+               isServer:         isServer,
                logger:           logger,
                idleTimeout:      idleTimeout,
                enableDatagrams:  enableDatagrams,
                decoder:          qpack.NewDecoder(func(hf qpack.HeaderField) {}),
                receivedSettings: make(chan struct{}),
-               streams:          make(map[protocol.StreamID]*stateTrackingStream),
-               maxStreamID:      protocol.InvalidStreamID,
-               lastStreamID:     protocol.InvalidStreamID,
+               streams:          make(map[quic.StreamID]*stateTrackingStream),
+               maxStreamID:      invalidStreamID,
+               lastStreamID:     invalidStreamID,
        }
        if idleTimeout > 0 {
                c.idleTimer = time.AfterFunc(idleTimeout, c.onIdleTimer)
@@ -124,7 +126,7 @@ func (c *Conn) clearStream(id quic.StreamID) {
        }
        // The server is performing a graceful shutdown.
        // If no more streams are remaining, close the connection.
-       if c.maxStreamID != protocol.InvalidStreamID {
+       if c.maxStreamID != invalidStreamID {
                if len(c.streams) == 0 {
                        c.CloseWithError(quic.ApplicationErrorCode(ErrCodeNoError), "")
                }
@@ -141,7 +143,7 @@ func (c *Conn) openRequestStream(
        c.streamMx.Lock()
        maxStreamID := c.maxStreamID
        var nextStreamID quic.StreamID
-       if c.lastStreamID == protocol.InvalidStreamID {
+       if c.lastStreamID == invalidStreamID {
                nextStreamID = 0
        } else {
                nextStreamID = c.lastStreamID + 4
@@ -149,7 +151,7 @@ func (c *Conn) openRequestStream(
        c.streamMx.Unlock()
        // Streams with stream ID equal to or greater than the stream ID carried in the GOAWAY frame
        // will be rejected, see section 5.2 of RFC 9114.
-       if maxStreamID != protocol.InvalidStreamID && nextStreamID >= maxStreamID {
+       if maxStreamID != invalidStreamID && nextStreamID >= maxStreamID {
                return nil, errGoAway
        }
 
@@ -268,13 +270,12 @@ func (c *Conn) handleUnidirectionalStreams(hijack func(StreamType, quic.Connecti
                                // Our QPACK implementation doesn't use the dynamic table yet.
                                return
                        case streamTypePushStream:
-                               switch c.perspective {
-                               case protocol.PerspectiveClient:
-                                       // we never increased the Push ID, so we don't expect any push streams
-                                       c.CloseWithError(quic.ApplicationErrorCode(ErrCodeIDError), "")
-                               case protocol.PerspectiveServer:
+                               if c.isServer {
                                        // only the server can push
                                        c.CloseWithError(quic.ApplicationErrorCode(ErrCodeStreamCreationError), "")
+                               } else {
+                                       // we never increased the Push ID, so we don't expect any push streams
+                                       c.CloseWithError(quic.ApplicationErrorCode(ErrCodeIDError), "")
                                }
                                return
                        default:
@@ -342,7 +343,7 @@ func (c *Conn) handleControlStream(str *quic.ReceiveStream) {
        }
 
        // we don't support server push, hence we don't expect any GOAWAY frames from the client
-       if c.perspective == protocol.PerspectiveServer {
+       if c.isServer {
                return
        }
 
@@ -370,7 +371,7 @@ func (c *Conn) handleControlStream(str *quic.ReceiveStream) {
                        return
                }
                c.streamMx.Lock()
-               if c.maxStreamID != protocol.InvalidStreamID && goaway.StreamID > c.maxStreamID {
+               if c.maxStreamID != invalidStreamID && goaway.StreamID > c.maxStreamID {
                        c.streamMx.Unlock()
                        c.conn.CloseWithError(quic.ApplicationErrorCode(ErrCodeIDError), "")
                        return
@@ -387,7 +388,7 @@ func (c *Conn) handleControlStream(str *quic.ReceiveStream) {
        }
 }
 
-func (c *Conn) sendDatagram(streamID protocol.StreamID, b []byte) error {
+func (c *Conn) sendDatagram(streamID quic.StreamID, b []byte) error {
        // TODO: this creates a lot of garbage and an additional copy
        data := make([]byte, 0, len(b)+8)
        data = quicvarint.Append(data, uint64(streamID/4))
@@ -410,7 +411,7 @@ func (c *Conn) receiveDatagrams() error {
                        c.CloseWithError(quic.ApplicationErrorCode(ErrCodeDatagramError), "")
                        return fmt.Errorf("invalid quarter stream id: %w", err)
                }
-               streamID := protocol.StreamID(4 * quarterStreamID)
+               streamID := quic.StreamID(4 * quarterStreamID)
                c.streamMx.Lock()
                dg, ok := c.streams[streamID]
                c.streamMx.Unlock()
index 21e50afa3e46d21f4c4764da9c4d53aa0fd5a967..d781eefd4778b48e1b32a5055462c358981b84ea 100644 (file)
@@ -8,7 +8,6 @@ import (
        "time"
 
        "github.com/quic-go/quic-go"
-       "github.com/quic-go/quic-go/internal/protocol"
        "github.com/quic-go/quic-go/quicvarint"
 
        "github.com/stretchr/testify/require"
@@ -21,7 +20,7 @@ func TestConnReceiveSettings(t *testing.T) {
                serverConn.Context(),
                serverConn,
                false,
-               protocol.PerspectiveServer,
+               true, // server
                nil,
                0,
        )
@@ -71,7 +70,7 @@ func testConnRejectDuplicateStreams(t *testing.T, typ uint64) {
                context.Background(),
                serverConn,
                false,
-               protocol.PerspectiveServer,
+               true, // server
                nil,
                0,
        )
@@ -116,7 +115,7 @@ func TestConnResetUnknownUniStream(t *testing.T) {
                context.Background(),
                serverConn,
                false,
-               protocol.PerspectiveServer,
+               true, // server
                nil,
                0,
        )
@@ -198,7 +197,7 @@ func testConnControlStreamFailures(t *testing.T, data []byte, readErr error, exp
                clientConn.Context(),
                clientConn,
                false,
-               protocol.PerspectiveClient,
+               false, // client
                nil,
                0,
        )
@@ -261,7 +260,7 @@ func testConnGoAway(t *testing.T, withStream bool) {
                clientConn.Context(),
                clientConn,
                false,
-               protocol.PerspectiveClient,
+               false, // client
                nil,
                0,
        )
@@ -318,21 +317,21 @@ func testConnGoAway(t *testing.T, withStream bool) {
 
 func TestConnRejectPushStream(t *testing.T) {
        t.Run("client", func(t *testing.T) {
-               testConnRejectPushStream(t, protocol.PerspectiveClient, ErrCodeStreamCreationError)
+               testConnRejectPushStream(t, false, ErrCodeStreamCreationError)
        })
        t.Run("server", func(t *testing.T) {
-               testConnRejectPushStream(t, protocol.PerspectiveServer, ErrCodeIDError)
+               testConnRejectPushStream(t, true, ErrCodeIDError)
        })
 }
 
-func testConnRejectPushStream(t *testing.T, pers protocol.Perspective, expectedErr ErrCode) {
+func testConnRejectPushStream(t *testing.T, isServer bool, expectedErr ErrCode) {
        clientConn, serverConn := newConnPair(t)
 
        conn := newConnection(
                clientConn.Context(),
                clientConn,
                false,
-               pers.Opposite(),
+               !isServer,
                nil,
                0,
        )
@@ -370,7 +369,7 @@ func TestConnInconsistentDatagramSupport(t *testing.T) {
                clientConn.Context(),
                clientConn,
                true,
-               protocol.PerspectiveClient,
+               false, // client
                nil,
                0,
        )
@@ -400,7 +399,7 @@ func TestConnSendAndReceiveDatagram(t *testing.T) {
                clientConn.Context(),
                clientConn,
                true,
-               protocol.PerspectiveClient,
+               false, // client
                nil,
                0,
        )
@@ -429,7 +428,7 @@ func TestConnSendAndReceiveDatagram(t *testing.T) {
 
        str, err := conn.openRequestStream(context.Background(), nil, nil, true, 1000)
        require.NoError(t, err)
-       require.Equal(t, protocol.StreamID(strID), str.StreamID())
+       require.Equal(t, quic.StreamID(strID), str.StreamID())
 
        // now open the stream...
        require.NoError(t, serverConn.SendDatagram(append(quarterStreamID, []byte("bar")...)))
@@ -467,7 +466,7 @@ func testConnDatagramFailures(t *testing.T, datagram []byte) {
                clientConn.Context(),
                clientConn,
                true,
-               protocol.PerspectiveClient,
+               false, // client
                nil,
                0,
        )
index 66a6284ee80a3b57514d7f3c90d278b5bc67a617..2098d337e4ce97d4f48a43a90ba91b1d5237c42e 100644 (file)
@@ -21,11 +21,13 @@ import (
 
        "github.com/quic-go/qpack"
        "github.com/quic-go/quic-go"
-       "github.com/quic-go/quic-go/internal/protocol"
 
        "github.com/stretchr/testify/require"
 )
 
+// maxByteCount is the maximum value of a ByteCount
+const maxByteCount = uint64(1<<62 - 1)
+
 func newUDPConnLocalhost(t testing.TB) *net.UDPConn {
        t.Helper()
        conn, err := net.ListenUDP("udp", &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 0})
@@ -134,8 +136,8 @@ func newConnPair(t *testing.T) (client, server *quic.Conn) {
                newUDPConnLocalhost(t),
                getTLSConfig(),
                &quic.Config{
-                       InitialStreamReceiveWindow:     uint64(protocol.MaxByteCount),
-                       InitialConnectionReceiveWindow: uint64(protocol.MaxByteCount),
+                       InitialStreamReceiveWindow:     maxByteCount,
+                       InitialConnectionReceiveWindow: maxByteCount,
                },
        )
        require.NoError(t, err)
@@ -164,8 +166,8 @@ func newConnPairWithDatagrams(t *testing.T) (client, server *quic.Conn) {
                newUDPConnLocalhost(t),
                getTLSConfig(),
                &quic.Config{
-                       InitialStreamReceiveWindow:     uint64(protocol.MaxByteCount),
-                       InitialConnectionReceiveWindow: uint64(protocol.MaxByteCount),
+                       InitialStreamReceiveWindow:     maxByteCount,
+                       InitialConnectionReceiveWindow: maxByteCount,
                        EnableDatagrams:                true,
                },
        )
diff --git a/http3/internal/testdata/ca.pem b/http3/internal/testdata/ca.pem
new file mode 100644 (file)
index 0000000..67a5545
--- /dev/null
@@ -0,0 +1,17 @@
+-----BEGIN CERTIFICATE-----
+MIICzDCCAbQCCQDA+rLymNnfJzANBgkqhkiG9w0BAQsFADAoMSYwJAYDVQQKDB1x
+dWljLWdvIENlcnRpZmljYXRlIEF1dGhvcml0eTAeFw0yMDA4MTgwOTIxMzVaFw0z
+MDA4MTYwOTIxMzVaMCgxJjAkBgNVBAoMHXF1aWMtZ28gQ2VydGlmaWNhdGUgQXV0
+aG9yaXR5MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA1OcsYrVaSDfh
+iDppl6oteVspOY3yFb96T9Y/biaGPJAkBO9VGKcqwOUPmUeiWpedRAUB9LE7Srs6
+qBX4mnl90Icjp8jbIs5cPgIWLkIu8Qm549RghFzB3bn+EmCQSe4cxvyDMN3ndClp
+3YMXpZgXWgJGiPOylVi/OwHDdWDBorw4hvry+6yDtpQo2TuI2A/xtxXPT7BgsEJD
+WGffdgZOYXChcFA0c1XVLIYlu2w2JhxS8c2TUF6uSDlmcoONNKVoiNCuu1Z9MorS
+Qmg7a2G7dSPu123KcTcSQFcmJrt+1G81gOBtHB69kacD8xDmgksj09h/ODPL/gIU
+1ZcU2ci1/QIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQB0Tb1JbLXp/BvWovSAhO/j
+wG7UEaUA1rCtkDB+fV2HS9bxCbV5eErdg8AMHKgB51ygUrq95vm/baZmUILr84XK
+uTEoxxrw5S9Z7SrhtbOpKCumoSeTsCPjDvCcwFExHv4XHFk+CPqZwbMHueVIMT0+
+nGWss/KecCPdJLdnUgMRz0tIuXzkoRuOiUiZfUeyBNVNbDFSrLigYshTeAPGaYjX
+CypoHxkeS93nWfOMUu8FTYLYkvGMU5i076zDoFGKJiEtbjSiNW+Hei7u2aSEuCzp
+qyTKzYPWYffAq3MM2MKJgZdL04e9GEGeuce/qhM1o3q77aI/XJImwEDdut2LDec1
+-----END CERTIFICATE-----
diff --git a/http3/internal/testdata/cert.go b/http3/internal/testdata/cert.go
new file mode 100644 (file)
index 0000000..f77a7b2
--- /dev/null
@@ -0,0 +1,56 @@
+package testdata
+
+import (
+       "crypto/tls"
+       "crypto/x509"
+       "os"
+       "path"
+       "runtime"
+)
+
+var certPath string
+
+func init() {
+       _, filename, _, ok := runtime.Caller(0)
+       if !ok {
+               panic("Failed to get current frame")
+       }
+
+       certPath = path.Dir(filename)
+}
+
+// GetCertificatePaths returns the paths to certificate and key
+func GetCertificatePaths() (string, string) {
+       return path.Join(certPath, "cert.pem"), path.Join(certPath, "priv.key")
+}
+
+// GetTLSConfig returns a tls config for quic.clemente.io
+func GetTLSConfig() *tls.Config {
+       cert, err := tls.LoadX509KeyPair(GetCertificatePaths())
+       if err != nil {
+               panic(err)
+       }
+       return &tls.Config{
+               MinVersion:   tls.VersionTLS13,
+               Certificates: []tls.Certificate{cert},
+       }
+}
+
+// AddRootCA adds the root CA certificate to a cert pool
+func AddRootCA(certPool *x509.CertPool) {
+       caCertPath := path.Join(certPath, "ca.pem")
+       caCertRaw, err := os.ReadFile(caCertPath)
+       if err != nil {
+               panic(err)
+       }
+       if ok := certPool.AppendCertsFromPEM(caCertRaw); !ok {
+               panic("Could not add root ceritificate to pool.")
+       }
+}
+
+// GetRootCA returns an x509.CertPool containing (only) the CA certificate
+func GetRootCA() *x509.CertPool {
+       pool := x509.NewCertPool()
+       AddRootCA(pool)
+       return pool
+}
diff --git a/http3/internal/testdata/cert.pem b/http3/internal/testdata/cert.pem
new file mode 100644 (file)
index 0000000..91d1aa9
--- /dev/null
@@ -0,0 +1,18 @@
+-----BEGIN CERTIFICATE-----
+MIIC1TCCAb2gAwIBAgIJAK2fcqC0BVA7MA0GCSqGSIb3DQEBCwUAMCgxJjAkBgNV
+BAoMHXF1aWMtZ28gQ2VydGlmaWNhdGUgQXV0aG9yaXR5MB4XDTIwMDgxODA5MjEz
+NVoXDTMwMDgxNjA5MjEzNVowEjEQMA4GA1UECgwHcXVpYy1nbzCCASIwDQYJKoZI
+hvcNAQEBBQADggEPADCCAQoCggEBAN/YwrigSXdJCL/bdBGhb0UpqtU8H+krV870
++w1yCSykLImH8x3qHZEXt9sr/vgjcJoV6Z15RZmnbEqnAx84sIClIBoIgnk0VPxu
+WF+/U/dElbftCfYcfJAddhRckdmGB+yb3Wogb32UJ+q3my++h6NjHsYb+OwpJPnQ
+meXjOE7Kkf+bXfFywHF3R8kzVdh5JUFYeKbxYmYgxRps1YTsbCrZCrSy1CbQ9FJw
+Wg5C8t+7yvVFmOeWPECypBCz2xS2mu+kycMNIjIWMl0SL7oVM5cBkRKPeVIG/KcM
+i5+/4lRSLoPh0Txh2TKBWfpzLbIOdPU8/O7cAukIGWx0XsfHUQMCAwEAAaMYMBYw
+FAYDVR0RBA0wC4IJbG9jYWxob3N0MA0GCSqGSIb3DQEBCwUAA4IBAQAyxxvebdMz
+shp5pt1SxMOSXbo8sTa1cpaf2rTmb4nxjXs6KPBEn53hSBz9bhe5wXE4f94SHadf
+636rLh3d75KgrLUwO9Yq0HfCxMo1jUV/Ug++XwcHCI9vk58Tk/H4hqEM6C8RrdTj
+fYeuegQ0/oNLJ4uTw2P2A8TJbL6FC2dcICEAvUGZUcVyZ8m8tHXNRYYh6MZ7ubCh
+hinvL+AA5fY6EVlc5G/P4DN6fYxGn1cFNbiL4uZP4+W3dOmP+NV0YV9ihTyMzz0R
+vSoOZ9FeVkyw8EhMb3LoyXYKazvJy2VQST1ltzAGit9RiM1Gv4vuna74WsFzrn1U
+A/TbaR0ih/qG
+-----END CERTIFICATE-----
diff --git a/http3/internal/testdata/cert_test.go b/http3/internal/testdata/cert_test.go
new file mode 100644 (file)
index 0000000..2eff1fe
--- /dev/null
@@ -0,0 +1,28 @@
+package testdata
+
+import (
+       "crypto/tls"
+       "io"
+       "testing"
+
+       "github.com/stretchr/testify/require"
+)
+
+func TestCertificates(t *testing.T) {
+       ln, err := tls.Listen("tcp", "localhost:4433", GetTLSConfig())
+       require.NoError(t, err)
+
+       go func() {
+               conn, err := ln.Accept()
+               require.NoError(t, err)
+               defer conn.Close()
+               _, err = conn.Write([]byte("foobar"))
+               require.NoError(t, err)
+       }()
+
+       conn, err := tls.Dial("tcp", "localhost:4433", &tls.Config{RootCAs: GetRootCA()})
+       require.NoError(t, err)
+       data, err := io.ReadAll(conn)
+       require.NoError(t, err)
+       require.Equal(t, "foobar", string(data))
+}
diff --git a/http3/internal/testdata/generate_key.sh b/http3/internal/testdata/generate_key.sh
new file mode 100755 (executable)
index 0000000..7ecaa96
--- /dev/null
@@ -0,0 +1,24 @@
+#!/bin/bash
+
+set -e
+
+echo "Generating CA key and certificate:"
+openssl req -x509 -sha256 -nodes -days 3650 -newkey rsa:2048 \
+  -keyout ca.key -out ca.pem \
+  -subj "/O=quic-go Certificate Authority/"
+
+echo "Generating CSR"
+openssl req -out cert.csr -new -newkey rsa:2048 -nodes -keyout priv.key \
+  -subj "/O=quic-go/"
+
+echo "Sign certificate:"
+openssl x509 -req -sha256 -days 3650 -in cert.csr  -out cert.pem \
+  -CA ca.pem -CAkey ca.key -CAcreateserial \
+  -extfile <(printf "subjectAltName=DNS:localhost")
+
+# debug output the certificate
+openssl x509 -noout -text -in cert.pem
+
+# we don't need the CA key, the serial number and the CSR any more
+rm ca.key cert.csr ca.srl
+
diff --git a/http3/internal/testdata/priv.key b/http3/internal/testdata/priv.key
new file mode 100644 (file)
index 0000000..56b8d89
--- /dev/null
@@ -0,0 +1,28 @@
+-----BEGIN PRIVATE KEY-----
+MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQDf2MK4oEl3SQi/
+23QRoW9FKarVPB/pK1fO9PsNcgkspCyJh/Md6h2RF7fbK/74I3CaFemdeUWZp2xK
+pwMfOLCApSAaCIJ5NFT8blhfv1P3RJW37Qn2HHyQHXYUXJHZhgfsm91qIG99lCfq
+t5svvoejYx7GG/jsKST50Jnl4zhOypH/m13xcsBxd0fJM1XYeSVBWHim8WJmIMUa
+bNWE7Gwq2Qq0stQm0PRScFoOQvLfu8r1RZjnljxAsqQQs9sUtprvpMnDDSIyFjJd
+Ei+6FTOXAZESj3lSBvynDIufv+JUUi6D4dE8YdkygVn6cy2yDnT1PPzu3ALpCBls
+dF7Hx1EDAgMBAAECggEBAMm+mLDBdbUWk9YmuZNyRdC13wvT5obF05vo26OglXgw
+dxt09b6OVBuCnuff3SpS9pdJDIYq2HnFlSorH/sxopIvQKF17fHDIp1n7ipNTCXd
+IHrmHkY8Il/YzaVIUQMVc2rih0mw9greTqOS20DKnYC6QvAWIeDmrDaitTGl+ge3
+hm7e2lsgZi13R6fTNwQs9geEQSGzP2k7bFceHQFDChOYiQraR5+VZZ8S8AMGjk47
+AUa5EsKeUe6O9t2xuDSFxzYz5eadOAiErKGDos5KXXr3VQgFcC8uPEFFjcJ/yl+8
+tOe4iLeVwGSDJhTAThdR2deJOjaDcarWM7ixmxA3DAECgYEA/WVwmY4gWKwv49IJ
+Jnh1Gu93P772GqliMNpukdjTI+joQxfl4jRSt2hk4b1KRwyT9aaKfvdz0HFlXo/r
+9NVSAYT3/3vbcw61bfvPhhtz44qRAAKua6b5cUM6XqxVt1hqdP8lrf/blvA5ln+u
+O51S8+wpxZMuqKz/29zdWSG6tAMCgYEA4iWXMXX9dZajI6abVkWwuosvOakXdLk4
+tUy7zd+JPF7hmUzzj2gtg4hXoiQPAOi+GY3TX+1Nza3s1LD7iWaXSKeOWvvligw9
+Q/wVTNW2P1+tdhScJf9QudzW69xOm5HNBgx9uWV2cHfjC12vg5aTH0k5axvaq15H
+9WBXlH5q3wECgYBYoYGYBDFmMpvxmMagkSOMz1OrlVSpkLOKmOxx0SBRACc1SIec
+7mY8RqR6nOX9IfYixyTMMittLiyhvb9vfKnZZDQGRcFFZlCpbplws+t+HDqJgWaW
+uumm5zfkY2z7204pLBF24fZhvha2gGRl76pTLTiTJd79Gr3HnmJByd1vFwKBgHL7
+vfYuEeM55lT4Hz8sTAFtR2O/7+cvTgAQteSlZbfGXlp939DonUulhTkxsFc7/3wq
+unCpzcdoSWSTYDGqcf1FBIKKVVltg7EPeR0KBJIQabgCHqrLOBZojPZ7m5RJ+765
+lysuxZvFuTFMPzNe2gssRf+JuBMt6tR+WclsxZYBAoGAEEFs1ppDil1xlP5rdH7T
+d3TSw/u4eU/X8Ei1zi25hdRUiV76fP9fBELYFmSrPBhugYv91vtSv/LmD4zLfLv/
+yzwAD9j1lGbgM8Of8klCkk+XSJ88ryUwnMTJ5loQJW8t4L+zLv5Le7Ca9SAT0kJ1
+jT0GzDymgLMGp8RPdBkpk+w=
+-----END PRIVATE KEY-----
index 8d53a7246709da5ff92c1d559edc0ff90f3fb403..7e002a09b64a532e6ebf9b3a4070dcaaabf7129b 100644 (file)
@@ -18,7 +18,6 @@ import (
        "time"
 
        "github.com/quic-go/quic-go"
-       "github.com/quic-go/quic-go/internal/protocol"
        "github.com/quic-go/quic-go/quicvarint"
 
        "github.com/quic-go/qpack"
@@ -468,7 +467,7 @@ func (s *Server) handleConn(conn *quic.Conn) error {
                connCtx,
                conn,
                s.EnableDatagrams,
-               protocol.PerspectiveServer,
+               true, // server
                s.Logger,
                s.IdleTimeout,
        )
index 3c81253f8ba2d1111fbe66d18a4ba4ed934d951b..b39993a0c5def4a84b73e1e6727d47263a1df1b3 100644 (file)
@@ -15,7 +15,7 @@ import (
        "time"
 
        "github.com/quic-go/quic-go"
-       "github.com/quic-go/quic-go/internal/testdata"
+       "github.com/quic-go/quic-go/http3/internal/testdata"
        "github.com/quic-go/quic-go/quicvarint"
 
        "github.com/stretchr/testify/assert"
index a1dafa11dc8a06ef39056436722f8964994fec26..50295600c227b251a109d3d68278007b8093b2f7 100644 (file)
@@ -10,7 +10,6 @@ import (
        "time"
 
        "github.com/quic-go/quic-go"
-       "github.com/quic-go/quic-go/internal/protocol"
 
        "github.com/quic-go/qpack"
 )
@@ -79,7 +78,7 @@ func (s *Stream) Read(b []byte) (int, error) {
                                s.bytesRemainingInFrame = f.Length
                                break parseLoop
                        case *headersFrame:
-                               if s.conn.perspective == protocol.PerspectiveServer {
+                               if s.conn.isServer {
                                        continue
                                }
                                if s.parsedTrailer {
@@ -124,7 +123,7 @@ func (s *Stream) writeUnframed(b []byte) (int, error) {
        return s.datagramStream.Write(b)
 }
 
-func (s *Stream) StreamID() protocol.StreamID {
+func (s *Stream) StreamID() quic.StreamID {
        return s.datagramStream.StreamID()
 }
 
@@ -194,7 +193,7 @@ func (s *RequestStream) Read(b []byte) (int, error) {
 }
 
 // StreamID returns the QUIC stream ID of the underlying QUIC stream.
-func (s *RequestStream) StreamID() protocol.StreamID {
+func (s *RequestStream) StreamID() quic.StreamID {
        return s.str.StreamID()
 }
 
index a6352a1d44b72d6c53bf0466c44ebaa56f2f13e2..ca18a9cd6d2b6a50c9f41302ad826a9793fc6b88 100644 (file)
@@ -13,7 +13,6 @@ import (
        "time"
 
        "github.com/quic-go/quic-go"
-       "github.com/quic-go/quic-go/internal/protocol"
 
        "github.com/quic-go/qpack"
 
@@ -40,7 +39,7 @@ func TestStreamReadDataFrames(t *testing.T) {
                        clientConn.Context(),
                        clientConn,
                        false,
-                       protocol.PerspectiveClient,
+                       false, // client
                        nil,
                        0,
                ),
@@ -92,7 +91,7 @@ func TestStreamInvalidFrame(t *testing.T) {
 
        str := newStream(
                qstr,
-               newConnection(context.Background(), clientConn, false, protocol.PerspectiveClient, nil, 0),
+               newConnection(context.Background(), clientConn, false, false, nil, 0),
                nil,
                func(r io.Reader, u uint64) error { return nil },
        )
@@ -146,7 +145,7 @@ func TestRequestStream(t *testing.T) {
        str := newRequestStream(
                newStream(
                        qstr,
-                       newConnection(context.Background(), clientConn, false, protocol.PerspectiveClient, nil, 0),
+                       newConnection(context.Background(), clientConn, false, false, nil, 0),
                        &httptrace.ClientTrace{},
                        func(r io.Reader, u uint64) error { return nil },
                ),
index dac84bb8dad8a53b05c717ccc26f47c3b3f74460..4085faca5ef45cac6c8fd8b9f7a4f53e834cdb30 100644 (file)
@@ -18,7 +18,6 @@ import (
        "golang.org/x/net/http/httpguts"
 
        "github.com/quic-go/quic-go"
-       "github.com/quic-go/quic-go/internal/protocol"
 )
 
 // Settings are HTTP/3 settings that apply to the underlying connection.
@@ -146,7 +145,7 @@ func (t *Transport) init() error {
        }
        if len(t.QUICConfig.Versions) == 0 {
                t.QUICConfig = t.QUICConfig.Clone()
-               t.QUICConfig.Versions = []quic.Version{protocol.SupportedVersions[0]}
+               t.QUICConfig.Versions = []quic.Version{quic.SupportedVersions()[0]}
        }
        if len(t.QUICConfig.Versions) != 1 {
                return errors.New("can only use a single QUIC version for dialing a HTTP/3 connection")
index 63adc76f074a8a00e53d3de86c90ea000839164e..2b98ccf1cf73a0ce323030cf5e1ed2d2223be632 100644 (file)
@@ -14,7 +14,6 @@ import (
        "time"
 
        "github.com/quic-go/quic-go"
-       "github.com/quic-go/quic-go/internal/protocol"
 
        "github.com/stretchr/testify/assert"
        "github.com/stretchr/testify/require"
@@ -208,7 +207,7 @@ func TestTransportDatagrams(t *testing.T) {
 
 func TestTransportMultipleQUICVersions(t *testing.T) {
        qconf := &quic.Config{
-               Versions: []quic.Version{protocol.Version2, protocol.Version1},
+               Versions: []quic.Version{quic.Version2, quic.Version1},
        }
        tr := &Transport{QUICConfig: qconf}
        req := httptest.NewRequest(http.MethodGet, "https://example.com", nil)
index 70dcdef1c0a3ab9da2bed8f9ea51dfd04e3258aa..45a03a52ac41f469fdfe55ab79a5d92ab6ad5e4f 100644 (file)
@@ -5,6 +5,7 @@ import (
        "crypto/tls"
        "errors"
        "net"
+       "slices"
        "time"
 
        "github.com/quic-go/quic-go/internal/handshake"
@@ -25,6 +26,12 @@ const (
        Version2 = protocol.Version2
 )
 
+// SupportedVersions returns the support versions, sorted in descending order of preference.
+func SupportedVersions() []Version {
+       // clone the slice to prevent the caller from modifying the slice
+       return slices.Clone(protocol.SupportedVersions)
+}
+
 // A ClientToken is a token received by the client.
 // It can be used to skip address validation on future connection attempts.
 type ClientToken struct {