diff options
-rw-r--r-- | lib/yahns/openssl_client.rb | 40 |
1 files changed, 35 insertions, 5 deletions
diff --git a/lib/yahns/openssl_client.rb b/lib/yahns/openssl_client.rb index bf64255..cd7d210 100644 --- a/lib/yahns/openssl_client.rb +++ b/lib/yahns/openssl_client.rb @@ -1,3 +1,4 @@ +# -*- encoding: binary -*- # Copyright (C) 2013-2016 all contributors <yahns-public@yhbt.net> # License: GPL-3.0+ (https://www.gnu.org/licenses/gpl-3.0.txt) # frozen_string_literal: true @@ -7,8 +8,6 @@ require_relative 'sendfile_compat' # this is to be included into a Kgio::Socket-derived class # this requires Ruby 2.1 and later for "exception: false" module Yahns::OpenSSLClient # :nodoc: - include Yahns::SendfileCompat - def self.included(cls) # Forward these methods to OpenSSL::SSL::SSLSocket so hijackers # can rely on stdlib methods instead of ugly kgio stuff that @@ -37,15 +36,25 @@ module Yahns::OpenSSLClient # :nodoc: def yahns_init_ssl(ssl_ctx) @need_accept = true @ssl = OpenSSL::SSL::SSLSocket.new(self, ssl_ctx) + @ssl_blocked = nil end def kgio_trywrite(buf) - rv = @ssl.write_nonblock(buf, exception: false) - Integer === rv and - rv = buf.bytesize == rv ? nil : buf.byteslice(rv, buf.bytesize) + buf = @ssl_blocked = buf.dup + case rv = @ssl.write_nonblock(buf, exception: false) + when :wait_readable, :wait_writable + return rv # do not clear ssl_blocked + when Integer + rv = buf.bytesize == rv ? nil : buf.byteslice(rv, buf.bytesize - rv) + end + @ssl_blocked = nil rv end + def kgio_trywritev(buf) + kgio_trywrite(buf.join) + end + def kgio_syssend(buf, flags) kgio_trywrite(buf) end @@ -63,6 +72,27 @@ module Yahns::OpenSSLClient # :nodoc: @ssl.read_nonblock(len, buf, exception: false) end + def trysendfile(io, offset, count) + return 0 if count == 0 + + unless buf = @ssl_blocked + count = 0x4000 if count > 0x4000 + buf = Thread.current[:yahns_sfbuf] ||= ''.dup + io.pos = offset + buf = io.read(count, buf) or return # nil for EOF + buf = @ssl_blocked = buf.dup + end + + # call write_nonblock directly since kgio_trywrite allocates + # an unnecessary string + case rv = @ssl.write_nonblock(buf, exception: false) + when :wait_readable, :wait_writable + return rv # do not clear ssl_blocked + end + @ssl_blocked = nil + rv + end + def close @ssl.close # flushes SSLSocket super # IO#close |