From 4660f63033cf8036a21f97021ea20c8565b0cde7 Mon Sep 17 00:00:00 2001 From: Justin Chadwell Date: Wed, 12 Apr 2023 17:02:09 +0100 Subject: [PATCH] copy: remove wrapping io.NopCloser from push writer pipe io.Pipe produces a PipeReader and a PipeWriter - a close on the write side, causes an error on both the read and write sides, while a close on the read side causes an error on only the read side. Previously, we explicitly prohibited closing from the read side. However, http.Request.Body requires that "calling Close should unblock a Read waiting for input". Our reader will not do this - calling close becomes a no-op. This can cause a deadlock because client.Do may never terminate in some circumstances. We need the Reader side to close its side of the pipe as well, which it already does using the go standard library - otherwise, we can hang forever, writing to a pipe that will never be closed. Allowing the requester to close the body should be safe - we never reuse the same reader between requests, as the result of body() will never be reused by the guarantees of the standard library. Signed-off-by: Justin Chadwell --- core/remotes/docker/pusher.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/core/remotes/docker/pusher.go b/core/remotes/docker/pusher.go index c3d0c6069..d38b0c70f 100644 --- a/core/remotes/docker/pusher.go +++ b/core/remotes/docker/pusher.go @@ -280,7 +280,7 @@ func (p dockerPusher) push(ctx context.Context, desc ocispec.Descriptor, ref str req.body = func() (io.ReadCloser, error) { pr, pw := io.Pipe() pushw.setPipe(pw) - return io.NopCloser(pr), nil + return pr, nil } req.size = desc.Size