set EndStream header in HeadersFrame

This commit is contained in:
Marten Seemann
2017-01-05 10:53:46 +07:00
parent db09de621c
commit 6dd297379b
4 changed files with 42 additions and 7 deletions

View File

@@ -155,6 +155,8 @@ func (c *Client) Do(req *http.Request) (*http.Response, error) {
return nil, errors.New("h2quic Client BUG: Do called for the wrong client")
}
hasBody := (req.Body != nil)
c.mutex.Lock()
c.highestOpenedStream += 2
dataStreamID := c.highestOpenedStream
@@ -176,7 +178,9 @@ func (c *Client) Do(req *http.Request) (*http.Response, error) {
if !c.t.disableCompression() && req.Header.Get("Accept-Encoding") == "" && req.Header.Get("Range") == "" && req.Method != "HEAD" {
requestedGzip = true
}
err = c.requestWriter.WriteRequest(req, dataStreamID, requestedGzip)
// TODO: add support for trailers
endStream := !hasBody
err = c.requestWriter.WriteRequest(req, dataStreamID, endStream, requestedGzip)
if err != nil {
c.Close(err)
return nil, err
@@ -217,7 +221,6 @@ func (c *Client) Do(req *http.Request) (*http.Response, error) {
}
res.Request = req
// TODO: correctly handle gzipped responses
return res, nil
}

View File

@@ -204,6 +204,21 @@ var _ = Describe("Client", func() {
})
})
It("sets the EndStream header for requests without a body", func() {
go func() { client.Do(request) }()
Eventually(func() []byte { return headerStream.dataWritten.Bytes() }).ShouldNot(BeNil())
mhf := getRequest(headerStream.dataWritten.Bytes())
Expect(mhf.HeadersFrame.StreamEnded()).To(BeTrue())
})
It("sets the EndStream header to false for requests with a body", func() {
request.Body = &mockBody{}
go func() { client.Do(request) }()
Eventually(func() []byte { return headerStream.dataWritten.Bytes() }).ShouldNot(BeNil())
mhf := getRequest(headerStream.dataWritten.Bytes())
Expect(mhf.HeadersFrame.StreamEnded()).To(BeFalse())
})
Context("gzip compression", func() {
var gzippedData []byte // a gzipped foobar
var response *http.Response

View File

@@ -34,7 +34,7 @@ func newRequestWriter(headerStream utils.Stream) *requestWriter {
return rw
}
func (w *requestWriter) WriteRequest(req *http.Request, dataStreamID protocol.StreamID, requestGzip bool) error {
func (w *requestWriter) WriteRequest(req *http.Request, dataStreamID protocol.StreamID, endStream, requestGzip bool) error {
// TODO: add support for trailers
// TODO: add support for gzip compression
// TODO: write continuation frames, if the header frame is too long
@@ -47,6 +47,7 @@ func (w *requestWriter) WriteRequest(req *http.Request, dataStreamID protocol.St
return h2framer.WriteHeaders(http2.HeadersFrameParam{
StreamID: uint32(dataStreamID),
EndHeaders: true,
EndStream: endStream,
BlockFragment: w.hbuf.Bytes(),
Priority: http2.PriorityParam{Weight: 0xff},
})

View File

@@ -44,7 +44,7 @@ var _ = Describe("Request", func() {
It("writes a GET request", func() {
req, err := http.NewRequest("GET", "https://quic.clemente.io/index.html?foo=bar", nil)
Expect(err).ToNot(HaveOccurred())
rw.WriteRequest(req, 1337, false)
rw.WriteRequest(req, 1337, true, false)
headerFrame, headerFields := decode(headerStream.dataWritten.Bytes())
Expect(headerFrame.StreamID).To(Equal(uint32(1337)))
Expect(headerFrame.HasPriority()).To(BeTrue())
@@ -55,10 +55,26 @@ var _ = Describe("Request", func() {
Expect(headerFields).ToNot(HaveKey("accept-encoding"))
})
It("sets the EndStream header", func() {
req, err := http.NewRequest("GET", "https://quic.clemente.io/", nil)
Expect(err).ToNot(HaveOccurred())
rw.WriteRequest(req, 1337, true, false)
headerFrame, _ := decode(headerStream.dataWritten.Bytes())
Expect(headerFrame.StreamEnded()).To(BeTrue())
})
It("doesn't set the EndStream header, if requested", func() {
req, err := http.NewRequest("GET", "https://quic.clemente.io/", nil)
Expect(err).ToNot(HaveOccurred())
rw.WriteRequest(req, 1337, false, false)
headerFrame, _ := decode(headerStream.dataWritten.Bytes())
Expect(headerFrame.StreamEnded()).To(BeFalse())
})
It("requests gzip compression, if requested", func() {
req, err := http.NewRequest("GET", "https://quic.clemente.io/index.html?foo=bar", nil)
Expect(err).ToNot(HaveOccurred())
rw.WriteRequest(req, 1337, true)
rw.WriteRequest(req, 1337, true, true)
_, headerFields := decode(headerStream.dataWritten.Bytes())
Expect(headerFields).To(HaveKeyWithValue("accept-encoding", "gzip"))
})
@@ -68,7 +84,7 @@ var _ = Describe("Request", func() {
form.Add("foo", "bar")
req, err := http.NewRequest("POST", "https://quic.clemente.io/upload.html", strings.NewReader(form.Encode()))
Expect(err).ToNot(HaveOccurred())
rw.WriteRequest(req, 5, false)
rw.WriteRequest(req, 5, true, false)
_, headerFields := decode(headerStream.dataWritten.Bytes())
Expect(headerFields).To(HaveKeyWithValue(":method", "POST"))
Expect(headerFields).To(HaveKey("content-length"))
@@ -90,7 +106,7 @@ var _ = Describe("Request", func() {
}
req.AddCookie(cookie1)
req.AddCookie(cookie2)
rw.WriteRequest(req, 11, false)
rw.WriteRequest(req, 11, true, false)
_, headerFields := decode(headerStream.dataWritten.Bytes())
Expect(headerFields).To(HaveKeyWithValue("cookie", "Cookie #1=Value #1; Cookie #2=Value #2"))
})