webseed: Close unused part responses after error

Also don't bother to read their response bodies.
This commit is contained in:
Matt Joiner 2021-11-12 12:40:15 +11:00
parent 2fd928b918
commit 411ebdbe28
1 changed files with 28 additions and 9 deletions

View File

@ -94,7 +94,7 @@ func (ws *Client) NewRequest(r RequestSpec) Request {
Result: make(chan RequestResult, 1),
}
go func() {
b, err := readRequestPartResponses(requestParts)
b, err := readRequestPartResponses(ctx, requestParts)
req.Result <- RequestResult{
Bytes: b,
Err: err,
@ -112,12 +112,15 @@ func (me ErrBadResponse) Error() string {
return me.Msg
}
func recvPartResult(buf io.Writer, part requestPart) error {
func recvPartResult(ctx context.Context, buf io.Writer, part requestPart) error {
result := <-part.result
if result.err != nil {
return result.err
}
defer result.resp.Body.Close()
if ctx.Err() != nil {
return ctx.Err()
}
switch result.resp.StatusCode {
case http.StatusPartialContent:
case http.StatusOK:
@ -140,13 +143,29 @@ func recvPartResult(buf io.Writer, part requestPart) error {
return nil
}
func readRequestPartResponses(parts []requestPart) ([]byte, error) {
func readRequestPartResponses(ctx context.Context, parts []requestPart) ([]byte, error) {
ctx, cancel := context.WithCancel(ctx)
defer cancel()
var buf bytes.Buffer
for _, part := range parts {
err := recvPartResult(&buf, part)
if err != nil {
return buf.Bytes(), fmt.Errorf("reading %q at %q: %w", part.req.URL, part.req.Header.Get("Range"), err)
firstErr := make(chan error, 1)
go func() {
for _, part := range parts {
err := recvPartResult(ctx, &buf, part)
if err != nil {
// Ensure no further unnecessary response reads occur.
cancel()
select {
case firstErr <- fmt.Errorf("reading %q at %q: %w", part.req.URL, part.req.Header.Get("Range"), err):
default:
}
}
}
}
return buf.Bytes(), nil
select {
case firstErr <- nil:
default:
}
}()
// This can't be merged into the return statement, because buf.Bytes is called first!
err := <-firstErr
return buf.Bytes(), err
}