dependency-inject quic.Listen and quic.ListenAddr in h2quic.Server

This commit is contained in:
Marten Seemann
2017-07-08 16:02:34 +08:00
parent e21f74d317
commit 79c7ed4ed1
2 changed files with 26 additions and 34 deletions

View File

@@ -29,6 +29,12 @@ type remoteCloser interface {
CloseRemote(protocol.ByteCount) CloseRemote(protocol.ByteCount)
} }
// allows mocking of quic.Listen and quic.ListenAddr
var (
quicListen = quic.Listen
quicListenAddr = quic.ListenAddr
)
// Server is a HTTP2 server listening for QUIC connections. // Server is a HTTP2 server listening for QUIC connections.
type Server struct { type Server struct {
*http.Server *http.Server
@@ -90,9 +96,9 @@ func (s *Server) serveImpl(tlsConfig *tls.Config, conn net.PacketConn) error {
var ln quic.Listener var ln quic.Listener
var err error var err error
if conn == nil { if conn == nil {
ln, err = quic.ListenAddr(s.Addr, tlsConfig, &config) ln, err = quicListenAddr(s.Addr, tlsConfig, &config)
} else { } else {
ln, err = quic.Listen(conn, tlsConfig, &config) ln, err = quicListen(conn, tlsConfig, &config)
} }
if err != nil { if err != nil {
s.listenerMutex.Unlock() s.listenerMutex.Unlock()

View File

@@ -2,13 +2,12 @@ package h2quic
import ( import (
"bytes" "bytes"
"crypto/tls"
"errors"
"io" "io"
"net" "net"
"net/http" "net/http"
"os"
"runtime"
"sync" "sync"
"syscall"
"time" "time"
"golang.org/x/net/http2" "golang.org/x/net/http2"
@@ -66,9 +65,10 @@ func (s *mockSession) WaitUntilClosed() { panic("not implemented") }
var _ = Describe("H2 server", func() { var _ = Describe("H2 server", func() {
var ( var (
s *Server s *Server
session *mockSession session *mockSession
dataStream *mockStream dataStream *mockStream
origQuicListenAddr = quicListenAddr
) )
BeforeEach(func() { BeforeEach(func() {
@@ -80,6 +80,11 @@ var _ = Describe("H2 server", func() {
dataStream = newMockStream(0) dataStream = newMockStream(0)
close(dataStream.unblockRead) close(dataStream.unblockRead)
session = &mockSession{dataStream: dataStream} session = &mockSession{dataStream: dataStream}
origQuicListenAddr = quicListenAddr
})
AfterEach(func() {
quicListenAddr = origQuicListenAddr
}) })
Context("handling requests", func() { Context("handling requests", func() {
@@ -399,7 +404,6 @@ var _ = Describe("H2 server", func() {
Expect(err).To(MatchError("ListenAndServe may only be called once")) Expect(err).To(MatchError("ListenAndServe may only be called once"))
err = s.Close() err = s.Close()
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
}, 0.5) }, 0.5)
}) })
@@ -436,31 +440,13 @@ var _ = Describe("H2 server", func() {
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
}) })
It("at least errors in global ListenAndServeQUIC", func() { It("errors when listening fails", func() {
// It's quite hard to test this, since we cannot properly shutdown the server testErr := errors.New("listen error")
// once it's started. So, we open a socket on the same port before the test, quicListenAddr = func(addr string, tlsConf *tls.Config, config *quic.Config) (quic.Listener, error) {
// so that ListenAndServeQUIC definitely fails. This way we know it at least return nil, testErr
// created a socket on the proper address :)
const addr = "127.0.0.1:4826"
udpAddr, err := net.ResolveUDPAddr("udp", addr)
Expect(err).NotTo(HaveOccurred())
c, err := net.ListenUDP("udp", udpAddr)
Expect(err).NotTo(HaveOccurred())
defer c.Close()
fullpem, privkey := testdata.GetCertificatePaths()
err = ListenAndServeQUIC(addr, fullpem, privkey, nil)
// Check that it's an EADDRINUSE
Expect(err).ToNot(BeNil())
opErr, ok := err.(*net.OpError)
Expect(ok).To(BeTrue())
syscallErr, ok := opErr.Err.(*os.SyscallError)
Expect(ok).To(BeTrue())
if runtime.GOOS == "windows" {
// for some reason, Windows return a different error number, corresponding to an WSAEADDRINUSE error
// see https://msdn.microsoft.com/en-us/library/windows/desktop/ms681391(v=vs.85).aspx
Expect(syscallErr.Err).To(Equal(syscall.Errno(0x2740)))
} else {
Expect(syscallErr.Err).To(MatchError(syscall.EADDRINUSE))
} }
fullpem, privkey := testdata.GetCertificatePaths()
err := ListenAndServeQUIC("", fullpem, privkey, nil)
Expect(err).To(MatchError(testErr))
}) })
}) })