From cb826915cdd1881cbcfc1fb4e645d26244dfda71 Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Mon, 5 Jun 2023 10:12:49 +0000 Subject: [PATCH 20/23] t/integration.t: switch PUT tests to MD5, reuse buffers MD5 is faster, and these tests aren't meant to be secure, they're just for checking for data corruption. Furthermore, Content-MD5 is a supported HTTP trailer and we can verify that here to obsolete other tests. Furthermore, we can reuse buffers on env['rack.input'].read calls to avoid malloc(3) and GC overhead. Combined, these give roughly a 3% speedup for t/integration.t on my system. --- t/integration.ru | 20 +++++++++++++++----- t/integration.t | 5 ++--- t/preread_input.ru | 17 ++++++++++++----- 3 files changed, 29 insertions(+), 13 deletions(-) diff --git a/t/integration.ru b/t/integration.ru index dab384d..086126a 100644 --- a/t/integration.ru +++ b/t/integration.ru @@ -55,8 +55,8 @@ def env_dump(env) def rack_input_tests(env) return [ 100, {}, [] ] if /\A100-continue\z/i =~ env['HTTP_EXPECT'] cap = 16384 - require 'digest/sha1' - digest = Digest::SHA1.new + require 'digest/md5' + dig = Digest::MD5.new input = env['rack.input'] case env['PATH_INFO'] when '/rack_input/size_first'; input.size @@ -68,11 +68,21 @@ def rack_input_tests(env) if buf = input.read(rand(cap)) begin raise "#{buf.size} > #{cap}" if buf.size > cap - digest.update(buf) + dig.update(buf) end while input.read(rand(cap), buf) + buf.clear # remove this call if Ruby ever gets escape analysis end - [ 200, {'content-length' => '40', 'content-type' => 'text/plain'}, - [ digest.hexdigest ] ] + h = { 'content-type' => 'text/plain' } + if env['HTTP_TRAILER'] =~ /\bContent-MD5\b/i + cmd5_b64 = env['HTTP_CONTENT_MD5'] or return [500, {}, ['No Content-MD5']] + cmd5_bin = cmd5_b64.unpack('m')[0] + if cmd5_bin != dig.digest + h['content-length'] = cmd5_b64.size.to_s + return [ 500, h, [ cmd5_b64 ] ] + end + end + h['content-length'] = '32' + [ 200, h, [ dig.hexdigest ] ] end run(lambda do |env| diff --git a/t/integration.t b/t/integration.t index 8433497..38a9675 100644 --- a/t/integration.t +++ b/t/integration.t @@ -27,7 +27,6 @@ my %PUT = ( chunked_md5 => sub { my ($in, $out, $path, %opt) = @_; my $bs = $opt{bs} // 16384; - require Digest::MD5; my $dig = Digest::MD5->new; print $out <new(1)->addfile($rh)->hexdigest; + require Digest::MD5; + $blob_hash = Digest::MD5->new->addfile($rh)->hexdigest; my $ck_hash = sub { my ($sub, $path, %opt) = @_; diff --git a/t/preread_input.ru b/t/preread_input.ru index f0a1748..18af221 100644 --- a/t/preread_input.ru +++ b/t/preread_input.ru @@ -1,15 +1,22 @@ #\-E none -require 'digest/sha1' +require 'digest/md5' require 'unicorn/preread_input' use Unicorn::PrereadInput nr = 0 run lambda { |env| $stderr.write "app dispatch: #{nr += 1}\n" input = env["rack.input"] - dig = Digest::SHA1.new - while buf = input.read(16384) - dig.update(buf) + dig = Digest::MD5.new + if buf = input.read(16384) + begin + dig.update(buf) + end while input.read(16384, buf) + buf.clear # remove this call if Ruby ever gets escape analysis + end + if env['HTTP_TRAILER'] =~ /\bContent-MD5\b/i + cmd5_b64 = env['HTTP_CONTENT_MD5'] or return [500, {}, ['No Content-MD5']] + cmd5_bin = cmd5_b64.unpack('m')[0] + return [500, {}, [ cmd5_b64 ] ] if cmd5_bin != dig.digest end - [ 200, {}, [ dig.hexdigest ] ] }