Merge pull request #2329 from lucas-clemente/interop-0rtt

add support for the upcoming 0-RTT interop test case
This commit is contained in:
Marten Seemann
2020-03-08 16:17:30 +07:00
committed by GitHub
5 changed files with 33 additions and 20 deletions

View File

@@ -74,14 +74,16 @@ func runTestcase(testcase string) error {
QuicConfig: quicConf, QuicConfig: quicConf,
} }
defer r.Close() defer r.Close()
return downloadFiles(r, urls) return downloadFiles(r, urls, false)
case "handshake", "transfer", "retry": case "handshake", "transfer", "retry":
case "multiconnect": case "multiconnect":
return runMultiConnectTest(urls) return runMultiConnectTest(urls)
case "versionnegotiation": case "versionnegotiation":
return runVersionNegotiationTest(urls) return runVersionNegotiationTest(urls)
case "resumption": case "resumption":
return runResumptionTest(urls) return runResumptionTest(urls, false)
case "zerortt":
return runResumptionTest(urls, true)
default: default:
return errUnsupported return errUnsupported
} }
@@ -91,7 +93,7 @@ func runTestcase(testcase string) error {
QuicConfig: quicConf, QuicConfig: quicConf,
} }
defer r.Close() defer r.Close()
return downloadFiles(r, urls) return downloadFiles(r, urls, false)
} }
func runVersionNegotiationTest(urls []string) error { func runVersionNegotiationTest(urls []string) error {
@@ -99,7 +101,7 @@ func runVersionNegotiationTest(urls []string) error {
return errors.New("expected at least 2 URLs") return errors.New("expected at least 2 URLs")
} }
protocol.SupportedVersions = []protocol.VersionNumber{0x1a2a3a4a} protocol.SupportedVersions = []protocol.VersionNumber{0x1a2a3a4a}
err := downloadFile(&http09.RoundTripper{}, urls[0]) err := downloadFile(&http09.RoundTripper{}, urls[0], false)
if err == nil { if err == nil {
return errors.New("expected version negotiation to fail") return errors.New("expected version negotiation to fail")
} }
@@ -112,7 +114,7 @@ func runVersionNegotiationTest(urls []string) error {
func runMultiConnectTest(urls []string) error { func runMultiConnectTest(urls []string) error {
for _, url := range urls { for _, url := range urls {
r := &http09.RoundTripper{TLSClientConfig: tlsConf} r := &http09.RoundTripper{TLSClientConfig: tlsConf}
if err := downloadFile(r, url); err != nil { if err := downloadFile(r, url, false); err != nil {
return err return err
} }
if err := r.Close(); err != nil { if err := r.Close(); err != nil {
@@ -122,7 +124,7 @@ func runMultiConnectTest(urls []string) error {
return nil return nil
} }
func runResumptionTest(urls []string) error { func runResumptionTest(urls []string, use0RTT bool) error {
if len(urls) < 2 { if len(urls) < 2 {
return errors.New("expected at least 2 URLs") return errors.New("expected at least 2 URLs")
} }
@@ -131,7 +133,7 @@ func runResumptionTest(urls []string) error {
// do the first transfer // do the first transfer
r := &http09.RoundTripper{TLSClientConfig: tlsConf} r := &http09.RoundTripper{TLSClientConfig: tlsConf}
if err := downloadFiles(r, urls[:1]); err != nil { if err := downloadFiles(r, urls[:1], false); err != nil {
return err return err
} }
r.Close() r.Close()
@@ -139,22 +141,26 @@ func runResumptionTest(urls []string) error {
// reestablish the connection, using the session ticket that the server (hopefully provided) // reestablish the connection, using the session ticket that the server (hopefully provided)
r = &http09.RoundTripper{TLSClientConfig: tlsConf} r = &http09.RoundTripper{TLSClientConfig: tlsConf}
defer r.Close() defer r.Close()
return downloadFiles(r, urls[1:]) return downloadFiles(r, urls[1:], use0RTT)
} }
func downloadFiles(cl http.RoundTripper, urls []string) error { func downloadFiles(cl http.RoundTripper, urls []string, use0RTT bool) error {
var g errgroup.Group var g errgroup.Group
for _, u := range urls { for _, u := range urls {
url := u url := u
g.Go(func() error { g.Go(func() error {
return downloadFile(cl, url) return downloadFile(cl, url, use0RTT)
}) })
} }
return g.Wait() return g.Wait()
} }
func downloadFile(cl http.RoundTripper, url string) error { func downloadFile(cl http.RoundTripper, url string, use0RTT bool) error {
req, err := http.NewRequest(http.MethodGet, url, nil) method := http.MethodGet
if use0RTT {
method = http09.MethodGet0RTT
}
req, err := http.NewRequest(method, url, nil)
if err != nil { if err != nil {
return err return err
} }

View File

@@ -15,6 +15,10 @@ import (
"github.com/lucas-clemente/quic-go" "github.com/lucas-clemente/quic-go"
) )
// MethodGet0RTT allows a GET request to be sent using 0-RTT.
// Note that 0-RTT data doesn't provide replay protection.
const MethodGet0RTT = "GET_0RTT"
// RoundTripper performs HTTP/0.9 roundtrips over QUIC. // RoundTripper performs HTTP/0.9 roundtrips over QUIC.
type RoundTripper struct { type RoundTripper struct {
mutex sync.Mutex mutex sync.Mutex
@@ -30,7 +34,7 @@ var _ http.RoundTripper = &RoundTripper{}
// RoundTrip performs a HTTP/0.9 request. // RoundTrip performs a HTTP/0.9 request.
// It only supports GET requests. // It only supports GET requests.
func (r *RoundTripper) RoundTrip(req *http.Request) (*http.Response, error) { func (r *RoundTripper) RoundTrip(req *http.Request) (*http.Response, error) {
if req.Method != http.MethodGet { if req.Method != http.MethodGet && req.Method != MethodGet0RTT {
return nil, errors.New("only GET requests supported") return nil, errors.New("only GET requests supported")
} }
@@ -76,17 +80,20 @@ type client struct {
quicConf *quic.Config quicConf *quic.Config
once sync.Once once sync.Once
sess quic.Session sess quic.EarlySession
dialErr error dialErr error
} }
func (c *client) RoundTrip(req *http.Request) (*http.Response, error) { func (c *client) RoundTrip(req *http.Request) (*http.Response, error) {
c.once.Do(func() { c.once.Do(func() {
c.sess, c.dialErr = quic.DialAddr(c.hostname, c.tlsConf, c.quicConf) c.sess, c.dialErr = quic.DialAddrEarly(c.hostname, c.tlsConf, c.quicConf)
}) })
if c.dialErr != nil { if c.dialErr != nil {
return nil, c.dialErr return nil, c.dialErr
} }
if req.Method != MethodGet0RTT {
<-c.sess.HandshakeComplete().Done()
}
return c.doRequest(req) return c.doRequest(req)
} }

View File

@@ -36,8 +36,8 @@ var _ = Describe("HTTP 0.9 integration tests", func() {
defer close(done) defer close(done)
_ = server.ListenAndServe() _ = server.ListenAndServe()
}() }()
var ln quic.Listener var ln quic.EarlyListener
Eventually(func() quic.Listener { Eventually(func() quic.EarlyListener {
server.mutex.Lock() server.mutex.Lock()
defer server.mutex.Unlock() defer server.mutex.Unlock()
ln = server.listener ln = server.listener

View File

@@ -41,7 +41,7 @@ type Server struct {
QuicConfig *quic.Config QuicConfig *quic.Config
mutex sync.Mutex mutex sync.Mutex
listener quic.Listener listener quic.EarlyListener
} }
// Close closes the server. // Close closes the server.
@@ -69,7 +69,7 @@ func (s *Server) ListenAndServe() error {
tlsConf := s.TLSConfig.Clone() tlsConf := s.TLSConfig.Clone()
tlsConf.NextProtos = []string{h09alpn} tlsConf.NextProtos = []string{h09alpn}
ln, err := quic.Listen(conn, tlsConf, s.QuicConfig) ln, err := quic.ListenEarly(conn, tlsConf, s.QuicConfig)
if err != nil { if err != nil {
return err return err
} }

View File

@@ -51,7 +51,7 @@ func main() {
tlsConf.KeyLogWriter = keyLog tlsConf.KeyLogWriter = keyLog
switch testcase { switch testcase {
case "versionnegotiation", "handshake", "transfer", "resumption", "multiconnect": case "versionnegotiation", "handshake", "transfer", "resumption", "zerortt", "multiconnect":
err = runHTTP09Server(quicConf) err = runHTTP09Server(quicConf)
case "retry": case "retry":
// By default, quic-go performs a Retry on every incoming connection. // By default, quic-go performs a Retry on every incoming connection.