blob: 8e727d2512734be7eba65e41fb093170a146e70b [file] [log] [blame] [edit]
// Copyright 2024 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
//go:build go1.24 && goexperiment.synctest
package http3
import (
"net/netip"
"testing"
"testing/synctest"
"golang.org/x/net/internal/quic/quicwire"
"golang.org/x/net/quic"
)
func TestServerReceivePushStream(t *testing.T) {
// "[...] if a server receives a client-initiated push stream,
// this MUST be treated as a connection error of type H3_STREAM_CREATION_ERROR."
// https://www.rfc-editor.org/rfc/rfc9114.html#section-6.2.2-3
runSynctest(t, func(t testing.TB) {
ts := newTestServer(t)
tc := ts.connect()
tc.newStream(streamTypePush)
tc.wantClosed("invalid client-created push stream", errH3StreamCreationError)
})
}
func TestServerCancelPushForUnsentPromise(t *testing.T) {
runSynctest(t, func(t testing.TB) {
ts := newTestServer(t)
tc := ts.connect()
tc.greet()
const pushID = 100
tc.control.writeVarint(int64(frameTypeCancelPush))
tc.control.writeVarint(int64(quicwire.SizeVarint(pushID)))
tc.control.writeVarint(pushID)
tc.control.Flush()
tc.wantClosed("client canceled never-sent push ID", errH3IDError)
})
}
type testServer struct {
t testing.TB
s *Server
tn testNet
*testQUICEndpoint
addr netip.AddrPort
}
type testQUICEndpoint struct {
t testing.TB
e *quic.Endpoint
}
func (te *testQUICEndpoint) dial() {
}
type testServerConn struct {
ts *testServer
*testQUICConn
control *testQUICStream
}
func newTestServer(t testing.TB) *testServer {
t.Helper()
ts := &testServer{
t: t,
s: &Server{
Config: &quic.Config{
TLSConfig: testTLSConfig,
},
},
}
e := ts.tn.newQUICEndpoint(t, ts.s.Config)
ts.addr = e.LocalAddr()
go ts.s.Serve(e)
return ts
}
func (ts *testServer) connect() *testServerConn {
ts.t.Helper()
config := &quic.Config{TLSConfig: testTLSConfig}
e := ts.tn.newQUICEndpoint(ts.t, nil)
qconn, err := e.Dial(ts.t.Context(), "udp", ts.addr.String(), config)
if err != nil {
ts.t.Fatal(err)
}
tc := &testServerConn{
ts: ts,
testQUICConn: newTestQUICConn(ts.t, qconn),
}
synctest.Wait()
return tc
}
// greet performs initial connection handshaking with the server.
func (tc *testServerConn) greet() {
// Client creates a control stream.
tc.control = tc.newStream(streamTypeControl)
tc.control.writeVarint(int64(frameTypeSettings))
tc.control.writeVarint(0) // size
tc.control.Flush()
synctest.Wait()
}