diff options
author | tenderlove <tenderlove@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2013-08-26 22:41:44 +0000 |
---|---|---|
committer | tenderlove <tenderlove@b2dd03c8-39d4-4d8f-98ff-823fe69b080e> | 2013-08-26 22:41:44 +0000 |
commit | 988ca60565a5ba6661f7215026f008afebcf7aee (patch) | |
tree | bc196f4e6ce27e3ea505c18269a08f3910b99ba5 /ext | |
parent | eadad2c9000f8cc1d5ef58d7d58569793f3db901 (diff) | |
download | ruby-988ca60565a5ba6661f7215026f008afebcf7aee.tar.gz |
* io.c (io_read_nonblock): support non-blocking reads without raising
exceptions. As in: `io.read_nonblock(size, exception: false)`
[ruby-core:38666] [Feature #5138]
* ext/openssl/ossl_ssl.c (ossl_ssl_read_internal): ditto
* ext/stringio/stringio.c (strio_sysread): ditto
* io.c (rb_io_write_nonblock): support non-blocking writes without
raising an exception.
* ext/openssl/ossl_ssl.c (ossl_ssl_write_internal): ditto
* test/openssl/test_pair.rb (class OpenSSL): tests
* test/ruby/test_io.rb (class TestIO): ditto
* test/socket/test_nonblock.rb (class TestSocketNonblock): ditto
* test/stringio/test_stringio.rb (class TestStringIO): ditto
git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@42695 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
Diffstat (limited to 'ext')
-rw-r--r-- | ext/openssl/lib/openssl/buffering.rb | 8 | ||||
-rw-r--r-- | ext/openssl/ossl_ssl.c | 45 | ||||
-rw-r--r-- | ext/stringio/stringio.c | 51 |
3 files changed, 89 insertions, 15 deletions
diff --git a/ext/openssl/lib/openssl/buffering.rb b/ext/openssl/lib/openssl/buffering.rb index 51bc968e3a..e40dfee667 100644 --- a/ext/openssl/lib/openssl/buffering.rb +++ b/ext/openssl/lib/openssl/buffering.rb @@ -161,7 +161,7 @@ module OpenSSL::Buffering # when the peer requests a new TLS/SSL handshake. See openssl the FAQ for # more details. http://www.openssl.org/support/faq.html - def read_nonblock(maxlen, buf=nil) + def read_nonblock(maxlen, buf=nil, exception: true) if maxlen == 0 if buf buf.clear @@ -171,7 +171,7 @@ module OpenSSL::Buffering end end if @rbuffer.empty? - return sysread_nonblock(maxlen, buf) + return sysread_nonblock(maxlen, buf, exception: exception) end ret = consume_rbuff(maxlen) if buf @@ -370,9 +370,9 @@ module OpenSSL::Buffering # is when the peer requests a new TLS/SSL handshake. See the openssl FAQ # for more details. http://www.openssl.org/support/faq.html - def write_nonblock(s) + def write_nonblock(s, exception: true) flush - syswrite_nonblock(s) + syswrite_nonblock(s, exception: exception) end ## diff --git a/ext/openssl/ossl_ssl.c b/ext/openssl/ossl_ssl.c index fde5ac4fe5..ccbb793cd6 100644 --- a/ext/openssl/ossl_ssl.c +++ b/ext/openssl/ossl_ssl.c @@ -103,6 +103,8 @@ static const char *ossl_ssl_attrs[] = { ID ID_callback_state; +static VALUE sym_exception; + /* * SSLContext class */ @@ -1373,10 +1375,16 @@ ossl_ssl_read_internal(int argc, VALUE *argv, VALUE self, int nonblock) { SSL *ssl; int ilen, nread = 0; + int no_exception = 0; VALUE len, str; rb_io_t *fptr; + VALUE opts = Qnil; + + rb_scan_args(argc, argv, "11:", &len, &str, &opts); + + if (!NIL_P(opts) && Qfalse == rb_hash_aref(opts, sym_exception)) + no_exception = 1; - rb_scan_args(argc, argv, "11", &len, &str); ilen = NUM2INT(len); if(NIL_P(str)) str = rb_str_new(0, ilen); else{ @@ -1397,17 +1405,23 @@ ossl_ssl_read_internal(int argc, VALUE *argv, VALUE self, int nonblock) case SSL_ERROR_NONE: goto end; case SSL_ERROR_ZERO_RETURN: + if (no_exception) { return Qnil; } rb_eof_error(); case SSL_ERROR_WANT_WRITE: + if (no_exception) { return ID2SYM(rb_intern("wait_writable")); } write_would_block(nonblock); rb_io_wait_writable(FPTR_TO_FD(fptr)); continue; case SSL_ERROR_WANT_READ: + if (no_exception) { return ID2SYM(rb_intern("wait_readable")); } read_would_block(nonblock); rb_io_wait_readable(FPTR_TO_FD(fptr)); continue; case SSL_ERROR_SYSCALL: - if(ERR_peek_error() == 0 && nread == 0) rb_eof_error(); + if(ERR_peek_error() == 0 && nread == 0) { + if (no_exception) { return Qnil; } + rb_eof_error(); + } rb_sys_fail(0); default: ossl_raise(eSSLError, "SSL_read"); @@ -1445,9 +1459,11 @@ ossl_ssl_read(int argc, VALUE *argv, VALUE self) * call-seq: * ssl.sysread_nonblock(length) => string * ssl.sysread_nonblock(length, buffer) => buffer + * ssl.sysread_nonblock(length[, buffer [, opts]) => buffer * * A non-blocking version of #sysread. Raises an SSLError if reading would - * block. + * block. If "exception: false" is passed, this method returns a symbol of + * :wait_writable, :wait_writable, or nil, rather than raising an exception. * * Reads +length+ bytes from the SSL connection. If a pre-allocated +buffer+ * is provided the data will be written into it. @@ -1459,7 +1475,7 @@ ossl_ssl_read_nonblock(int argc, VALUE *argv, VALUE self) } static VALUE -ossl_ssl_write_internal(VALUE self, VALUE str, int nonblock) +ossl_ssl_write_internal(VALUE self, VALUE str, int nonblock, int no_exception) { SSL *ssl; int nwrite = 0; @@ -1476,10 +1492,12 @@ ossl_ssl_write_internal(VALUE self, VALUE str, int nonblock) case SSL_ERROR_NONE: goto end; case SSL_ERROR_WANT_WRITE: + if (no_exception) { return ID2SYM(rb_intern("wait_writable")); } write_would_block(nonblock); rb_io_wait_writable(FPTR_TO_FD(fptr)); continue; case SSL_ERROR_WANT_READ: + if (no_exception) { return ID2SYM(rb_intern("wait_readable")); } read_would_block(nonblock); rb_io_wait_readable(FPTR_TO_FD(fptr)); continue; @@ -1509,7 +1527,7 @@ ossl_ssl_write_internal(VALUE self, VALUE str, int nonblock) static VALUE ossl_ssl_write(VALUE self, VALUE str) { - return ossl_ssl_write_internal(self, str, 0); + return ossl_ssl_write_internal(self, str, 0, 0); } /* @@ -1520,9 +1538,18 @@ ossl_ssl_write(VALUE self, VALUE str) * SSLError if writing would block. */ static VALUE -ossl_ssl_write_nonblock(VALUE self, VALUE str) +ossl_ssl_write_nonblock(int argc, VALUE *argv, VALUE self) { - return ossl_ssl_write_internal(self, str, 1); + VALUE str; + VALUE opts = Qnil; + int no_exception = 0; + + rb_scan_args(argc, argv, "1:", &str, &opts); + + if (!NIL_P(opts) && Qfalse == rb_hash_aref(opts, sym_exception)) + no_exception = 1; + + return ossl_ssl_write_internal(self, str, 1, no_exception); } /* @@ -2168,7 +2195,7 @@ Init_ossl_ssl() rb_define_method(cSSLSocket, "sysread", ossl_ssl_read, -1); rb_define_private_method(cSSLSocket, "sysread_nonblock", ossl_ssl_read_nonblock, -1); rb_define_method(cSSLSocket, "syswrite", ossl_ssl_write, 1); - rb_define_private_method(cSSLSocket, "syswrite_nonblock", ossl_ssl_write_nonblock, 1); + rb_define_private_method(cSSLSocket, "syswrite_nonblock", ossl_ssl_write_nonblock, -1); rb_define_method(cSSLSocket, "sysclose", ossl_ssl_close, 0); rb_define_method(cSSLSocket, "cert", ossl_ssl_get_cert, 0); rb_define_method(cSSLSocket, "peer_cert", ossl_ssl_get_peer_cert, 0); @@ -2239,4 +2266,6 @@ Init_ossl_ssl() ossl_ssl_def_const(OP_PKCS1_CHECK_2); ossl_ssl_def_const(OP_NETSCAPE_CA_DN_BUG); ossl_ssl_def_const(OP_NETSCAPE_DEMO_CIPHER_CHANGE_BUG); + + sym_exception = ID2SYM(rb_intern("exception")); } diff --git a/ext/stringio/stringio.c b/ext/stringio/stringio.c index ef3df832b8..5c2c64ca03 100644 --- a/ext/stringio/stringio.c +++ b/ext/stringio/stringio.c @@ -119,6 +119,8 @@ typedef char strio_flags_check[(STRIO_READABLE/FMODE_READABLE == STRIO_WRITABLE/ #define READABLE(strio) STRIO_MODE_SET_P(strio, READABLE) #define WRITABLE(strio) STRIO_MODE_SET_P(strio, WRITABLE) +static VALUE sym_exception; + static struct StringIO* readable(VALUE strio) { @@ -1327,7 +1329,6 @@ strio_read(int argc, VALUE *argv, VALUE self) * call-seq: * strio.sysread(integer[, outbuf]) -> string * strio.readpartial(integer[, outbuf]) -> string - * strio.read_nonblock(integer[, outbuf]) -> string * * Similar to #read, but raises +EOFError+ at end of string instead of * returning +nil+, as well as IO#sysread does. @@ -1342,8 +1343,50 @@ strio_sysread(int argc, VALUE *argv, VALUE self) return val; } +/* + * call-seq: + * strio.read_nonblock(integer[, outbuf [, opts]]) -> string + * + * Similar to #read, but raises +EOFError+ at end of string unless the + * +exception: false+ option is passed in. + */ +static VALUE +strio_read_nonblock(int argc, VALUE *argv, VALUE self) +{ + VALUE opts = Qnil; + int no_exception = 0; + + rb_scan_args(argc, argv, "11:", NULL, NULL, &opts); + + if (!NIL_P(opts)) { + argc--; + + if (Qfalse == rb_hash_aref(opts, sym_exception)) + no_exception = 1; + } + + VALUE val = strio_read(argc, argv, self); + if (NIL_P(val)) { + if (no_exception) + return Qnil; + else + rb_eof_error(); + } + + return val; +} + #define strio_syswrite rb_io_write +static VALUE +strio_syswrite_nonblock(int argc, VALUE *argv, VALUE self) +{ + VALUE str; + + rb_scan_args(argc, argv, "10:", &str, NULL); + return strio_syswrite(self, str); +} + #define strio_isatty strio_false #define strio_pid strio_nil @@ -1542,7 +1585,7 @@ Init_stringio() rb_define_method(mReadable, "readline", strio_readline, -1); rb_define_method(mReadable, "sysread", strio_sysread, -1); rb_define_method(mReadable, "readpartial", strio_sysread, -1); - rb_define_method(mReadable, "read_nonblock", strio_sysread, -1); + rb_define_method(mReadable, "read_nonblock", strio_read_nonblock, -1); rb_include_module(StringIO, mReadable); } { @@ -1552,7 +1595,9 @@ Init_stringio() rb_define_method(mWritable, "printf", strio_printf, -1); rb_define_method(mWritable, "puts", strio_puts, -1); rb_define_method(mWritable, "syswrite", strio_syswrite, 1); - rb_define_method(mWritable, "write_nonblock", strio_syswrite, 1); + rb_define_method(mWritable, "write_nonblock", strio_syswrite_nonblock, -1); rb_include_module(StringIO, mWritable); } + + sym_exception = ID2SYM(rb_intern("exception")); } |