From: Eric Wong Date: 2017-09-20T21:22:18+00:00 Subject: [ruby-core:82909] Re: [Ruby trunk Bug#13921] buffered read_nonblock doesn't work as expected using SSLSocket I've setup some test cases with yahns on https://80x24.org:8443/ to handle large uploads and return the MD5 curl -v -T large_file https://80x24.org:8443/ curl -v -T large_file https://80x24.org:8443/gets_read_mix curl -v -T large_file https://80x24.org:8443/each Where large_file is <= 1GB For each of the endpoints, the MD5 hexdigest matches the output of `md5sum large_file`. All of these match for me with random-sized buffers at the Rack app level. yahns always uses the buffer arg for SSLSocket#read_nonblock I run yahns with the following command and config files below: /path/to/bin/yahns -c /path/to/yahns.conf.rb ==> /path/to/yahns.conf.rb <== # disclaimer: I don't know if this HTTPS configuration is correct require 'openssl' ctx = OpenSSL::SSL::SSLContext.new ctx.cert = OpenSSL::X509::Certificate.new(IO.read( '/path/to/ssl/certs/example.com.crt')) ctx.extra_chain_cert = [ OpenSSL::X509::Certificate.new(IO.read( '/path/to/ssl/certs/example.com.chain.crt')) ] ctx.key = OpenSSL::PKey::RSA.new(IO.read( '/path/to/ssl/private/example.com.key')) ctx.set_params(verify_mode: OpenSSL::SSL::VERIFY_NONE) ctx.session_cache_mode = OpenSSL::SSL::SSLContext::SESSION_CACHE_SERVER app(:rack, '/path/to/config.ru', preload: true) do listen 8443, ssl_ctx: ctx listen '[::]:8443', ipv6only: true, ssl_ctx: ctx client_max_body_size(1024 * 1024 * 1024) client_timeout 5 output_buffering false input_buffering false end ==> /path/to/config.ru <== map('http://80x24.org/') do use Rack::Head run(lambda do |env| case env['REQUEST_METHOD'] when 'PUT' cap = 0x1000000 /\A100-continue\z/i =~ env['HTTP_EXPECT'] and return [ 100, {}, [] ] digest = Digest::MD5.new input = env['rack.input'] case env["PATH_INFO"] when "/gets_read_mix" if buf = input.gets begin digest.update(buf) end while input.read(rand(cap), buf) end when "/each" input.each do |b| digest.update(b) b.clear end else if buf = input.read(rand(cap)) begin raise "#{buf.size} > #{cap}" if buf.size > cap digest.update(buf) end while input.read(rand(cap), buf) end end buf&.clear [ 200, { 'Content-Type' => -'text/plain', 'Content-Length' => -'33', }, [ "#{digest.hexdigest}\n" ] ] else [ 405, { 'Content-Type' => -'text/plain', 'Content-Length' => -'3' }, [ "no\n" ] ] end end) end Unsubscribe: