forked from quic-go/quic-go
rework stream / connection erros for the client
This commit is contained in:
@@ -130,8 +130,7 @@ func (c *client) maxHeaderBytes() uint64 {
|
||||
return uint64(c.opts.MaxHeaderBytes)
|
||||
}
|
||||
|
||||
// Roundtrip executes a request and returns a response
|
||||
// TODO: handle request cancelations
|
||||
// RoundTrip executes a request and returns a response
|
||||
func (c *client) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
if req.URL.Scheme != "https" {
|
||||
return nil, errors.New("http3: unsupported scheme")
|
||||
@@ -153,7 +152,22 @@ func (c *client) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Request Cancelation:
|
||||
rsp, rerr := c.doRequest(req, str)
|
||||
if rerr.streamErr != 0 {
|
||||
str.CancelWrite(quic.ErrorCode(rerr.streamErr))
|
||||
}
|
||||
if rerr.connErr != 0 {
|
||||
var reason string
|
||||
if rerr.err != nil {
|
||||
reason = rerr.err.Error()
|
||||
}
|
||||
c.session.CloseWithError(quic.ErrorCode(rerr.connErr), reason)
|
||||
}
|
||||
return rsp, rerr.err
|
||||
}
|
||||
|
||||
func (c *client) doRequest(req *http.Request, str quic.Stream) (*http.Response, requestError) {
|
||||
// Request Cancellation:
|
||||
// This go routine keeps running even after RoundTrip() returns.
|
||||
// It is shut down when the application is done processing the body.
|
||||
reqDone := make(chan struct{})
|
||||
@@ -171,28 +185,30 @@ func (c *client) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
requestGzip = true
|
||||
}
|
||||
if err := c.requestWriter.WriteRequest(str, req, requestGzip); err != nil {
|
||||
return nil, err
|
||||
return nil, newStreamError(errorInternalError, err)
|
||||
}
|
||||
|
||||
frame, err := parseNextFrame(str)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
return nil, newStreamError(errorFrameError, err)
|
||||
}
|
||||
hf, ok := frame.(*headersFrame)
|
||||
if !ok {
|
||||
return nil, errors.New("not a HEADERS frame")
|
||||
return nil, newConnError(errorUnexpectedFrame, errors.New("expected first frame to be a HEADERS frame"))
|
||||
}
|
||||
if hf.Length > c.maxHeaderBytes() {
|
||||
return nil, fmt.Errorf("Headers frame too large: %d bytes (max: %d)", hf.Length, c.maxHeaderBytes())
|
||||
return nil, newStreamError(errorFrameError, fmt.Errorf("HEADERS frame too large: %d bytes (max: %d)", hf.Length, c.maxHeaderBytes()))
|
||||
}
|
||||
headerBlock := make([]byte, hf.Length)
|
||||
if _, err := io.ReadFull(str, headerBlock); err != nil {
|
||||
return nil, err
|
||||
return nil, newStreamError(errorRequestIncomplete, err)
|
||||
}
|
||||
hfs, err := c.decoder.DecodeFull(headerBlock)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
// TODO: use the right error code
|
||||
return nil, newConnError(errorGeneralProtocolError, err)
|
||||
}
|
||||
|
||||
res := &http.Response{
|
||||
Proto: "HTTP/3",
|
||||
ProtoMajor: 3,
|
||||
@@ -203,7 +219,7 @@ func (c *client) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
case ":status":
|
||||
status, err := strconv.Atoi(hf.Value)
|
||||
if err != nil {
|
||||
return nil, errors.New("malformed non-numeric status pseudo header")
|
||||
return nil, newStreamError(errorGeneralProtocolError, errors.New("malformed non-numeric status pseudo header"))
|
||||
}
|
||||
res.StatusCode = status
|
||||
res.Status = hf.Value + " " + http.StatusText(status)
|
||||
@@ -222,5 +238,5 @@ func (c *client) RoundTrip(req *http.Request) (*http.Response, error) {
|
||||
res.Body = respBody
|
||||
}
|
||||
|
||||
return res, nil
|
||||
return res, requestError{}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user