mirror of
https://github.com/refraction-networking/uquic.git
synced 2025-04-01 19:27:35 +03:00
119 lines
4.2 KiB
Go
119 lines
4.2 KiB
Go
package http3
|
|
|
|
import (
|
|
"bytes"
|
|
"io"
|
|
"net/http"
|
|
|
|
mockquic "github.com/refraction-networking/uquic/internal/mocks/quic"
|
|
"github.com/refraction-networking/uquic/internal/utils"
|
|
|
|
"github.com/quic-go/qpack"
|
|
"go.uber.org/mock/gomock"
|
|
|
|
. "github.com/onsi/ginkgo/v2"
|
|
. "github.com/onsi/gomega"
|
|
)
|
|
|
|
var _ = Describe("Request Writer", func() {
|
|
var (
|
|
rw *requestWriter
|
|
str *mockquic.MockStream
|
|
strBuf *bytes.Buffer
|
|
)
|
|
|
|
decode := func(str io.Reader) map[string]string {
|
|
frame, err := parseNextFrame(str, nil)
|
|
ExpectWithOffset(1, err).ToNot(HaveOccurred())
|
|
ExpectWithOffset(1, frame).To(BeAssignableToTypeOf(&headersFrame{}))
|
|
headersFrame := frame.(*headersFrame)
|
|
data := make([]byte, headersFrame.Length)
|
|
_, err = io.ReadFull(str, data)
|
|
ExpectWithOffset(1, err).ToNot(HaveOccurred())
|
|
decoder := qpack.NewDecoder(nil)
|
|
hfs, err := decoder.DecodeFull(data)
|
|
ExpectWithOffset(1, err).ToNot(HaveOccurred())
|
|
values := make(map[string]string)
|
|
for _, hf := range hfs {
|
|
values[hf.Name] = hf.Value
|
|
}
|
|
return values
|
|
}
|
|
|
|
BeforeEach(func() {
|
|
rw = newRequestWriter(utils.DefaultLogger)
|
|
strBuf = &bytes.Buffer{}
|
|
str = mockquic.NewMockStream(mockCtrl)
|
|
str.EXPECT().Write(gomock.Any()).DoAndReturn(strBuf.Write).AnyTimes()
|
|
})
|
|
|
|
It("writes a GET request", func() {
|
|
req, err := http.NewRequest(http.MethodGet, "https://quic.clemente.io/index.html?foo=bar", nil)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(rw.WriteRequestHeader(str, req, false)).To(Succeed())
|
|
headerFields := decode(strBuf)
|
|
Expect(headerFields).To(HaveKeyWithValue(":authority", "quic.clemente.io"))
|
|
Expect(headerFields).To(HaveKeyWithValue(":method", "GET"))
|
|
Expect(headerFields).To(HaveKeyWithValue(":path", "/index.html?foo=bar"))
|
|
Expect(headerFields).To(HaveKeyWithValue(":scheme", "https"))
|
|
Expect(headerFields).ToNot(HaveKey("accept-encoding"))
|
|
})
|
|
|
|
It("rejects invalid host headers", func() {
|
|
req, err := http.NewRequest(http.MethodGet, "https://quic.clemente.io/index.html?foo=bar", nil)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
req.Host = "foo@bar" // @ is invalid
|
|
Expect(rw.WriteRequestHeader(str, req, false)).To(MatchError("http3: invalid Host header"))
|
|
})
|
|
|
|
It("sends cookies", func() {
|
|
req, err := http.NewRequest(http.MethodGet, "https://quic.clemente.io/", nil)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
cookie1 := &http.Cookie{
|
|
Name: "Cookie #1",
|
|
Value: "Value #1",
|
|
}
|
|
cookie2 := &http.Cookie{
|
|
Name: "Cookie #2",
|
|
Value: "Value #2",
|
|
}
|
|
req.AddCookie(cookie1)
|
|
req.AddCookie(cookie2)
|
|
Expect(rw.WriteRequestHeader(str, req, false)).To(Succeed())
|
|
headerFields := decode(strBuf)
|
|
Expect(headerFields).To(HaveKeyWithValue("cookie", `Cookie #1="Value #1"; Cookie #2="Value #2"`))
|
|
})
|
|
|
|
It("adds the header for gzip support", func() {
|
|
req, err := http.NewRequest(http.MethodGet, "https://quic.clemente.io/", nil)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(rw.WriteRequestHeader(str, req, true)).To(Succeed())
|
|
headerFields := decode(strBuf)
|
|
Expect(headerFields).To(HaveKeyWithValue("accept-encoding", "gzip"))
|
|
})
|
|
|
|
It("writes a CONNECT request", func() {
|
|
req, err := http.NewRequest(http.MethodConnect, "https://quic.clemente.io/", nil)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
Expect(rw.WriteRequestHeader(str, req, false)).To(Succeed())
|
|
headerFields := decode(strBuf)
|
|
Expect(headerFields).To(HaveKeyWithValue(":method", "CONNECT"))
|
|
Expect(headerFields).To(HaveKeyWithValue(":authority", "quic.clemente.io"))
|
|
Expect(headerFields).ToNot(HaveKey(":path"))
|
|
Expect(headerFields).ToNot(HaveKey(":scheme"))
|
|
Expect(headerFields).ToNot(HaveKey(":protocol"))
|
|
})
|
|
|
|
It("writes an Extended CONNECT request", func() {
|
|
req, err := http.NewRequest(http.MethodConnect, "https://quic.clemente.io/foobar", nil)
|
|
Expect(err).ToNot(HaveOccurred())
|
|
req.Proto = "webtransport"
|
|
Expect(rw.WriteRequestHeader(str, req, false)).To(Succeed())
|
|
headerFields := decode(strBuf)
|
|
Expect(headerFields).To(HaveKeyWithValue(":authority", "quic.clemente.io"))
|
|
Expect(headerFields).To(HaveKeyWithValue(":method", "CONNECT"))
|
|
Expect(headerFields).To(HaveKeyWithValue(":path", "/foobar"))
|
|
Expect(headerFields).To(HaveKeyWithValue(":scheme", "https"))
|
|
Expect(headerFields).To(HaveKeyWithValue(":protocol", "webtransport"))
|
|
})
|
|
})
|