forked from quic-go/quic-go
refactor HTTP/3 stream handling to use a dedicated stream
Reading from and writing onto this stream applies HTTP/3 DATA framing.
This commit is contained in:
@@ -298,15 +298,59 @@ func (c *client) RoundTripOpt(req *http.Request, opt RoundTripOpt) (*http.Respon
|
||||
return rsp, rerr.err
|
||||
}
|
||||
|
||||
func (c *client) sendRequestBody(str Stream, body io.ReadCloser) error {
|
||||
defer body.Close()
|
||||
b := make([]byte, bodyCopyBufferSize)
|
||||
for {
|
||||
n, rerr := body.Read(b)
|
||||
if n == 0 {
|
||||
if rerr == nil {
|
||||
continue
|
||||
}
|
||||
if rerr == io.EOF {
|
||||
break
|
||||
}
|
||||
}
|
||||
if _, err := str.Write(b[:n]); err != nil {
|
||||
return err
|
||||
}
|
||||
if rerr != nil {
|
||||
if rerr == io.EOF {
|
||||
break
|
||||
}
|
||||
str.CancelWrite(quic.StreamErrorCode(errorRequestCanceled))
|
||||
return rerr
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c *client) doRequest(req *http.Request, str quic.Stream, opt RoundTripOpt, reqDone chan struct{}) (*http.Response, requestError) {
|
||||
var requestGzip bool
|
||||
if !c.opts.DisableCompression && req.Method != "HEAD" && req.Header.Get("Accept-Encoding") == "" && req.Header.Get("Range") == "" {
|
||||
requestGzip = true
|
||||
}
|
||||
if err := c.requestWriter.WriteRequest(str, req, opt.DontCloseRequestStream, requestGzip); err != nil {
|
||||
if err := c.requestWriter.WriteRequestHeader(str, req, requestGzip); err != nil {
|
||||
return nil, newStreamError(errorInternalError, err)
|
||||
}
|
||||
|
||||
if req.Body == nil && !opt.DontCloseRequestStream {
|
||||
str.Close()
|
||||
}
|
||||
|
||||
hstr := newStream(str, func() { c.conn.CloseWithError(quic.ApplicationErrorCode(errorFrameUnexpected), "") })
|
||||
if req.Body != nil {
|
||||
// send the request body asynchronously
|
||||
go func() {
|
||||
if err := c.sendRequestBody(hstr, req.Body); err != nil {
|
||||
c.logger.Errorf("Error writing request: %s", err)
|
||||
}
|
||||
if !opt.DontCloseRequestStream {
|
||||
hstr.Close()
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
frame, err := parseNextFrame(str, nil)
|
||||
if err != nil {
|
||||
return nil, newStreamError(errorFrameError, err)
|
||||
@@ -348,9 +392,7 @@ func (c *client) doRequest(req *http.Request, str quic.Stream, opt RoundTripOpt,
|
||||
res.Header.Add(hf.Name, hf.Value)
|
||||
}
|
||||
}
|
||||
respBody := newResponseBody(str, c.conn, reqDone, func() {
|
||||
c.conn.CloseWithError(quic.ApplicationErrorCode(errorFrameUnexpected), "")
|
||||
})
|
||||
respBody := newResponseBody(hstr, c.conn, reqDone)
|
||||
|
||||
// Rules for when to set Content-Length are defined in https://tools.ietf.org/html/rfc7230#section-3.3.2.
|
||||
_, hasTransferEncoding := res.Header["Transfer-Encoding"]
|
||||
|
||||
Reference in New Issue
Block a user