diff --git a/lib/protocol/http/body/stream.rb b/lib/protocol/http/body/stream.rb index 52afdf3..f1209ea 100644 --- a/lib/protocol/http/body/stream.rb +++ b/lib/protocol/http/body/stream.rb @@ -89,12 +89,25 @@ def read(length = nil, buffer = nil) # Will avoid reading from the underlying stream if there is buffered data available. # # @parameter length [Integer] The maximum number of bytes to read. - def read_partial(length = nil) + def read_partial(length = nil, buffer = nil) if @buffer - buffer = @buffer + if buffer + buffer.replace(@buffer) + else + buffer = @buffer + end @buffer = nil else - buffer = read_next + if chunk = read_next + if buffer + buffer.replace(chunk) + else + buffer = chunk + end + else + buffer&.clear + buffer = nil + end end if buffer and length @@ -111,8 +124,8 @@ def read_partial(length = nil) end # Similar to {read_partial} but raises an `EOFError` if the stream is at EOF. - def readpartial(length) - read_partial(length) or raise EOFError, "End of file reached!" + def readpartial(length, buffer = nil) + read_partial(length, buffer) or raise EOFError, "End of file reached!" end # Read data from the stream without blocking if possible. diff --git a/test/protocol/http/body/stream.rb b/test/protocol/http/body/stream.rb index c094679..3b117ee 100644 --- a/test/protocol/http/body/stream.rb +++ b/test/protocol/http/body/stream.rb @@ -121,6 +121,24 @@ expect(stream.read_partial(2)).to be == "d" expect(stream.read_partial(2)).to be == nil end + + it "can read partial input with buffer" do + buffer = String.new + expect(stream.read_partial(2, buffer)).to be == "He" + expect(buffer).to be == "He" + expect(stream.read_partial(2, buffer)).to be == "ll" + expect(buffer).to be == "ll" + expect(stream.read_partial(2, buffer)).to be == "o" + expect(buffer).to be == "o" + expect(stream.read_partial(2, buffer)).to be == "Wo" + expect(buffer).to be == "Wo" + expect(stream.read_partial(2, buffer)).to be == "rl" + expect(buffer).to be == "rl" + expect(stream.read_partial(2, buffer)).to be == "d" + expect(buffer).to be == "d" + expect(stream.read_partial(2, buffer)).to be == nil + expect(buffer).to be == "" + end end with '#readpartial' do @@ -129,6 +147,16 @@ expect(stream.readpartial(20)).to be == "World" expect{stream.readpartial(20)}.to raise_exception(EOFError) end + + it "can read partial input with buffer" do + buffer = String.new + expect(stream.readpartial(20, buffer)).to be == "Hello" + expect(buffer).to be == "Hello" + expect(stream.readpartial(20, buffer)).to be == "World" + expect(buffer).to be == "World" + expect{stream.readpartial(20, buffer)}.to raise_exception(EOFError) + expect(buffer).to be == "" + end end with '#read_until' do @@ -224,4 +252,14 @@ expect(stream).to be(:closed?) end end + + with 'IO.copy_stream' do + let(:output) {StringIO.new} + + it "can copy input to output" do + ::IO.copy_stream(stream, output) + + expect(output.string).to be == "HelloWorld" + end + end end