class Excon::Socket
def read_nonblock(max_length)
def read_nonblock(max_length) begin if @read_offset != 0 && @read_offset >= @read_buffer.length # Clear the buffer so we can test for emptiness below @read_buffer.clear # Reset the offset so it matches the length of the buffer when empty. @read_offset = 0 end if max_length until @backend_eof || readable_bytes >= max_length if @read_buffer.empty? # Avoid allocating a new buffer string when the read buffer is empty @read_buffer = @socket.read_nonblock(max_length, @read_buffer) else @read_buffer << @socket.read_nonblock(max_length - readable_bytes) end end else until @backend_eof if @read_buffer.empty? # Avoid allocating a new buffer string when the read buffer is empty @read_buffer = @socket.read_nonblock(@data[:chunk_size], @read_buffer) else @read_buffer << @socket.read_nonblock(@data[:chunk_size]) end end end rescue OpenSSL::SSL::SSLError => error if error.message == 'read would block' if @read_buffer.empty? select_with_timeout(@socket, :read) && retry end else raise(error) end rescue *READ_RETRY_EXCEPTION_CLASSES if @read_buffer.empty? # if we didn't read anything, try again... select_with_timeout(@socket, :read) && retry end rescue EOFError @backend_eof = true end if max_length if @read_buffer.empty? # EOF met at beginning @eof = @backend_eof nil else start = @read_offset # Ensure that we can seek backwards when reading until a terminator string. # The read offset must never point past the end of the read buffer. @read_offset += max_length > readable_bytes ? readable_bytes : max_length @read_buffer[start...@read_offset] end else # read until EOFError, so return everything start = @read_offset @read_offset = @read_buffer.length @eof = @backend_eof @read_buffer[start..-1] end end