using byteslice instead of slice for buffer manipulation

The code from which the buffer and string handling was adapted,
inherited also the usage of slice!, which is not the appropriate tool
for when dealing with byte streams. Ruby doesn't have an equivalent
String#byteslice! yet, so we adapted other known workarounds (see
https://bugs.ruby-lang.org/issues/13626) for our code. This means that:

- For HTTPX::Buffer, we add a shift! method, as all usage shift the
buffer part which has been written to the socket;
- For HTTP1 parser and Chunker, we have to double the usage of
byteslice. In the cases where it results in nil, we might needlessly
initialize an empty string, however this is the lesser of evils, until a
proper backport is in place.
This commit is contained in:
HoneyryderChuck 2019-10-12 20:57:44 +01:00
parent a059726b9e
commit 933d319b0b
5 changed files with 18 additions and 11 deletions

View File

@ -16,8 +16,6 @@ module HTTPX
def_delegator :@buffer, :bytesize
def_delegator :@buffer, :slice!
def_delegator :@buffer, :clear
def_delegator :@buffer, :replace
@ -32,5 +30,9 @@ module HTTPX
def full?
@buffer.bytesize >= @limit
end
def shift!(fin)
@buffer = @buffer.byteslice(fin..-1)
end
end
end

View File

@ -87,7 +87,7 @@ module HTTPX
def write(buffer)
siz = @io.write_nonblock(buffer)
buffer.slice!(0, siz)
buffer.shift!(siz)
siz
rescue ::IO::WaitWritable
0
@ -108,7 +108,7 @@ module HTTPX
return 0 if siz == :wait_writable
return if siz.nil?
buffer.slice!(0, siz)
buffer.shift!(siz)
siz
end
end

View File

@ -30,7 +30,7 @@ module HTTPX
def write(buffer)
siz = @io.send(buffer, 0, @host, @port)
buffer.slice!(0, siz)
buffer.shift!(siz)
siz
end

View File

@ -67,7 +67,8 @@ module HTTPX
@status_code = code.to_i
raise(Error, "wrong status code (#{@status_code})") unless (100..599).cover?(@status_code)
@buffer.slice!(0, idx + 1)
# @buffer.slice!(0, idx + 1)
@buffer = @buffer.byteslice((idx + 1)..-1)
nextstate(:headers)
end
@ -116,7 +117,8 @@ module HTTPX
@observer.on_data(chunk)
end
elsif @content_length
data = @buffer.slice!(0, @content_length)
data = @buffer.byteslice(0, @content_length)
@buffer = @buffer.byteslice(@content_length..-1) || "".b
@content_length -= data.bytesize
@observer.on_data(data)
data.clear

View File

@ -60,7 +60,8 @@ module HTTPX::Transcoder
return unless index && index.positive?
# Read hex-length
hexlen = @buffer.slice!(0, index)
hexlen = @buffer.byteslice(0, index)
@buffer = @buffer.byteslice(index..-1) || "".b
hexlen[/\h/] || raise(Error, "wrong chunk size line: #{hexlen}")
@chunk_length = hexlen.hex
# check if is last chunk
@ -72,7 +73,7 @@ module HTTPX::Transcoder
return if @buffer.bytesize < crlf_size
raise Error, "wrong chunked encoding format" unless @buffer.start_with?(CRLF * (crlf_size / 2))
@buffer.slice!(0, crlf_size)
@buffer = @buffer.byteslice(crlf_size..-1)
if @chunk_length.nil?
nextstate(:length)
else
@ -81,8 +82,10 @@ module HTTPX::Transcoder
nextstate(:data)
end
when :data
@chunk_buffer << (slice = @buffer.slice!(0, @chunk_length))
@chunk_length -= slice.bytesize
chunk = @buffer.byteslice(0, @chunk_length)
@buffer = @buffer.byteslice(@chunk_length..-1) || "".b
@chunk_buffer << chunk
@chunk_length -= chunk.bytesize
if @chunk_length.zero?
yield @chunk_buffer unless @chunk_buffer.empty?
@chunk_buffer.clear