Repository: quic-go/quic-go
Pull request #4651 (2024-08-31 04:35:29)

interop: simplify API of http09.Server
Removes the `ListenAndServe` method in favor of a `ServeListener` method.


Patch:
diff --git a/interop/http09/client.go b/interop/http09/client.go
index b6de79ef..bb3f0d70 100644
--- a/interop/http09/client.go
+++ b/interop/http09/client.go
@@ -52,7 +52,7 @@ func (r *RoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
 		if r.TLSClientConfig != nil {
 			tlsConf = r.TLSClientConfig.Clone()
 		}
-		tlsConf.NextProtos = []string{h09alpn}
+		tlsConf.NextProtos = []string{NextProto}
 		c = &client{
 			hostname: hostname,
 			tlsConf:  tlsConf,
diff --git a/interop/http09/server.go b/interop/http09/server.go
index 7a1f30b8..9a6c7b32 100644
--- a/interop/http09/server.go
+++ b/interop/http09/server.go
@@ -5,17 +5,15 @@ import (
 	"errors"
 	"io"
 	"log"
-	"net"
 	"net/http"
 	"net/url"
 	"runtime"
 	"strings"
-	"sync"
 
 	"github.com/quic-go/quic-go"
 )
 
-const h09alpn = "hq-interop"
+const NextProto = "hq-interop"
 
 type responseWriter struct {
 	io.Writer
@@ -36,51 +34,14 @@ func (w *responseWriter) WriteHeader(int) {}
 // Server is a HTTP/0.9 server listening for QUIC connections.
 type Server struct {
 	*http.Server
-
-	ForceRetry bool
-	QuicConfig *quic.Config
-
-	mutex    sync.Mutex
-	listener *quic.EarlyListener
-}
-
-// Close closes the server.
-func (s *Server) Close() error {
-	s.mutex.Lock()
-	defer s.mutex.Unlock()
-
-	return s.listener.Close()
 }
 
 // ListenAndServe listens and serves HTTP/0.9 over QUIC.
-func (s *Server) ListenAndServe() error {
+func (s *Server) ServeListener(ln *quic.EarlyListener) error {
 	if s.Server == nil {
 		return errors.New("use of http3.Server without http.Server")
 	}
 
-	udpAddr, err := net.ResolveUDPAddr("udp", s.Addr)
-	if err != nil {
-		return err
-	}
-	conn, err := net.ListenUDP("udp", udpAddr)
-	if err != nil {
-		return err
-	}
-
-	tlsConf := s.TLSConfig.Clone()
-	tlsConf.NextProtos = []string{h09alpn}
-	tr := quic.Transport{Conn: conn}
-	if s.ForceRetry {
-		tr.VerifySourceAddress = func(net.Addr) bool { return true }
-	}
-	ln, err := tr.ListenEarly(tlsConf, s.QuicConfig)
-	if err != nil {
-		return err
-	}
-	s.mutex.Lock()
-	s.listener = ln
-	s.mutex.Unlock()
-
 	for {
 		conn, err := ln.Accept(context.Background())
 		if err != nil {
diff --git a/interop/server/main.go b/interop/server/main.go
index fee8aaeb..018d9cf8 100644
--- a/interop/server/main.go
+++ b/interop/server/main.go
@@ -4,6 +4,7 @@ import (
 	"crypto/tls"
 	"fmt"
 	"log"
+	"net"
 	"net/http"
 	"os"
 
@@ -71,16 +72,26 @@ func main() {
 }
 
 func runHTTP09Server(quicConf *quic.Config, forceRetry bool) error {
-	server := http09.Server{
-		Server: &http.Server{
-			Addr:      ":443",
-			TLSConfig: tlsConf,
-		},
-		ForceRetry: forceRetry,
-		QuicConfig: quicConf,
-	}
 	http.DefaultServeMux.Handle("/", http.FileServer(http.Dir("/www")))
-	return server.ListenAndServe()
+	server := http09.Server{}
+
+	udpAddr, err := net.ResolveUDPAddr("udp", ":443")
+	if err != nil {
+		return err
+	}
+	conn, err := net.ListenUDP("udp", udpAddr)
+	if err != nil {
+		return err
+	}
+	tr := &quic.Transport{
+		Conn:                conn,
+		VerifySourceAddress: func(net.Addr) bool { return forceRetry },
+	}
+	ln, err := tr.ListenEarly(tlsConf, quicConf)
+	if err != nil {
+		return err
+	}
+	return server.ServeListener(ln)
 }
 
 func runHTTP3Server(quicConf *quic.Config) error {


Test patch:
diff --git a/interop/http09/http_test.go b/interop/http09/http_test.go
index 03f39263..fb0e5e06 100644
--- a/interop/http09/http_test.go
+++ b/interop/http09/http_test.go
@@ -7,7 +7,6 @@ import (
 	"net"
 	"net/http"
 	"net/http/httptest"
-	"time"
 
 	"github.com/quic-go/quic-go"
 	"github.com/quic-go/quic-go/internal/testdata"
@@ -18,9 +17,9 @@ import (
 
 var _ = Describe("HTTP 0.9 integration tests", func() {
 	var (
-		server *Server
-		saddr  net.Addr
-		done   chan struct{}
+		ln    *quic.EarlyListener
+		saddr net.Addr
+		done  chan struct{}
 	)
 
 	http.HandleFunc("/helloworld", func(w http.ResponseWriter, r *http.Request) {
@@ -28,28 +27,27 @@ var _ = Describe("HTTP 0.9 integration tests", func() {
 	})
 
 	BeforeEach(func() {
-		server = &Server{
-			Server: &http.Server{TLSConfig: testdata.GetTLSConfig()},
+		server := &Server{
+			Server: &http.Server{},
 		}
+		conn, err := net.ListenUDP("udp", &net.UDPAddr{IP: net.IPv4(127, 0, 0, 1), Port: 0})
+		Expect(err).ToNot(HaveOccurred())
+		tr := &quic.Transport{Conn: conn}
+		tlsConf := testdata.GetTLSConfig()
+		tlsConf.NextProtos = []string{NextProto}
+		ln, err = tr.ListenEarly(tlsConf, &quic.Config{})
+		Expect(err).ToNot(HaveOccurred())
 		done = make(chan struct{})
 		go func() {
 			defer GinkgoRecover()
 			defer close(done)
-			_ = server.ListenAndServe()
+			_ = server.ServeListener(ln)
 		}()
-		var ln *quic.EarlyListener
-		Eventually(func() *quic.EarlyListener {
-			server.mutex.Lock()
-			defer server.mutex.Unlock()
-			ln = server.listener
-			return server.listener
-		}, 5*time.Second).ShouldNot(BeNil())
 		saddr = ln.Addr()
-		saddr.(*net.UDPAddr).IP = net.IP{127, 0, 0, 1}
 	})
 
 	AfterEach(func() {
-		Expect(server.Close()).To(Succeed())
+		Expect(ln.Close()).To(Succeed())
 		Eventually(done).Should(BeClosed())
 	})