зеркало из https://github.com/github/ruby.git
* 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
This commit is contained in:
Родитель
eadad2c900
Коммит
988ca60565
15
ChangeLog
15
ChangeLog
|
@ -1,3 +1,18 @@
|
|||
Tue Aug 27 07:35:05 2013 Aaron Patterson <aaron@tenderlovemaking.com>
|
||||
|
||||
* 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
|
||||
|
||||
Tue Aug 27 05:24:34 2013 Eric Hodel <drbrain@segment7.net>
|
||||
|
||||
* lib/rubygems: Import RubyGems 2.1.0 Release Candidate
|
||||
|
|
|
@ -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
|
||||
|
||||
##
|
||||
|
|
|
@ -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"));
|
||||
}
|
||||
|
|
|
@ -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"));
|
||||
}
|
||||
|
|
102
io.c
102
io.c
|
@ -159,7 +159,7 @@ static VALUE argf;
|
|||
|
||||
static ID id_write, id_read, id_getc, id_flush, id_readpartial, id_set_encoding;
|
||||
static VALUE sym_mode, sym_perm, sym_extenc, sym_intenc, sym_encoding, sym_open_args;
|
||||
static VALUE sym_textmode, sym_binmode, sym_autoclose;
|
||||
static VALUE sym_textmode, sym_binmode, sym_autoclose, sym_exception;
|
||||
static VALUE sym_SET, sym_CUR, sym_END;
|
||||
#ifdef SEEK_DATA
|
||||
static VALUE sym_DATA;
|
||||
|
@ -2413,14 +2413,14 @@ read_internal_call(VALUE arg)
|
|||
}
|
||||
|
||||
static VALUE
|
||||
io_getpartial(int argc, VALUE *argv, VALUE io, int nonblock)
|
||||
io_getpartial(int argc, VALUE *argv, VALUE io, int nonblock, int no_exception)
|
||||
{
|
||||
rb_io_t *fptr;
|
||||
VALUE length, str;
|
||||
long n, len;
|
||||
struct read_internal_arg arg;
|
||||
|
||||
rb_scan_args(argc, argv, "11", &length, &str);
|
||||
rb_scan_args(argc, argv, "11:", &length, &str, NULL);
|
||||
|
||||
if ((len = NUM2LONG(length)) < 0) {
|
||||
rb_raise(rb_eArgError, "negative length %ld given", len);
|
||||
|
@ -2452,8 +2452,12 @@ io_getpartial(int argc, VALUE *argv, VALUE io, int nonblock)
|
|||
if (n < 0) {
|
||||
if (!nonblock && rb_io_wait_readable(fptr->fd))
|
||||
goto again;
|
||||
if (nonblock && (errno == EWOULDBLOCK || errno == EAGAIN))
|
||||
if (nonblock && (errno == EWOULDBLOCK || errno == EAGAIN)) {
|
||||
if (no_exception)
|
||||
return ID2SYM(rb_intern("wait_readable"));
|
||||
else
|
||||
rb_readwrite_sys_fail(RB_IO_WAIT_READABLE, "read would block");
|
||||
}
|
||||
rb_sys_fail_path(fptr->pathv);
|
||||
}
|
||||
}
|
||||
|
@ -2529,7 +2533,7 @@ io_readpartial(int argc, VALUE *argv, VALUE io)
|
|||
{
|
||||
VALUE ret;
|
||||
|
||||
ret = io_getpartial(argc, argv, io, 0);
|
||||
ret = io_getpartial(argc, argv, io, 0, 0);
|
||||
if (NIL_P(ret))
|
||||
rb_eof_error();
|
||||
return ret;
|
||||
|
@ -2590,16 +2594,62 @@ static VALUE
|
|||
io_read_nonblock(int argc, VALUE *argv, VALUE io)
|
||||
{
|
||||
VALUE ret;
|
||||
VALUE opts = Qnil;
|
||||
int no_exception = 0;
|
||||
|
||||
ret = io_getpartial(argc, argv, io, 1);
|
||||
if (NIL_P(ret))
|
||||
rb_scan_args(argc, argv, "11:", NULL, NULL, &opts);
|
||||
|
||||
if (!NIL_P(opts) && Qfalse == rb_hash_aref(opts, sym_exception))
|
||||
no_exception = 1;
|
||||
|
||||
ret = io_getpartial(argc, argv, io, 1, no_exception);
|
||||
|
||||
if (NIL_P(ret)) {
|
||||
if (no_exception)
|
||||
return Qnil;
|
||||
else
|
||||
rb_eof_error();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
static VALUE
|
||||
io_write_nonblock(VALUE io, VALUE str, int no_exception)
|
||||
{
|
||||
rb_io_t *fptr;
|
||||
long n;
|
||||
|
||||
if (!RB_TYPE_P(str, T_STRING))
|
||||
str = rb_obj_as_string(str);
|
||||
|
||||
io = GetWriteIO(io);
|
||||
GetOpenFile(io, fptr);
|
||||
rb_io_check_writable(fptr);
|
||||
|
||||
if (io_fflush(fptr) < 0)
|
||||
rb_sys_fail(0);
|
||||
|
||||
rb_io_set_nonblock(fptr);
|
||||
n = write(fptr->fd, RSTRING_PTR(str), RSTRING_LEN(str));
|
||||
|
||||
if (n == -1) {
|
||||
if (errno == EWOULDBLOCK || errno == EAGAIN) {
|
||||
if (no_exception) {
|
||||
return ID2SYM(rb_intern("wait_writable"));
|
||||
} else {
|
||||
rb_readwrite_sys_fail(RB_IO_WAIT_WRITABLE, "write would block");
|
||||
}
|
||||
}
|
||||
rb_sys_fail_path(fptr->pathv);
|
||||
}
|
||||
|
||||
return LONG2FIX(n);
|
||||
}
|
||||
|
||||
/*
|
||||
* call-seq:
|
||||
* ios.write_nonblock(string) -> integer
|
||||
* ios.write_nonblock(string [, options]) -> integer
|
||||
*
|
||||
* Writes the given string to <em>ios</em> using
|
||||
* the write(2) system call after O_NONBLOCK is set for
|
||||
|
@ -2648,34 +2698,25 @@ io_read_nonblock(int argc, VALUE *argv, VALUE io)
|
|||
* according to the kind of the IO object.
|
||||
* In such cases, write_nonblock raises <code>Errno::EBADF</code>.
|
||||
*
|
||||
* By specifying `exception: false`, the options hash allows you to indicate
|
||||
* that write_nonblock should not raise an IO::WaitWritable exception, but
|
||||
* return the symbol :wait_writable instead.
|
||||
*
|
||||
*/
|
||||
|
||||
static VALUE
|
||||
rb_io_write_nonblock(VALUE io, VALUE str)
|
||||
rb_io_write_nonblock(int argc, VALUE *argv, VALUE io)
|
||||
{
|
||||
rb_io_t *fptr;
|
||||
long n;
|
||||
VALUE str;
|
||||
VALUE opts = Qnil;
|
||||
int no_exceptions = 0;
|
||||
|
||||
if (!RB_TYPE_P(str, T_STRING))
|
||||
str = rb_obj_as_string(str);
|
||||
rb_scan_args(argc, argv, "10:", &str, &opts);
|
||||
|
||||
io = GetWriteIO(io);
|
||||
GetOpenFile(io, fptr);
|
||||
rb_io_check_writable(fptr);
|
||||
if (!NIL_P(opts) && Qfalse == rb_hash_aref(opts, sym_exception))
|
||||
no_exceptions = 1;
|
||||
|
||||
if (io_fflush(fptr) < 0)
|
||||
rb_sys_fail(0);
|
||||
|
||||
rb_io_set_nonblock(fptr);
|
||||
n = write(fptr->fd, RSTRING_PTR(str), RSTRING_LEN(str));
|
||||
|
||||
if (n == -1) {
|
||||
if (errno == EWOULDBLOCK || errno == EAGAIN)
|
||||
rb_readwrite_sys_fail(RB_IO_WAIT_WRITABLE, "write would block");
|
||||
rb_sys_fail_path(fptr->pathv);
|
||||
}
|
||||
|
||||
return LONG2FIX(n);
|
||||
return io_write_nonblock(io, str, no_exceptions);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -10809,7 +10850,7 @@ argf_getpartial(int argc, VALUE *argv, VALUE argf, int nonblock)
|
|||
RUBY_METHOD_FUNC(0), Qnil, rb_eEOFError, (VALUE)0);
|
||||
}
|
||||
else {
|
||||
tmp = io_getpartial(argc, argv, ARGF.current_file, nonblock);
|
||||
tmp = io_getpartial(argc, argv, ARGF.current_file, nonblock, 0);
|
||||
}
|
||||
if (NIL_P(tmp)) {
|
||||
if (ARGF.next_p == -1) {
|
||||
|
@ -11851,7 +11892,7 @@ Init_IO(void)
|
|||
rb_define_method(rb_cIO, "readlines", rb_io_readlines, -1);
|
||||
|
||||
rb_define_method(rb_cIO, "read_nonblock", io_read_nonblock, -1);
|
||||
rb_define_method(rb_cIO, "write_nonblock", rb_io_write_nonblock, 1);
|
||||
rb_define_method(rb_cIO, "write_nonblock", rb_io_write_nonblock, -1);
|
||||
rb_define_method(rb_cIO, "readpartial", io_readpartial, -1);
|
||||
rb_define_method(rb_cIO, "read", io_read, -1);
|
||||
rb_define_method(rb_cIO, "write", io_write_m, 1);
|
||||
|
@ -12056,4 +12097,5 @@ Init_IO(void)
|
|||
#ifdef SEEK_HOLE
|
||||
sym_HOLE = ID2SYM(rb_intern("HOLE"));
|
||||
#endif
|
||||
sym_exception = ID2SYM(rb_intern("exception"));
|
||||
}
|
||||
|
|
|
@ -156,19 +156,46 @@ class OpenSSL::TestPair < Test::Unit::TestCase
|
|||
ret = nil
|
||||
assert_nothing_raised("[ruby-core:20298]") { ret = s2.read_nonblock(10) }
|
||||
assert_equal("def\n", ret)
|
||||
s1.close
|
||||
assert_raise(EOFError) { s2.read_nonblock(10) }
|
||||
}
|
||||
end
|
||||
|
||||
def test_read_nonblock_no_exception
|
||||
ssl_pair {|s1, s2|
|
||||
assert_equal :wait_readable, s2.read_nonblock(10, exception: false)
|
||||
s1.write "abc\ndef\n"
|
||||
IO.select([s2])
|
||||
assert_equal("ab", s2.read_nonblock(2, exception: false))
|
||||
assert_equal("c\n", s2.gets)
|
||||
ret = nil
|
||||
assert_nothing_raised("[ruby-core:20298]") { ret = s2.read_nonblock(10, exception: false) }
|
||||
assert_equal("def\n", ret)
|
||||
s1.close
|
||||
assert_equal(nil, s2.read_nonblock(10, exception: false))
|
||||
}
|
||||
end
|
||||
|
||||
def write_nonblock(socket, meth, str)
|
||||
ret = socket.send(meth, str)
|
||||
ret.is_a?(Symbol) ? 0 : ret
|
||||
end
|
||||
|
||||
def write_nonblock_no_ex(socket, str)
|
||||
ret = socket.write_nonblock str, exception: false
|
||||
ret.is_a?(Symbol) ? 0 : ret
|
||||
end
|
||||
|
||||
def test_write_nonblock
|
||||
ssl_pair {|s1, s2|
|
||||
n = 0
|
||||
begin
|
||||
n += s1.write_nonblock("a" * 100000)
|
||||
n += s1.write_nonblock("b" * 100000)
|
||||
n += s1.write_nonblock("c" * 100000)
|
||||
n += s1.write_nonblock("d" * 100000)
|
||||
n += s1.write_nonblock("e" * 100000)
|
||||
n += s1.write_nonblock("f" * 100000)
|
||||
n += write_nonblock s1, :write_nonblock, "a" * 100000
|
||||
n += write_nonblock s1, :write_nonblock, "b" * 100000
|
||||
n += write_nonblock s1, :write_nonblock, "c" * 100000
|
||||
n += write_nonblock s1, :write_nonblock, "d" * 100000
|
||||
n += write_nonblock s1, :write_nonblock, "e" * 100000
|
||||
n += write_nonblock s1, :write_nonblock, "f" * 100000
|
||||
rescue IO::WaitWritable
|
||||
end
|
||||
s1.close
|
||||
|
@ -176,6 +203,20 @@ class OpenSSL::TestPair < Test::Unit::TestCase
|
|||
}
|
||||
end
|
||||
|
||||
def test_write_nonblock_no_exceptions
|
||||
ssl_pair {|s1, s2|
|
||||
n = 0
|
||||
n += write_nonblock_no_ex s1, "a" * 100000
|
||||
n += write_nonblock_no_ex s1, "b" * 100000
|
||||
n += write_nonblock_no_ex s1, "c" * 100000
|
||||
n += write_nonblock_no_ex s1, "d" * 100000
|
||||
n += write_nonblock_no_ex s1, "e" * 100000
|
||||
n += write_nonblock_no_ex s1, "f" * 100000
|
||||
s1.close
|
||||
assert_equal(n, s2.read.length)
|
||||
}
|
||||
end
|
||||
|
||||
def test_write_nonblock_with_buffered_data
|
||||
ssl_pair {|s1, s2|
|
||||
s1.write "foo"
|
||||
|
@ -186,6 +227,16 @@ class OpenSSL::TestPair < Test::Unit::TestCase
|
|||
}
|
||||
end
|
||||
|
||||
def test_write_nonblock_with_buffered_data_no_exceptions
|
||||
ssl_pair {|s1, s2|
|
||||
s1.write "foo"
|
||||
s1.write_nonblock("bar", exception: false)
|
||||
s1.write "baz"
|
||||
s1.close
|
||||
assert_equal("foobarbaz", s2.read)
|
||||
}
|
||||
end
|
||||
|
||||
def test_connect_accept_nonblock
|
||||
host = "127.0.0.1"
|
||||
port = 0
|
||||
|
|
|
@ -1205,6 +1205,16 @@ class TestIO < Test::Unit::TestCase
|
|||
}
|
||||
end
|
||||
|
||||
def test_write_nonblock_simple_no_exceptions
|
||||
skip "IO#write_nonblock is not supported on file/pipe." if /mswin|bccwin|mingw/ =~ RUBY_PLATFORM
|
||||
pipe(proc do |w|
|
||||
w.write_nonblock('1', exception: false)
|
||||
w.close
|
||||
end, proc do |r|
|
||||
assert_equal("1", r.read)
|
||||
end)
|
||||
end
|
||||
|
||||
def test_read_nonblock_error
|
||||
return if !have_nonblock?
|
||||
skip "IO#read_nonblock is not supported on file/pipe." if /mswin|bccwin|mingw/ =~ RUBY_PLATFORM
|
||||
|
@ -1215,6 +1225,41 @@ class TestIO < Test::Unit::TestCase
|
|||
assert_kind_of(IO::WaitReadable, $!)
|
||||
end
|
||||
}
|
||||
|
||||
with_pipe {|r, w|
|
||||
begin
|
||||
r.read_nonblock 4096, ""
|
||||
rescue Errno::EWOULDBLOCK
|
||||
assert_kind_of(IO::WaitReadable, $!)
|
||||
end
|
||||
}
|
||||
end
|
||||
|
||||
def test_read_nonblock_no_exceptions
|
||||
return if !have_nonblock?
|
||||
skip "IO#read_nonblock is not supported on file/pipe." if /mswin|bccwin|mingw/ =~ RUBY_PLATFORM
|
||||
with_pipe {|r, w|
|
||||
assert_equal :wait_readable, r.read_nonblock(4096, exception: false)
|
||||
w.puts "HI!"
|
||||
assert_equal "HI!\n", r.read_nonblock(4096, exception: false)
|
||||
w.close
|
||||
assert_equal nil, r.read_nonblock(4096, exception: false)
|
||||
}
|
||||
end
|
||||
|
||||
def test_read_nonblock_with_buffer_no_exceptions
|
||||
return if !have_nonblock?
|
||||
skip "IO#read_nonblock is not supported on file/pipe." if /mswin|bccwin|mingw/ =~ RUBY_PLATFORM
|
||||
with_pipe {|r, w|
|
||||
assert_equal :wait_readable, r.read_nonblock(4096, "", exception: false)
|
||||
w.puts "HI!"
|
||||
buf = "buf"
|
||||
value = r.read_nonblock(4096, buf, exception: false)
|
||||
assert_equal value, "HI!\n"
|
||||
assert buf.equal?(value)
|
||||
w.close
|
||||
assert_equal nil, r.read_nonblock(4096, "", exception: false)
|
||||
}
|
||||
end
|
||||
|
||||
def test_write_nonblock_error
|
||||
|
@ -1231,6 +1276,20 @@ class TestIO < Test::Unit::TestCase
|
|||
}
|
||||
end
|
||||
|
||||
def test_write_nonblock_no_exceptions
|
||||
return if !have_nonblock?
|
||||
skip "IO#write_nonblock is not supported on file/pipe." if /mswin|bccwin|mingw/ =~ RUBY_PLATFORM
|
||||
with_pipe {|r, w|
|
||||
loop {
|
||||
ret = w.write_nonblock("a"*100000, exception: false)
|
||||
if ret.is_a?(Symbol)
|
||||
assert_equal :wait_writable, ret
|
||||
break
|
||||
end
|
||||
}
|
||||
}
|
||||
end
|
||||
|
||||
def test_gets
|
||||
pipe(proc do |w|
|
||||
w.write "foobarbaz"
|
||||
|
|
|
@ -190,6 +190,20 @@ class TestSocketNonblock < Test::Unit::TestCase
|
|||
s.close if s
|
||||
end
|
||||
|
||||
def test_read_nonblock_no_exception
|
||||
c, s = tcp_pair
|
||||
assert_equal :wait_readable, c.read_nonblock(100, exception: false)
|
||||
assert_equal :wait_readable, s.read_nonblock(100, exception: false)
|
||||
c.write("abc")
|
||||
IO.select [s]
|
||||
assert_equal("a", s.read_nonblock(1, exception: false))
|
||||
assert_equal("bc", s.read_nonblock(100, exception: false))
|
||||
assert_equal :wait_readable, s.read_nonblock(100, exception: false)
|
||||
ensure
|
||||
c.close if c
|
||||
s.close if s
|
||||
end
|
||||
|
||||
=begin
|
||||
def test_write_nonblock
|
||||
c, s = tcp_pair
|
||||
|
|
|
@ -89,6 +89,14 @@ class TestStringIO < Test::Unit::TestCase
|
|||
f.close unless f.closed?
|
||||
end
|
||||
|
||||
def test_write_nonblock_no_exceptions
|
||||
s = ""
|
||||
f = StringIO.new(s, "w")
|
||||
f.write_nonblock("foo", exception: false)
|
||||
f.close
|
||||
assert_equal("foo", s)
|
||||
end
|
||||
|
||||
def test_write_nonblock
|
||||
s = ""
|
||||
f = StringIO.new(s, "w")
|
||||
|
@ -437,7 +445,7 @@ class TestStringIO < Test::Unit::TestCase
|
|||
f = StringIO.new("\u3042\u3044")
|
||||
assert_raise(ArgumentError) { f.readpartial(-1) }
|
||||
assert_raise(ArgumentError) { f.readpartial(1, 2, 3) }
|
||||
assert_equal("\u3042\u3044", f.readpartial)
|
||||
assert_equal("\u3042\u3044".force_encoding(Encoding::ASCII_8BIT), f.readpartial(100))
|
||||
f.rewind
|
||||
assert_equal("\u3042\u3044".force_encoding(Encoding::ASCII_8BIT), f.readpartial(f.size))
|
||||
f.rewind
|
||||
|
@ -450,7 +458,19 @@ class TestStringIO < Test::Unit::TestCase
|
|||
f = StringIO.new("\u3042\u3044")
|
||||
assert_raise(ArgumentError) { f.read_nonblock(-1) }
|
||||
assert_raise(ArgumentError) { f.read_nonblock(1, 2, 3) }
|
||||
assert_equal("\u3042\u3044", f.read_nonblock)
|
||||
assert_equal("\u3042\u3044".force_encoding("BINARY"), f.read_nonblock(100))
|
||||
assert_raise(EOFError) { f.read_nonblock(10) }
|
||||
f.rewind
|
||||
assert_equal("\u3042\u3044".force_encoding(Encoding::ASCII_8BIT), f.read_nonblock(f.size))
|
||||
end
|
||||
|
||||
def test_read_nonblock_no_exceptions
|
||||
f = StringIO.new("\u3042\u3044")
|
||||
assert_raise(ArgumentError) { f.read_nonblock(-1, exception: false) }
|
||||
assert_raise(ArgumentError) { f.read_nonblock(1, 2, 3, exception: false) }
|
||||
assert_raise(ArgumentError) { f.read_nonblock }
|
||||
assert_equal("\u3042\u3044".force_encoding(Encoding::ASCII_8BIT), f.read_nonblock(100, exception: false))
|
||||
assert_equal(nil, f.read_nonblock(10, exception: false))
|
||||
f.rewind
|
||||
assert_equal("\u3042\u3044".force_encoding(Encoding::ASCII_8BIT), f.read_nonblock(f.size))
|
||||
f.rewind
|
||||
|
|
Загрузка…
Ссылка в новой задаче