1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162
|
require 'spec_helper'
require 'openssl'
describe OpenSSL::SSL::SSLSocket, :if => RUBY_VERSION >= "1.9.0" do
let(:tcp_port) { 34567 }
let(:ssl_key) { OpenSSL::PKey::RSA.new(1024) }
let(:ssl_cert) do
name = OpenSSL::X509::Name.new([%w[CN localhost]])
OpenSSL::X509::Certificate.new.tap do |cert|
cert.version = 2
cert.serial = 1
cert.issuer = name
cert.subject = name
cert.not_before = Time.now
cert.not_after = Time.now + (365 * 24 *60 *60)
cert.public_key = ssl_key.public_key
cert.sign(ssl_key, OpenSSL::Digest::SHA1.new)
end
end
let(:ssl_server_context) do
OpenSSL::SSL::SSLContext.new.tap do |ctx|
ctx.cert = ssl_cert
ctx.key = ssl_key
end
end
let :readable_subject do
server = TCPServer.new("localhost", tcp_port)
client = TCPSocket.open("localhost", tcp_port)
peer = server.accept
ssl_peer = OpenSSL::SSL::SSLSocket.new(peer, ssl_server_context)
ssl_peer.sync_close = true
ssl_client = OpenSSL::SSL::SSLSocket.new(client)
ssl_client.sync_close = true
# SSLSocket#connect and #accept are blocking calls.
thread = Thread.new { ssl_client.connect }
ssl_peer.accept
ssl_peer << "data"
thread.join
pending "Failed to produce a readable SSL socket" unless select([ssl_client], [], [], 0)
ssl_client
end
let :unreadable_subject do
server = TCPServer.new("localhost", tcp_port + 1)
client = TCPSocket.new("localhost", tcp_port + 1)
peer = server.accept
ssl_peer = OpenSSL::SSL::SSLSocket.new(peer, ssl_server_context)
ssl_peer.sync_close = true
ssl_client = OpenSSL::SSL::SSLSocket.new(client)
ssl_client.sync_close = true
# SSLSocket#connect and #accept are blocking calls.
thread = Thread.new { ssl_client.connect }
ssl_peer.accept
thread.join
pending "Failed to produce an unreadable socket" if select([ssl_client], [], [], 0)
ssl_client
end
let :writable_subject do
server = TCPServer.new("localhost", tcp_port + 2)
client = TCPSocket.new("localhost", tcp_port + 2)
peer = server.accept
ssl_peer = OpenSSL::SSL::SSLSocket.new(peer, ssl_server_context)
ssl_peer.sync_close = true
ssl_client = OpenSSL::SSL::SSLSocket.new(client)
ssl_client.sync_close = true
# SSLSocket#connect and #accept are blocking calls.
thread = Thread.new { ssl_client.connect }
ssl_peer.accept
thread.join
ssl_client
end
let :unwritable_subject do
server = TCPServer.new("localhost", tcp_port + 3)
client = TCPSocket.open("localhost", tcp_port + 3)
peer = server.accept
ssl_peer = OpenSSL::SSL::SSLSocket.new(peer, ssl_server_context)
ssl_peer.sync_close = true
ssl_client = OpenSSL::SSL::SSLSocket.new(client)
ssl_client.sync_close = true
# SSLSocket#connect and #accept are blocking calls.
thread = Thread.new { ssl_client.connect }
ssl_peer.accept
thread.join
begin
_, writers = select [], [ssl_client], [], 0
count = ssl_client.write_nonblock "X" * 1024
count.should_not == 0
rescue IO::WaitReadable, IO::WaitWritable
pending "SSL will report writable but not accept writes"
raise if(writers.include? ssl_client)
end while writers and writers.include? ssl_client
# I think the kernel might manage to drain its buffer a bit even after
# the socket first goes unwritable. Attempt to sleep past this and then
# attempt to write again
sleep 0.1
# Once more for good measure!
begin
# ssl_client.write_nonblock "X" * 1024
loop { ssl_client.write_nonblock "X" * 1024 }
rescue OpenSSL::SSL::SSLError
end
# Sanity check to make sure we actually produced an unwritable socket
# if select([], [ssl_client], [], 0)
# pending "Failed to produce an unwritable socket"
# end
ssl_client
end
let :pair do
pending "figure out why newly created sockets are selecting readable immediately"
server = TCPServer.new("localhost", tcp_port + 4)
client = TCPSocket.open("localhost", tcp_port + 4)
peer = server.accept
ssl_peer = OpenSSL::SSL::SSLSocket.new(peer, ssl_server_context)
ssl_peer.sync_close = true
ssl_client = OpenSSL::SSL::SSLSocket.new(client)
ssl_client.sync_close = true
# SSLSocket#connect and #accept are blocking calls.
thread = Thread.new { ssl_client.connect }
ssl_peer.accept
[thread.value, ssl_peer]
end
it_behaves_like "an NIO selectable"
it_behaves_like "an NIO selectable stream"
end
|