http3: add compatibility with net/http.ResponseController (#3790)

* feat: compatibility with "net/http".ResponseController

* better deadline tests

* don't run deadline tests on Go 1.19

* skip deadline tests on Go 1.19
This commit is contained in:
Kévin Dunglas 2023-05-01 13:40:33 +02:00 committed by GitHub
parent 4a2a5740b2
commit 172123c340
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 129 additions and 0 deletions

View file

@ -0,0 +1,22 @@
//go:build go1.19 && !go1.20
package self_test
import (
"errors"
"net/http"
"time"
)
var (
go120 = false
errNotSupported = errors.New("not supported")
)
func setReadDeadline(w http.ResponseWriter, deadline time.Time) error {
return errNotSupported
}
func setWriteDeadline(w http.ResponseWriter, deadline time.Time) error {
return errNotSupported
}

View file

@ -0,0 +1,22 @@
//go:build go1.20
package self_test
import (
"net/http"
"time"
)
var go120 = true
func setReadDeadline(w http.ResponseWriter, deadline time.Time) error {
rc := http.NewResponseController(w)
return rc.SetReadDeadline(deadline)
}
func setWriteDeadline(w http.ResponseWriter, deadline time.Time) error {
rc := http.NewResponseController(w)
return rc.SetWriteDeadline(deadline)
}

View file

@ -11,6 +11,7 @@ import (
"io"
"net"
"net/http"
"os"
"strconv"
"time"
@ -25,6 +26,17 @@ import (
"github.com/onsi/gomega/gbytes"
)
type neverEnding byte
func (b neverEnding) Read(p []byte) (n int, err error) {
for i := range p {
p[i] = byte(b)
}
return len(p), nil
}
const deadlineDelay = 250 * time.Millisecond
var _ = Describe("HTTP tests", func() {
var (
mux *http.ServeMux
@ -374,6 +386,60 @@ var _ = Describe("HTTP tests", func() {
Expect(repl).To(Equal(data))
})
It("supports read deadlines", func() {
if !go120 {
Skip("This test requires Go 1.20+")
}
mux.HandleFunc("/read-deadline", func(w http.ResponseWriter, r *http.Request) {
defer GinkgoRecover()
err := setReadDeadline(w, time.Now().Add(deadlineDelay))
Expect(err).ToNot(HaveOccurred())
body, err := io.ReadAll(r.Body)
Expect(err).To(MatchError(os.ErrDeadlineExceeded))
Expect(body).To(ContainSubstring("aa"))
w.Write([]byte("ok"))
})
expectedEnd := time.Now().Add(deadlineDelay)
resp, err := client.Post("https://localhost:"+port+"/read-deadline", "text/plain", neverEnding('a'))
Expect(err).ToNot(HaveOccurred())
Expect(resp.StatusCode).To(Equal(200))
body, err := io.ReadAll(gbytes.TimeoutReader(resp.Body, 2*deadlineDelay))
Expect(err).ToNot(HaveOccurred())
Expect(time.Now().After(expectedEnd)).To(BeTrue())
Expect(string(body)).To(Equal("ok"))
})
It("supports write deadlines", func() {
if !go120 {
Skip("This test requires Go 1.20+")
}
mux.HandleFunc("/write-deadline", func(w http.ResponseWriter, r *http.Request) {
defer GinkgoRecover()
err := setWriteDeadline(w, time.Now().Add(deadlineDelay))
Expect(err).ToNot(HaveOccurred())
_, err = io.Copy(w, neverEnding('a'))
Expect(err).To(MatchError(os.ErrDeadlineExceeded))
})
expectedEnd := time.Now().Add(deadlineDelay)
resp, err := client.Get("https://localhost:" + port + "/write-deadline")
Expect(err).ToNot(HaveOccurred())
Expect(resp.StatusCode).To(Equal(200))
body, err := io.ReadAll(gbytes.TimeoutReader(resp.Body, 2*deadlineDelay))
Expect(err).ToNot(HaveOccurred())
Expect(time.Now().After(expectedEnd)).To(BeTrue())
Expect(string(body)).To(ContainSubstring("aa"))
})
if version != protocol.VersionDraft29 {
It("serves other QUIC connections", func() {
tlsConf := testdata.GetTLSConfig()