diff options
-rw-r--r-- | ChangeLog | 41 | ||||
-rw-r--r-- | ext/openssl/extconf.rb | 28 | ||||
-rw-r--r-- | ext/openssl/lib/openssl/buffering.rb | 71 | ||||
-rw-r--r-- | ext/openssl/lib/openssl/ssl.rb | 11 | ||||
-rw-r--r-- | ext/openssl/ossl_ssl.c | 71 | ||||
-rw-r--r-- | test/ruby/ut_eof.rb | 13 |
6 files changed, 158 insertions, 77 deletions
@@ -1,3 +1,38 @@ +Wed Feb 16 02:55:21 2005 GOTOU Yuuzou <gotoyuzo@notwork.org> + + * ext/openssl/ossl_ssl.c (ossl_start_ssl, ossl_ssl_read, + ossl_ssl_write): + - need to set errno on Win32 platform. + - should call rb_sys_fail instead of rasing SSLError if + SSL_ERROR_SYSCALL occured. + - should wait for that the underlying IO become readable or + writable if the error was SSL_ERROR_WANT_READ or + SSL_ERROR_WANT_WRITE. [ruby-dev:25795] + + * ext/openssl/lib/openssl/buffering.rb + (Buffering#initialize): should set @eof and @rbuffer. + (Buffering#fill_rbuff): should rescue Errno::EAGAIN. + (Buffering#consume_rbuf): pointless eof flag resetting is deleted. + (Buffering#read): should return an empty string if the specified + size is zero. + (Buffering#readpartial): new method. + (Buffering#readline): fix typo. + (Buffering#getc): return the first character of string correctly. + (Buffering#each): fix typo. suggested by Brian Ollenberger. + (Buffering#readchar): fix typo. + (Buffering#eof?): should read again it the input buffer is empty. + (Buffering#do_write): should rescue Errno::EAGAIN. + (Buffering#puts): use "\n" as the output field separator. + + * ext/openssl/lib/openssl/ssl.rb: set non-blocking flag to the + underlying IO. + + * ext/openssl/extconf.rb: get rid of GNUmakefile generation. + + * text/openssl/test_pair.rb: test for IO like methods. + + * test/ruby/ut_eof.rb: test about empty file. + Mon Mar 7 10:22:06 2005 WATANABE Hirofumi <eban@ruby-lang.org> * lib/un.rb: should use OptionParser. (backported form HEAD) @@ -361,9 +396,9 @@ Fri Feb 11 17:40:42 2005 GOTOU Yuuzou <gotoyuzo@notwork.org> Fri Feb 11 11:33:53 2005 Tanaka Akira <akr@m17n.org> - * lib/open-uri.rb (URI::HTTP#proxy_open): new option supported: - :http_basic_authentication. - suggested by Kent Sibilev. [ruby-core:4392] + * lib/open-uri.rb (URI::HTTP#proxy_open): new option supported: + :http_basic_authentication. + suggested by Kent Sibilev. [ruby-core:4392] Fri Feb 11 06:30:07 2005 George Ogata <g_ogata@optushome.com.au> diff --git a/ext/openssl/extconf.rb b/ext/openssl/extconf.rb index d587116c82..4517ec82fb 100644 --- a/ext/openssl/extconf.rb +++ b/ext/openssl/extconf.rb @@ -113,33 +113,5 @@ have_struct_member("EVP_CIPHER_CTX", "engine", "openssl/evp.h") have_struct_member("X509_ATTRIBUTE", "single", "openssl/x509.h") message "=== Checking done. ===\n" -$distcleanfiles << "GNUmakefile" << "dep" create_makefile("openssl") -if /gcc/ =~ CONFIG["CC"] - File.open("GNUmakefile", "w") {|f| - f.print <<EOD -include Makefile - -SRCS = $(OBJS:.o=.c) - -test-link: $(OBJS) - $(CC) $(DLDFLAGS) #{OUTFLAG}.testlink $(OBJS) $(LIBPATH) $(LIBS) $(LOCAL_LIBS) - @$(RM) .testlink - @echo "Done." - -dep: - $(CC) $(CFLAGS) $(CPPFLAGS) -c $(SRCS) -MM | \\ - $(RUBY) -p -e 'BEGIN{S = []' \\ - -e 'while !ARGV.empty? and /^(\\w+)=(.*)/ =~ ARGV[0]' \\ - -e 'S << [/\#{Regexp.quote($$2)}\\//, "$$(\#{$$1})/"]' \\ - -e 'ARGV.shift' \\ - -e 'end' \\ - -e '}' -e 'S.each(&method(:gsub!))' -- \\ - 'topdir=$(topdir)' 'srcdir=$(srcdir)' 'hdrdir=$(hdrdir)' \\ - > dep - -include dep -EOD - } -end message "Done.\n" diff --git a/ext/openssl/lib/openssl/buffering.rb b/ext/openssl/lib/openssl/buffering.rb index 31dcdf1f9a..bd11afe043 100644 --- a/ext/openssl/lib/openssl/buffering.rb +++ b/ext/openssl/lib/openssl/buffering.rb @@ -20,6 +20,8 @@ module Buffering BLOCK_SIZE = 1024*16 def initialize(*args) + @eof = false + @rbuffer = "" @sync = @io.sync end @@ -29,17 +31,17 @@ module Buffering private def fill_rbuff - @rbuffer = "" unless defined? @rbuffer begin @rbuffer << self.sysread(BLOCK_SIZE) + rescue Errno::EAGAIN + retry rescue EOFError @eof = true end end def consume_rbuff(size=nil) - if @rbuffer.size == 0 - @eof = nil + if @rbuffer.empty? nil else size = @rbuffer.size unless size @@ -52,8 +54,14 @@ module Buffering public def read(size=nil, buf=nil) - fill_rbuff unless defined? @rbuffer - @eof ||= nil + if size == 0 + if buf + buf.clear + else + buf = "" + end + return @eof ? nil : buf + end until @eof break if size && size <= @rbuffer.size fill_rbuff @@ -66,10 +74,33 @@ module Buffering (size && ret.empty?) ? nil : ret end + def readpartial(maxlen, buf=nil) + if maxlen == 0 + if buf + buf.clear + else + buf = "" + end + return @eof ? nil : buf + end + if @rbuffer.empty? + begin + return sysread(maxlen, buf) + rescue Errno::EAGAIN + retry + end + end + ret = consume_rbuff(maxlen) + if buf + buf.replace(ret) + ret = buf + end + raise EOFError if ret.empty? + ret + end + def gets(eol=$/) - fill_rbuff unless defined? @rbuffer idx = @rbuffer.index(eol) - @eof ||= nil until @eof break if idx fill_rbuff @@ -84,7 +115,7 @@ module Buffering end def each(eol=$/) - while line = self.gets(eol?) + while line = self.gets(eol) yield line end end @@ -99,13 +130,13 @@ module Buffering end def readline(eol=$/) - raise EOFErorr if eof? + raise EOFError if eof? gets(eol) end def getc c = read(1) - c ? c.to_i : nil + c ? c[0] : nil end def each_byte @@ -115,7 +146,7 @@ module Buffering end def readchar - raise EOFErorr if eof? + raise EOFError if eof? getc end @@ -124,8 +155,8 @@ module Buffering end def eof? - @eof ||= nil - @eof && @rbuffer.size == 0 + fill_rbuff if !@eof && @rbuffer.empty? + @eof && @rbuffer.empty? end alias eof eof? @@ -142,7 +173,12 @@ module Buffering remain = idx ? idx + $/.size : @wbuffer.length nwritten = 0 while remain > 0 - nwrote = syswrite(@wbuffer[nwritten,remain]) + str = @wbuffer[nwritten,remain] + begin + nwrote = syswrite(str) + rescue Errno::EAGAIN + retry + end remain -= nwrote nwritten += nwrote end @@ -164,10 +200,13 @@ module Buffering def puts(*args) s = "" + if args.empty? + s << "\n" + end args.each{|arg| s << arg.to_s - unless /#{$/}\z/o =~ s - s << $/ + if $/ && /\n\z/ !~ s + s << "\n" end } do_write(s) diff --git a/ext/openssl/lib/openssl/ssl.rb b/ext/openssl/lib/openssl/ssl.rb index 9c31fa73cd..441890865b 100644 --- a/ext/openssl/lib/openssl/ssl.rb +++ b/ext/openssl/lib/openssl/ssl.rb @@ -16,6 +16,7 @@ require "openssl" require "openssl/buffering" +require "fcntl" module OpenSSL module SSL @@ -49,9 +50,19 @@ module OpenSSL end end + module Nonblock + def initialize(*args) + flag = File::NONBLOCK + flag |= @io.fcntl(Fcntl::F_GETFL) if defined?(Fcntl::F_GETFL) + @io.fcntl(Fcntl::F_SETFL, flag) + super + end + end + class SSLSocket include Buffering include SocketForwarder + include Nonblock def post_connection_check(hostname) check_common_name = true diff --git a/ext/openssl/ossl_ssl.c b/ext/openssl/ossl_ssl.c index c73a160a94..01b44f3210 100644 --- a/ext/openssl/ossl_ssl.c +++ b/ext/openssl/ossl_ssl.c @@ -433,52 +433,56 @@ ossl_ssl_setup(VALUE self) return Qtrue; } -static void -ossl_start_ssl(SSL *ssl, int (*func)()) +#ifdef _WIN32 +#define ssl_get_error(ssl, ret) \ + (errno = WSAGetLastError(), SSL_get_error(ssl, ret)) +#else +#define ssl_get_error(ssl, ret) SSL_get_error(ssl, ret) +#endif + +static VALUE +ossl_start_ssl(VALUE self, int (*func)()) { + SSL *ssl; + OpenFile *fptr; + VALUE cb; int ret; + Data_Get_Struct(self, SSL, ssl); + GetOpenFile(ossl_ssl_get_io(self), fptr); + cb = ossl_sslctx_get_verify_cb(ossl_ssl_get_ctx(self)); + SSL_set_ex_data(ssl, ossl_ssl_ex_vcb_idx, (void *)cb); for(;;){ if((ret = func(ssl)) > 0) break; - switch(SSL_get_error(ssl, ret)){ + switch(ssl_get_error(ssl, ret)){ case SSL_ERROR_WANT_WRITE: + rb_io_wait_writable(fileno(fptr->f)); + continue; case SSL_ERROR_WANT_READ: - rb_thread_schedule(); - continue; + rb_io_wait_readable(fileno(fptr->f)); + continue; + case SSL_ERROR_SYSCALL: + rb_sys_fail(0); default: ossl_raise(eSSLError, NULL); } } + + return self; } static VALUE ossl_ssl_connect(VALUE self) { - SSL *ssl; - VALUE cb; - ossl_ssl_setup(self); - Data_Get_Struct(self, SSL, ssl); - cb = ossl_sslctx_get_verify_cb(ossl_ssl_get_ctx(self)); - SSL_set_ex_data(ssl, ossl_ssl_ex_vcb_idx, (void *)cb); - ossl_start_ssl(ssl, SSL_connect); - - return self; + return ossl_start_ssl(self, SSL_connect); } static VALUE ossl_ssl_accept(VALUE self) { - SSL *ssl; - VALUE cb; - ossl_ssl_setup(self); - Data_Get_Struct(self, SSL, ssl); - cb = ossl_sslctx_get_verify_cb(ossl_ssl_get_ctx(self)); - SSL_set_ex_data(ssl, ossl_ssl_ex_vcb_idx, (void *)cb); - ossl_start_ssl(ssl, SSL_accept); - - return self; + return ossl_start_ssl(self, SSL_accept); } static VALUE @@ -506,18 +510,20 @@ ossl_ssl_read(int argc, VALUE *argv, VALUE self) rb_thread_wait_fd(fileno(fptr->f)); for (;;){ nread = SSL_read(ssl, RSTRING(str)->ptr, RSTRING(str)->len); - switch(SSL_get_error(ssl, nread)){ + switch(ssl_get_error(ssl, nread)){ case SSL_ERROR_NONE: goto end; case SSL_ERROR_ZERO_RETURN: rb_eof_error(); case SSL_ERROR_WANT_WRITE: + rb_io_wait_writable(fileno(fptr->f)); + continue; case SSL_ERROR_WANT_READ: - rb_thread_schedule(); + rb_io_wait_readable(fileno(fptr->f)); continue; case SSL_ERROR_SYSCALL: if(ERR_peek_error() == 0 && nread == 0) rb_eof_error(); - ossl_raise(eSSLError, "SSL_read: %s", strerror(errno)); + rb_sys_fail(0); default: ossl_raise(eSSLError, "SSL_read:"); } @@ -542,21 +548,26 @@ ossl_ssl_write(VALUE self, VALUE str) { SSL *ssl; int nwrite = 0; - FILE *fp; + OpenFile *fptr; StringValue(str); Data_Get_Struct(self, SSL, ssl); + GetOpenFile(ossl_ssl_get_io(self), fptr); if (ssl) { for (;;){ nwrite = SSL_write(ssl, RSTRING(str)->ptr, RSTRING(str)->len); - switch(SSL_get_error(ssl, nwrite)){ + switch(ssl_get_error(ssl, nwrite)){ case SSL_ERROR_NONE: goto end; case SSL_ERROR_WANT_WRITE: + rb_io_wait_writable(fileno(fptr->f)); + continue; case SSL_ERROR_WANT_READ: - rb_thread_schedule(); - continue; + rb_io_wait_readable(fileno(fptr->f)); + continue; + case SSL_ERROR_SYSCALL: + rb_sys_fail(0); default: ossl_raise(eSSLError, "SSL_write:"); } diff --git a/test/ruby/ut_eof.rb b/test/ruby/ut_eof.rb index eff0bddc0b..e6f6eddd6f 100644 --- a/test/ruby/ut_eof.rb +++ b/test/ruby/ut_eof.rb @@ -83,6 +83,19 @@ module TestEOF } end + def test_eof_2 + open_file("") {|f| + assert_equal("", f.read) + assert(f.eof?) + } + end + + def test_eof_3 + open_file("") {|f| + assert(f.eof?) + } + end + module Seek def open_file_seek(content, pos) open_file(content) do |f| |