http2: don't panic when ServeConn is passed a nil options

Fixes golang/go#75286

Change-Id: I91e6a0a61234c81f809b74151946dddde9099078
Reviewed-on: https://go-review.googlesource.com/c/net/+/700999
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
Reviewed-by: Nicholas Husin <nsh@golang.org>
Reviewed-by: Nicholas Husin <husin@google.com>
Auto-Submit: Nicholas Husin <nsh@golang.org>
This commit is contained in:
Damien Neil
2025-09-05 11:21:51 -07:00
committed by Gopher Robot
parent a2a62f206b
commit 1ff92d3eb0
3 changed files with 43 additions and 19 deletions

View File

@@ -287,7 +287,7 @@ func TestNoUnicodeStrings(t *testing.T) {
}
// setForTest sets *p = v, and restores its original value in t.Cleanup.
func setForTest[T any](t *testing.T, p *T, v T) {
func setForTest[T any](t testing.TB, p *T, v T) {
orig := *p
t.Cleanup(func() {
*p = orig

View File

@@ -390,6 +390,9 @@ func (o *ServeConnOpts) handler() http.Handler {
//
// The opts parameter is optional. If nil, default values are used.
func (s *Server) ServeConn(c net.Conn, opts *ServeConnOpts) {
if opts == nil {
opts = &ServeConnOpts{}
}
s.serveConn(c, opts, nil)
}

View File

@@ -3266,26 +3266,47 @@ func (c *issue53Conn) SetDeadline(t time.Time) error { return nil }
func (c *issue53Conn) SetReadDeadline(t time.Time) error { return nil }
func (c *issue53Conn) SetWriteDeadline(t time.Time) error { return nil }
// TestServeConnNilOpts ensures that Server.ServeConn(conn, nil) works.
//
// golang.org/issue/33839
func TestServeConnOptsNilReceiverBehavior(t *testing.T) {
synctestTest(t, testServeConnOptsNilReceiverBehavior)
}
func testServeConnOptsNilReceiverBehavior(t testing.TB) {
defer func() {
if r := recover(); r != nil {
t.Errorf("got a panic that should not happen: %v", r)
}
}()
func TestServeConnNilOpts(t *testing.T) { synctestTest(t, testServeConnNilOpts) }
func testServeConnNilOpts(t testing.TB) {
// A nil ServeConnOpts uses http.DefaultServeMux as the handler.
var gotRequest string
var mux http.ServeMux
mux.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
gotRequest = r.URL.Path
})
setForTest(t, &http.DefaultServeMux, &mux)
var o *ServeConnOpts
if o.context() == nil {
t.Error("o.context should not return nil")
}
if o.baseConfig() == nil {
t.Error("o.baseConfig should not return nil")
}
if o.handler() == nil {
t.Error("o.handler should not return nil")
srvConn, cliConn := net.Pipe()
defer srvConn.Close()
defer cliConn.Close()
s2 := &Server{}
go s2.ServeConn(srvConn, nil)
fr := NewFramer(cliConn, cliConn)
io.WriteString(cliConn, ClientPreface)
fr.WriteSettings()
fr.WriteSettingsAck()
var henc hpackEncoder
const reqPath = "/request"
fr.WriteHeaders(HeadersFrameParam{
StreamID: 1,
BlockFragment: henc.encodeHeaderRaw(t,
":method", "GET",
":path", reqPath,
":scheme", "https",
":authority", "foo.com",
),
EndStream: true,
EndHeaders: true,
})
synctest.Wait()
if got, want := gotRequest, reqPath; got != want {
t.Errorf("got request: %q, want %q", got, want)
}
}