forked from quic-go/quic-go
add support for serializing Extended CONNECT requests (#3360)
This commit is contained in:
@@ -113,7 +113,9 @@ func (w *requestWriter) writeHeaders(wr io.Writer, req *http.Request, gzip bool)
|
||||
}
|
||||
|
||||
// copied from net/transport.go
|
||||
|
||||
// Modified to support Extended CONNECT:
|
||||
// Contrary to what the godoc for the http.Request says,
|
||||
// we do respect the Proto field if the method is CONNECT.
|
||||
func (w *requestWriter) encodeHeaders(req *http.Request, addGzipHeader bool, trailers string, contentLength int64) error {
|
||||
host := req.Host
|
||||
if host == "" {
|
||||
@@ -124,8 +126,11 @@ func (w *requestWriter) encodeHeaders(req *http.Request, addGzipHeader bool, tra
|
||||
return err
|
||||
}
|
||||
|
||||
// http.NewRequest sets this field to HTTP/1.1
|
||||
isExtendedConnect := req.Method == http.MethodConnect && req.Proto != "" && req.Proto != "HTTP/1.1"
|
||||
|
||||
var path string
|
||||
if req.Method != "CONNECT" {
|
||||
if req.Method != http.MethodConnect || isExtendedConnect {
|
||||
path = req.URL.RequestURI()
|
||||
if !validPseudoPath(path) {
|
||||
orig := path
|
||||
@@ -162,10 +167,13 @@ func (w *requestWriter) encodeHeaders(req *http.Request, addGzipHeader bool, tra
|
||||
// [RFC3986]).
|
||||
f(":authority", host)
|
||||
f(":method", req.Method)
|
||||
if req.Method != "CONNECT" {
|
||||
if req.Method != http.MethodConnect || isExtendedConnect {
|
||||
f(":path", path)
|
||||
f(":scheme", req.URL.Scheme)
|
||||
}
|
||||
if isExtendedConnect {
|
||||
f(":protocol", req.Proto)
|
||||
}
|
||||
if trailers != "" {
|
||||
f("trailer", trailers)
|
||||
}
|
||||
|
||||
@@ -6,12 +6,12 @@ import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/marten-seemann/qpack"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
mockquic "github.com/lucas-clemente/quic-go/internal/mocks/quic"
|
||||
"github.com/lucas-clemente/quic-go/internal/utils"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/marten-seemann/qpack"
|
||||
|
||||
. "github.com/onsi/ginkgo"
|
||||
. "github.com/onsi/gomega"
|
||||
)
|
||||
@@ -58,7 +58,7 @@ var _ = Describe("Request Writer", func() {
|
||||
|
||||
It("writes a GET request", func() {
|
||||
str.EXPECT().Close()
|
||||
req, err := http.NewRequest("GET", "https://quic.clemente.io/index.html?foo=bar", nil)
|
||||
req, err := http.NewRequest(http.MethodGet, "https://quic.clemente.io/index.html?foo=bar", nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(rw.WriteRequest(str, req, false)).To(Succeed())
|
||||
headerFields := decode(strBuf)
|
||||
@@ -73,7 +73,7 @@ var _ = Describe("Request Writer", func() {
|
||||
closed := make(chan struct{})
|
||||
str.EXPECT().Close().Do(func() { close(closed) })
|
||||
postData := bytes.NewReader([]byte("foobar"))
|
||||
req, err := http.NewRequest("POST", "https://quic.clemente.io/upload.html", postData)
|
||||
req, err := http.NewRequest(http.MethodPost, "https://quic.clemente.io/upload.html", postData)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(rw.WriteRequest(str, req, false)).To(Succeed())
|
||||
|
||||
@@ -94,7 +94,7 @@ var _ = Describe("Request Writer", func() {
|
||||
It("writes a POST request, if the Body returns an EOF immediately", func() {
|
||||
closed := make(chan struct{})
|
||||
str.EXPECT().Close().Do(func() { close(closed) })
|
||||
req, err := http.NewRequest("POST", "https://quic.clemente.io/upload.html", &foobarReader{})
|
||||
req, err := http.NewRequest(http.MethodPost, "https://quic.clemente.io/upload.html", &foobarReader{})
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(rw.WriteRequest(str, req, false)).To(Succeed())
|
||||
|
||||
@@ -110,7 +110,7 @@ var _ = Describe("Request Writer", func() {
|
||||
|
||||
It("sends cookies", func() {
|
||||
str.EXPECT().Close()
|
||||
req, err := http.NewRequest("GET", "https://quic.clemente.io/", nil)
|
||||
req, err := http.NewRequest(http.MethodGet, "https://quic.clemente.io/", nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
cookie1 := &http.Cookie{
|
||||
Name: "Cookie #1",
|
||||
@@ -129,10 +129,37 @@ var _ = Describe("Request Writer", func() {
|
||||
|
||||
It("adds the header for gzip support", func() {
|
||||
str.EXPECT().Close()
|
||||
req, err := http.NewRequest("GET", "https://quic.clemente.io/", nil)
|
||||
req, err := http.NewRequest(http.MethodGet, "https://quic.clemente.io/", nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(rw.WriteRequest(str, req, true)).To(Succeed())
|
||||
headerFields := decode(strBuf)
|
||||
Expect(headerFields).To(HaveKeyWithValue("accept-encoding", "gzip"))
|
||||
})
|
||||
|
||||
It("writes a CONNECT request", func() {
|
||||
str.EXPECT().Close()
|
||||
req, err := http.NewRequest(http.MethodConnect, "https://quic.clemente.io/", nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
Expect(rw.WriteRequest(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() {
|
||||
str.EXPECT().Close()
|
||||
req, err := http.NewRequest(http.MethodConnect, "https://quic.clemente.io/foobar", nil)
|
||||
Expect(err).ToNot(HaveOccurred())
|
||||
req.Proto = "webtransport"
|
||||
Expect(rw.WriteRequest(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"))
|
||||
})
|
||||
})
|
||||
|
||||
Reference in New Issue
Block a user