httpclient icon indicating copy to clipboard operation
httpclient copied to clipboard

Using HTTP PUT method for binary StringIO body fails with ruby 3.4.x

Open jarl-dk opened this issue 10 months ago • 1 comments

There is a difference in StringIO#read behaviour between ruby 3.3.x and 3.4.x.

The difference is illustrated by this:

Ruby 3.3.7:

irb(main):001> RUBY_VERSION
=> "3.3.7"
irb(main):002> binary_io = StringIO.new("\x00".b)
=> #<StringIO:0x00007f50541b8518>
irb(main):003> buf = ''
=> ""
irb(main):004> buf.encoding
=> #<Encoding:UTF-8>
irb(main):005> binary_io.read(1, buf)
=> "\x00"
irb(main):006> buf.encoding
=> #<Encoding:ASCII-8BIT>

Ruby 3.4.0:

irb(main):001> RUBY_VERSION
=> "3.4.0"
irb(main):002> binary_io = StringIO.new("\x00".b)
=> #<StringIO:0x000071c808fafab8>
irb(main):003> buf = ''
=> ""
irb(main):004> buf.encoding
=> #<Encoding:UTF-8>
irb(main):005> binary_io.read(1, buf)
=> "\u0000"
irb(main):006> buf.encoding
=> #<Encoding:UTF-8>

I experience that this new beahaviour affects httpclient when using StringIO as body on PUT requests: https://github.com/nahi/httpclient/blob/d57cc6d5ffee1b566b5c189fe6dc8cc89570b812/lib/httpclient/http.rb#L580

This may very well also affect other http methods. I have not tried.

The workaround is not to upgrade ruby to 3.4.x

jarl-dk avatar Jan 30 '25 10:01 jarl-dk

I don’t have a strong preference regarding this behavior change, but for reference, it was introduced in stringio 3.1.2, not Ruby itself.

  • Ruby 3.3.8 with stringio 3.1.1 as a default gem
% irb
irb(main):001> p "StringIO::VERSION: #{StringIO::VERSION}"
irb(main):002> p "RUBY_VERSION: #{RUBY_VERSION}"
irb(main):003> binary_io = StringIO.new("\x00".b)
irb(main):004> buf = ''
irb(main):005> buf.encoding
irb(main):006> p binary_io.read(1, buf)
irb(main):007> p buf.encoding
"StringIO::VERSION: 3.1.1"
"RUBY_VERSION: 3.3.8"
"\x00"
#<Encoding:ASCII-8BIT>
=> #<Encoding:ASCII-8BIT>
irb(main):008> 
  • Ruby 3.3.8 with stringio 3.1.2
% gem install stringio -v 3.1.2
Fetching stringio-3.1.2.gem
Building native extensions. This could take a while...
Successfully installed stringio-3.1.2
Parsing documentation for stringio-3.1.2
Installing ri documentation for stringio-3.1.2
Done installing documentation for stringio after 2 seconds
1 gem installed
% irb                         
irb(main):001> p "StringIO::VERSION: #{StringIO::VERSION}"
irb(main):002> p "RUBY_VERSION: #{RUBY_VERSION}"
irb(main):003> binary_io = StringIO.new("\x00".b)
irb(main):004> buf = ''
irb(main):005> buf.encoding
irb(main):006> p binary_io.read(1, buf)
irb(main):007> p buf.encoding
"StringIO::VERSION: 3.1.2"
"RUBY_VERSION: 3.3.8"
"\u0000"
#<Encoding:UTF-8>
=> #<Encoding:UTF-8>
irb(main):008> 

yahonda avatar Jun 30 '25 12:06 yahonda