'Asynchronously reads all data from the socket until it is closed.
If a ``streaming_callback`` is given, it will be called with chunks
of data as they become available, and the final result will be empty.
Otherwise, the result is all the data that was read.
If a callback is given, it will be run with the data as an argument;
if not, this method returns a `.Future`.
Note that if a ``streaming_callback`` is used, data will be
read from the socket as quickly as it becomes available; there
is no way to apply backpressure or cancel the reads. If flow
control or cancellation are desired, use a loop with
`read_bytes(partial=True) <.read_bytes>` instead.
.. versionchanged:: 4.0
The callback argument is now optional and a `.Future` will
be returned if it is omitted.'

def read_until_close(self, callback=None, streaming_callback=None):

    future = self._set_read_callback(callback)
    self._streaming_callback = stack_context.wrap(streaming_callback)
    if self.closed():
        if (self._streaming_callback is not None):
            self._run_read_callback(self._read_buffer_size, True)
        self._run_read_callback(self._read_buffer_size, False)
        return future
    self._read_until_close = True
    try:
        self._try_inline_read()
    except:
        if (future is not None):
            future.add_done_callback((lambda f: f.exception()))
        raise
    return future
