cancellable: use sync.Once to prevent double channel close

Signed-off-by: Alexander Morozov <lk4d4math@gmail.com>
This commit is contained in:
Alexander Morozov 2016-08-10 10:47:56 -07:00
Родитель fc564829f6
Коммит d8ae3d962c
1 изменённых файлов: 10 добавлений и 8 удалений

Просмотреть файл

@ -8,6 +8,7 @@ package cancellable
import (
"io"
"net/http"
"sync"
"github.com/docker/engine-api/client/transport"
@ -82,7 +83,7 @@ func Do(ctx context.Context, client transport.Sender, req *http.Request) (*http.
// The response's Body is closed.
}
}()
resp.Body = &notifyingReader{resp.Body, c}
resp.Body = &notifyingReader{ReadCloser: resp.Body, notify: c}
return resp, nil
}
@ -91,23 +92,24 @@ func Do(ctx context.Context, client transport.Sender, req *http.Request) (*http.
// Close is called or a Read fails on the underlying ReadCloser.
type notifyingReader struct {
io.ReadCloser
notify chan<- struct{}
notify chan<- struct{}
notifyOnce sync.Once
}
func (r *notifyingReader) Read(p []byte) (int, error) {
n, err := r.ReadCloser.Read(p)
if err != nil && r.notify != nil {
close(r.notify)
r.notify = nil
if err != nil {
r.notifyOnce.Do(func() {
close(r.notify)
})
}
return n, err
}
func (r *notifyingReader) Close() error {
err := r.ReadCloser.Close()
if r.notify != nil {
r.notifyOnce.Do(func() {
close(r.notify)
r.notify = nil
}
})
return err
}