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: <mailto:ruby-core-request / ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-core>