aboutsummaryrefslogtreecommitdiffstats
path: root/ext
diff options
context:
space:
mode:
authortenderlove <tenderlove@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2013-08-26 22:41:44 +0000
committertenderlove <tenderlove@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2013-08-26 22:41:44 +0000
commit988ca60565a5ba6661f7215026f008afebcf7aee (patch)
treebc196f4e6ce27e3ea505c18269a08f3910b99ba5 /ext
parenteadad2c9000f8cc1d5ef58d7d58569793f3db901 (diff)
downloadruby-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.rb8
-rw-r--r--ext/openssl/ossl_ssl.c45
-rw-r--r--ext/stringio/stringio.c51
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"));
}