Project

General

Profile

Bug #814 » better.patch

better patch with tests. - tenderlovemaking (Aaron Patterson), 12/04/2008 09:02 AM

View differences:

ext/openssl/ossl_ssl.c (working copy)
*/
#include "ossl.h"
#define rb_sys_fail_path(path) rb_sys_fail(NIL_P(path) ? 0 : RSTRING_PTR(path))
#if defined(HAVE_FCNTL_H) || defined(_WIN32)
#include <fcntl.h>
#elif defined(HAVE_SYS_FCNTL_H)
#include <sys/fcntl.h>
#endif
#if defined(HAVE_UNISTD_H)
# include <unistd.h> /* for read(), and write() */
#endif
......
static VALUE
ossl_ssl_read(int argc, VALUE *argv, VALUE self)
{
SSL *ssl;
int ilen, nread = 0;
VALUE len, str;
rb_io_t *fptr;
rb_scan_args(argc, argv, "11", &len, &str);
ilen = NUM2INT(len);
if(NIL_P(str)) str = rb_str_new(0, ilen);
else{
StringValue(str);
rb_str_modify(str);
rb_str_resize(str, ilen);
}
if(ilen == 0) return str;
Data_Get_Struct(self, SSL, ssl);
GetOpenFile(ossl_ssl_get_io(self), fptr);
if (ssl) {
if(SSL_pending(ssl) <= 0)
rb_thread_wait_fd(FPTR_TO_FD(fptr));
for (;;){
nread = SSL_read(ssl, RSTRING_PTR(str), RSTRING_LEN(str));
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(FPTR_TO_FD(fptr));
continue;
case SSL_ERROR_WANT_READ:
rb_io_wait_readable(FPTR_TO_FD(fptr));
continue;
case SSL_ERROR_SYSCALL:
if(ERR_peek_error() == 0 && nread == 0) rb_eof_error();
rb_sys_fail(0);
default:
ossl_raise(eSSLError, "SSL_read:");
}
}
}
else {
ID id_read_nonblock = rb_intern("read_nonblock");
rb_warning("SSL session is not started yet.");
return rb_funcall(ossl_ssl_get_io(self), id_read_nonblock, 2, len, str);
}
end:
rb_str_set_len(str, nread);
OBJ_TAINT(str);
return str;
}
/*
* call-seq:
* ssl.read_nonblock(length) => string
* ssl.read_nonblock(length, buffer) => buffer
*
* === Parameters
* * +length+ is a positive integer.
* * +buffer+ is a string used to store the result.
*/
static VALUE
ossl_ssl_read_nonblock(int argc, VALUE *argv, VALUE self)
{
SSL *ssl;
int ilen, nread = 0;
VALUE len, str;
......
Data_Get_Struct(self, SSL, ssl);
GetOpenFile(ossl_ssl_get_io(self), fptr);
rb_io_set_nonblock(fptr);
if (ssl) {
if(SSL_pending(ssl) <= 0)
rb_thread_wait_fd(FPTR_TO_FD(fptr));
for (;;){
nread = SSL_read(ssl, RSTRING_PTR(str), RSTRING_LEN(str));
switch(ssl_get_error(ssl, nread)){
switch(SSL_get_error(ssl, nread)){
case SSL_ERROR_NONE:
goto end;
case SSL_ERROR_ZERO_RETURN:
......
rb_io_wait_writable(FPTR_TO_FD(fptr));
continue;
case SSL_ERROR_WANT_READ:
rb_io_wait_readable(FPTR_TO_FD(fptr));
rb_sys_fail_path(fptr->pathv);
continue;
case SSL_ERROR_SYSCALL:
if(ERR_peek_error() == 0 && nread == 0) rb_eof_error();
......
rb_define_method(cSSLSocket, "sysread", ossl_ssl_read, -1);
rb_define_method(cSSLSocket, "syswrite", ossl_ssl_write, 1);
rb_define_method(cSSLSocket, "sysclose", ossl_ssl_close, 0);
rb_define_method(cSSLSocket, "read_nonblock", ossl_ssl_read_nonblock, -1);
rb_define_method(cSSLSocket, "cert", ossl_ssl_get_cert, 0);
rb_define_method(cSSLSocket, "peer_cert", ossl_ssl_get_peer_cert, 0);
rb_define_method(cSSLSocket, "peer_cert_chain", ossl_ssl_get_peer_cert_chain, 0);
test/openssl/test_ssl.rb (working copy)
assert_equal(ctx.setup, nil)
end
def test_ssl_read_nonblock
start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true) { |server, port|
sock = TCPSocket.new("127.0.0.1", port)
ssl = OpenSSL::SSL::SSLSocket.new(sock)
ssl.sync_close = true
ssl.connect
assert_raise(Errno::EAGAIN, Errno::EWOULDBLOCK) { ssl.read_nonblock(100) }
ssl.write("abc\n")
IO.select [ssl]
assert_equal('a', ssl.read_nonblock(1))
assert_equal("bc\n", ssl.read_nonblock(100))
assert_raise(Errno::EAGAIN, Errno::EWOULDBLOCK) { ssl.read_nonblock(100) }
}
end
def test_connect_and_close
start_server(PORT, OpenSSL::SSL::VERIFY_NONE, true){|server, port|
sock = TCPSocket.new("127.0.0.1", port)
(2-2/2)