package h2quic import ( "bytes" "io" "net/http" . "github.com/onsi/ginkgo" . "github.com/onsi/gomega" ) type mockQuicRoundTripper struct{} func (m *mockQuicRoundTripper) Dial() error { return nil } func (m *mockQuicRoundTripper) Do(req *http.Request) (*http.Response, error) { return &http.Response{Request: req}, nil } type mockBody struct { reader bytes.Reader readErr error closeErr error closed bool } func (m *mockBody) Read(p []byte) (int, error) { if m.readErr != nil { return 0, m.readErr } return m.reader.Read(p) } func (m *mockBody) SetData(data []byte) { m.reader = *bytes.NewReader(data) } func (m *mockBody) Close() error { m.closed = true return m.closeErr } // make sure the mockBody can be used as a http.Request.Body var _ io.ReadCloser = &mockBody{} var _ = Describe("RoundTripper", func() { var ( rt *QuicRoundTripper req1 *http.Request ) BeforeEach(func() { rt = &QuicRoundTripper{} var err error req1, err = http.NewRequest("GET", "https://www.example.org/file1.html", nil) Expect(err).ToNot(HaveOccurred()) }) It("reuses existing clients", func() { rt.clients = make(map[string]h2quicClient) rt.clients["www.example.org:443"] = &mockQuicRoundTripper{} rsp, err := rt.RoundTrip(req1) Expect(err).ToNot(HaveOccurred()) Expect(rsp.Request).To(Equal(req1)) Expect(rt.clients).To(HaveLen(1)) }) It("disable compression", func() { Expect(rt.disableCompression()).To(BeFalse()) rt.DisableCompression = true Expect(rt.disableCompression()).To(BeTrue()) }) Context("validating request", func() { It("rejects plain HTTP requests", func() { req, err := http.NewRequest("GET", "http://www.example.org/", nil) req.Body = &mockBody{} Expect(err).ToNot(HaveOccurred()) _, err = rt.RoundTrip(req) Expect(err).To(MatchError("quic: unsupported protocol scheme: http")) Expect(req.Body.(*mockBody).closed).To(BeTrue()) }) It("rejects requests without a URL", func() { req1.URL = nil req1.Body = &mockBody{} _, err := rt.RoundTrip(req1) Expect(err).To(MatchError("quic: nil Request.URL")) Expect(req1.Body.(*mockBody).closed).To(BeTrue()) }) It("rejects request without a URL Host", func() { req1.URL.Host = "" req1.Body = &mockBody{} _, err := rt.RoundTrip(req1) Expect(err).To(MatchError("quic: no Host in request URL")) Expect(req1.Body.(*mockBody).closed).To(BeTrue()) }) It("doesn't try to close the body if the request doesn't have one", func() { req1.URL = nil Expect(req1.Body).To(BeNil()) _, err := rt.RoundTrip(req1) Expect(err).To(MatchError("quic: nil Request.URL")) }) It("rejects requests without a header", func() { req1.Header = nil req1.Body = &mockBody{} _, err := rt.RoundTrip(req1) Expect(err).To(MatchError("quic: nil Request.Header")) Expect(req1.Body.(*mockBody).closed).To(BeTrue()) }) It("rejects requests with invalid header name fields", func() { req1.Header.Add("foobär", "value") _, err := rt.RoundTrip(req1) Expect(err).To(MatchError("quic: invalid http header field name \"foobär\"")) }) It("rejects requests with invalid header name values", func() { req1.Header.Add("foo", string([]byte{0x7})) _, err := rt.RoundTrip(req1) Expect(err.Error()).To(ContainSubstring("quic: invalid http header field value")) }) It("rejects requests with an invalid request method", func() { req1.Method = "foobär" req1.Body = &mockBody{} _, err := rt.RoundTrip(req1) Expect(err).To(MatchError("quic: invalid method \"foobär\"")) Expect(req1.Body.(*mockBody).closed).To(BeTrue()) }) }) })