ione 1.2.0.pre1 → 1.2.0.pre2

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,21 @@
1
+ # encoding: utf-8
2
+
3
+
4
+ module Ione
5
+ module Io
6
+ # @private
7
+ class SslAcceptor < Acceptor
8
+ def initialize(host, port, backlog, unblocker, reactor, ssl_context, socket_impl=nil, ssl_socket_impl=nil)
9
+ super(host, port, backlog, unblocker, reactor, socket_impl)
10
+ @ssl_context = ssl_context
11
+ @ssl_socket_impl = ssl_socket_impl
12
+ end
13
+
14
+ def read
15
+ client_socket, host, port = accept
16
+ connection = SslServerConnection.new(client_socket, host, port, @unblocker, @ssl_context, method(:notify_accept_listeners), @ssl_socket_impl)
17
+ @reactor.accept(connection)
18
+ end
19
+ end
20
+ end
21
+ end
@@ -0,0 +1,79 @@
1
+ # encoding: utf-8
2
+
3
+ require 'openssl'
4
+
5
+
6
+ module Ione
7
+ module Io
8
+ # @private
9
+ class SslConnection < BaseConnection
10
+ def initialize(host, port, io, unblocker, ssl_context=nil, socket_impl=OpenSSL::SSL::SSLSocket)
11
+ super(host, port, unblocker)
12
+ @socket_impl = socket_impl
13
+ @ssl_context = ssl_context
14
+ @raw_io = io
15
+ @connected_promise = Promise.new
16
+ on_closed(&method(:cleanup_on_close))
17
+ end
18
+
19
+ def connect
20
+ if @io.nil? && @ssl_context
21
+ @io = @socket_impl.new(@raw_io, @ssl_context)
22
+ elsif @io.nil?
23
+ @io = @socket_impl.new(@raw_io)
24
+ end
25
+ @io.connect_nonblock
26
+ @state = :connected
27
+ @connected_promise.fulfill(self)
28
+ @connected_promise.future
29
+ rescue IO::WaitReadable, IO::WaitWritable
30
+ # WaitReadable in JRuby, WaitWritable in MRI
31
+ @connected_promise.future
32
+ rescue => e
33
+ close(e)
34
+ @connected_promise.future
35
+ end
36
+
37
+ def to_io
38
+ @raw_io
39
+ end
40
+
41
+ if RUBY_ENGINE == 'jruby'
42
+ # @private
43
+ def read
44
+ while true
45
+ new_data = @io.read_nonblock(2**16)
46
+ @data_listener.call(new_data) if @data_listener
47
+ end
48
+ rescue IO::WaitReadable
49
+ # no more data available
50
+ rescue => e
51
+ close(e)
52
+ end
53
+ else
54
+ # @private
55
+ def read
56
+ read_size = 2**16
57
+ while read_size > 0
58
+ new_data = @io.read_nonblock(read_size)
59
+ @data_listener.call(new_data) if @data_listener
60
+ read_size = @io.pending
61
+ end
62
+ rescue => e
63
+ close(e)
64
+ end
65
+ end
66
+
67
+ private
68
+
69
+ def cleanup_on_close(cause)
70
+ if cause && !cause.is_a?(IoError)
71
+ cause = ConnectionError.new(cause.message)
72
+ end
73
+ unless @connected_promise.future.completed?
74
+ @connected_promise.fail(cause)
75
+ end
76
+ end
77
+ end
78
+ end
79
+ end
@@ -0,0 +1,43 @@
1
+ # encoding: utf-8
2
+
3
+ module Ione
4
+ module Io
5
+ # @private
6
+ class SslServerConnection < ServerConnection
7
+ def initialize(socket, host, port, unblocker, ssl_context, accept_callback, ssl_socket_impl=nil)
8
+ super(socket, host, port, unblocker)
9
+ @ssl_context = ssl_context
10
+ @accept_callback = accept_callback
11
+ @ssl_socket_impl = ssl_socket_impl || OpenSSL::SSL::SSLSocket
12
+ @ssl_state = :accepting
13
+ end
14
+
15
+ # @private
16
+ def to_io
17
+ if @ssl_state == :established
18
+ @io.to_io
19
+ else
20
+ @io
21
+ end
22
+ end
23
+
24
+ def read
25
+ if @ssl_state == :accepting
26
+ begin
27
+ @ssl_io ||= @ssl_socket_impl.new(@io, @ssl_context)
28
+ @ssl_io.accept_nonblock
29
+ @io = @ssl_io
30
+ @ssl_state = :established
31
+ @accept_callback.call(self)
32
+ rescue IO::WaitReadable
33
+ # connection not ready yet
34
+ rescue => e
35
+ close(e)
36
+ end
37
+ else
38
+ super
39
+ end
40
+ end
41
+ end
42
+ end
43
+ end
data/lib/ione/version.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  # encoding: utf-8
2
2
 
3
3
  module Ione
4
- VERSION = '1.2.0.pre1'.freeze
4
+ VERSION = '1.2.0.pre2'.freeze
5
5
  end
@@ -0,0 +1,97 @@
1
+ # encoding: utf-8
2
+
3
+ require 'spec_helper'
4
+
5
+
6
+ describe 'SSL' do
7
+ let :io_reactor do
8
+ Ione::Io::IoReactor.new
9
+ end
10
+
11
+ let :port do
12
+ 2**15 + rand(2**15)
13
+ end
14
+
15
+ let :ssl_key do
16
+ OpenSSL::PKey::RSA.new(2048)
17
+ end
18
+
19
+ let :ssl_cert do
20
+ cert = OpenSSL::X509::Certificate.new
21
+ cert.version = 2
22
+ cert.serial = 1
23
+ name = OpenSSL::X509::Name.new([['CN', 'localhost']])
24
+ cert.subject = name
25
+ cert.issuer = name
26
+ cert.not_before = Time.now
27
+ cert.not_after = Time.now + (365*24*60*60)
28
+ cert.public_key = ssl_key.public_key
29
+ cert.sign(ssl_key, OpenSSL::Digest::SHA1.new)
30
+ cert
31
+ end
32
+
33
+ let :ssl_context do
34
+ ctx = OpenSSL::SSL::SSLContext.new
35
+ ctx.cert = ssl_cert
36
+ ctx.key = ssl_key
37
+ ctx
38
+ end
39
+
40
+ let :server_received_data do
41
+ Ione::ByteBuffer.new
42
+ end
43
+
44
+ let :client_received_data do
45
+ Ione::ByteBuffer.new
46
+ end
47
+
48
+ def start_server
49
+ ssl_context = OpenSSL::SSL::SSLContext.new
50
+ ssl_context.key = OpenSSL::PKey::RSA.new(ssl_key)
51
+ ssl_context.cert = OpenSSL::X509::Certificate.new(ssl_cert)
52
+
53
+ f = io_reactor.start
54
+ f = f.flat_map do
55
+ io_reactor.bind(ENV['SERVER_HOST'], port, ssl: ssl_context) do |acceptor|
56
+ acceptor.on_accept do |connection|
57
+ connection.on_data do |data|
58
+ server_received_data << data
59
+ connection.write(data.reverse)
60
+ end
61
+ end
62
+ end
63
+ end
64
+ f
65
+ end
66
+
67
+ it 'establishes an encrypted connection' do
68
+ ssl_context = OpenSSL::SSL::SSLContext.new
69
+ ssl_context.cert = OpenSSL::X509::Certificate.new(ssl_cert)
70
+
71
+ response_received = Ione::Promise.new
72
+ f = start_server
73
+ f = f.flat_map do
74
+ io_reactor.connect(ENV['SERVER_HOST'], port, ssl: ssl_context)
75
+ end
76
+ client = f.value
77
+ client.on_data do |data|
78
+ client_received_data << data
79
+ response_received.fulfill(data)
80
+ end
81
+ client.write('hello world')
82
+ response_received.future.value
83
+ server_received_data.to_s.should == 'hello world'
84
+ client_received_data.to_s.should == 'dlrow olleh'
85
+ end
86
+
87
+ it 'fails to send a message when not using encryption' do
88
+ f = start_server
89
+ f = f.flat_map do
90
+ io_reactor.connect(ENV['SERVER_HOST'], port)
91
+ end
92
+ client = f.value
93
+ client.write('hello world')
94
+ await { client.closed? }
95
+ client.should be_closed
96
+ end
97
+ end
@@ -211,15 +211,91 @@ module Ione
211
211
  f2.should equal(future)
212
212
  end
213
213
 
214
- it 'passes the value as the second parameter to the block' do
214
+ it 'passes the value as the first parameter to the block when it expects two arguments' do
215
215
  v1, v2 = nil, nil
216
- future.on_complete { |_, v| v1 = v }
217
- future.on_complete { |_, v| v2 = v }
216
+ future.on_complete { |v, _| v1 = v }
217
+ future.on_complete { |v, _| v2 = v }
218
218
  promise.fulfill('bar')
219
219
  v1.should == 'bar'
220
220
  v2.should == 'bar'
221
221
  end
222
222
 
223
+ it 'passes future as the third parameter to the block when it expects three arguments' do
224
+ f1, f2 = nil, nil
225
+ future.on_complete { |_, _, f| f1 = f }
226
+ future.on_complete { |_, _, f| f2 = f }
227
+ promise.fulfill('bar')
228
+ f1.should equal(future)
229
+ f2.should equal(future)
230
+ end
231
+
232
+ it 'passes the value, error and future to the block when it expects any number of arguments' do
233
+ value = 'bar'
234
+ error = StandardError.new('bork')
235
+ args1, args2 = nil, nil
236
+ p1 = Promise.new
237
+ p2 = Promise.new
238
+ p1.future.on_complete { |*a| args1 = a }
239
+ p2.future.on_complete { |*a| args2 = a }
240
+ p1.fulfill(value)
241
+ p2.fail(error)
242
+ args1[0].should equal(value)
243
+ args1[1].should be_nil
244
+ args1[2].should equal(p1.future)
245
+ args2[0].should be_nil
246
+ args2[1].should equal(error)
247
+ args2[2].should equal(p2.future)
248
+ end
249
+
250
+ it 'passes the value, error and future to the listener when the listener is a lambda' do
251
+ value = 'bar'
252
+ error = StandardError.new('bork')
253
+ args1, args2 = nil, nil
254
+ p1 = Promise.new
255
+ p2 = Promise.new
256
+ p1.future.on_complete(&lambda { |v, e, f| args1 = [v, e, f] })
257
+ p2.future.on_complete(&lambda { |v, e, f| args2 = [v, e, f] })
258
+ p1.fulfill(value)
259
+ p2.fail(error)
260
+ args1[0].should equal(value)
261
+ args1[1].should be_nil
262
+ args1[2].should equal(p1.future)
263
+ args2[0].should be_nil
264
+ args2[1].should equal(error)
265
+ args2[2].should equal(p2.future)
266
+ end
267
+
268
+ it 'ignores optional arguments for lambdas' do
269
+ value = 'bar'
270
+ error = StandardError.new('bork')
271
+ args1, args2 = nil, nil
272
+ p1 = Promise.new
273
+ p2 = Promise.new
274
+ p1.future.on_complete(&lambda { |v, e, f=nil| args1 = [v, e, f] })
275
+ p2.future.on_complete(&lambda { |v, e, f, x=1, y=2| args2 = [v, e, f, x, y] })
276
+ p1.fulfill(value)
277
+ p2.fail(error)
278
+ args1[0].should equal(value)
279
+ args1[1].should be_nil
280
+ args1[2].should be_nil
281
+ args2[0].should be_nil
282
+ args2[1].should equal(error)
283
+ args2[2].should equal(p2.future)
284
+ end
285
+
286
+ it 'does not handle listeners that are lambdas and have one optional argument' do
287
+ pending 'MRI 1.9.3 thinks these lambas have arity 1 and not -2' if RUBY_ENGINE == 'ruby' && RUBY_VERSION < '2.0.0'
288
+ called1, called2 = false, false
289
+ p1 = Promise.new
290
+ p2 = Promise.new
291
+ p1.future.on_complete(&lambda { |v, e=nil| called1 = true })
292
+ p2.future.on_complete(&lambda { |v, e=nil| called2 = true })
293
+ p1.fulfill('bar')
294
+ p2.fail(StandardError.new('bork'))
295
+ called1.should be_false
296
+ called2.should be_false
297
+ end
298
+
223
299
  it 'notifies all listeners when the promise fails' do
224
300
  c1, c2 = nil, nil
225
301
  future.on_complete { c1 = true }
@@ -229,10 +305,10 @@ module Ione
229
305
  c2.should be_true
230
306
  end
231
307
 
232
- it 'passes the error as the third parameter' do
308
+ it 'passes the error as the second parameter to the block when it expects two arguments' do
233
309
  e1, e2 = nil, nil
234
- future.on_complete { |_, _, e| e1 = e }
235
- future.on_complete { |_, _, e| e2 = e }
310
+ future.on_complete { |_, e| e1 = e }
311
+ future.on_complete { |_, e| e2 = e }
236
312
  future.fail(error)
237
313
  e1.should equal(error)
238
314
  e2.should equal(error)
@@ -257,7 +333,7 @@ module Ione
257
333
  it 'notifies listeners registered after the promise was fulfilled' do
258
334
  f, v, e = nil, nil, nil
259
335
  promise.fulfill('bar')
260
- future.on_complete { |ff, vv, ee| f = ff; v = vv; e = ee }
336
+ future.on_complete { |vv, ee, ff| v = vv; e = ee; f = ff }
261
337
  f.should equal(future)
262
338
  v.should == 'bar'
263
339
  e.should be_nil
@@ -266,7 +342,7 @@ module Ione
266
342
  it 'notifies listeners registered after the promise failed' do
267
343
  f, v, e = nil, nil, nil
268
344
  promise.fail(StandardError.new('bork'))
269
- future.on_complete { |ff, vv, ee| f = ff; v = vv; e = ee }
345
+ future.on_complete { |vv, ee, ff| v = vv; e = ee; f = ff }
270
346
  f.should equal(future)
271
347
  v.should be_nil
272
348
  e.message.should == 'bork'
@@ -274,7 +350,7 @@ module Ione
274
350
 
275
351
  it 'notifies listeners registered after the promise failed' do
276
352
  promise.fail(error)
277
- expect { future.on_complete { |v| raise 'blurgh' } }.to_not raise_error
353
+ expect { future.on_complete { raise 'blurgh' } }.to_not raise_error
278
354
  end
279
355
 
280
356
  it 'returns nil' do
@@ -432,6 +508,12 @@ module Ione
432
508
  promise.fulfill(:hello)
433
509
  listeners.map(&:value).should == Array.new(10, :hello)
434
510
  end
511
+
512
+ it 'is aliased as #get' do
513
+ obj = 'hello world'
514
+ promise.fulfill(obj)
515
+ future.get.should equal(obj)
516
+ end
435
517
  end
436
518
 
437
519
  describe '#map' do
@@ -512,7 +594,7 @@ module Ione
512
594
 
513
595
  it 'accepts anything that implements #on_complete as a chained future' do
514
596
  fake_future = double(:fake_future)
515
- fake_future.stub(:on_complete) { |&listener| listener.call(nil, :foobar) }
597
+ fake_future.stub(:on_complete) { |&listener| listener.call(:foobar, nil) }
516
598
  p = Promise.new
517
599
  f = p.future.flat_map { fake_future }
518
600
  p.fulfill
@@ -531,13 +613,26 @@ module Ione
531
613
  end
532
614
 
533
615
  context 'when the block returns something that quacks like a future' do
534
- it 'works like #flat_map' do
535
- fake_future = double(:fake_future)
536
- fake_future.stub(:on_complete) { |&listener| listener.call(nil, :foobar) }
537
- p = Promise.new
538
- f = p.future.then { |v| fake_future }
539
- p.fulfill
540
- f.value.should == :foobar
616
+ context 'and yields a value from #on_complete' do
617
+ it 'works like #flat_map' do
618
+ fake_future = double(:fake_future)
619
+ fake_future.stub(:on_complete) { |&listener| listener.call(:foobar) }
620
+ p = Promise.new
621
+ f = p.future.then { |v| fake_future }
622
+ p.fulfill
623
+ f.value.should == :foobar
624
+ end
625
+ end
626
+
627
+ context 'and yields an error from #on_complete' do
628
+ it 'works like #flat_map' do
629
+ fake_future = double(:fake_future)
630
+ fake_future.stub(:on_complete) { |&listener| listener.call(nil, StandardError.new('bork')) }
631
+ p = Promise.new
632
+ f = p.future.then { |v| fake_future }
633
+ p.fulfill
634
+ expect { f.value }.to raise_error(StandardError, 'bork')
635
+ end
541
636
  end
542
637
  end
543
638
 
@@ -662,7 +757,7 @@ module Ione
662
757
 
663
758
  it 'accepts anything that implements #on_complete as a fallback future' do
664
759
  fake_future = double(:fake_future)
665
- fake_future.stub(:on_complete) { |&listener| listener.call(nil, 'foo') }
760
+ fake_future.stub(:on_complete) { |&listener| listener.call('foo', nil) }
666
761
  p = Promise.new
667
762
  f = p.future.fallback { fake_future }
668
763
  p.fail(error)
@@ -703,7 +798,7 @@ module Ione
703
798
 
704
799
  it 'accepts anything that implements #on_complete as futures' do
705
800
  fake_future = double(:fake_future)
706
- fake_future.stub(:on_complete) { |&listener| listener.call(nil, :foobar) }
801
+ fake_future.stub(:on_complete) { |&listener| listener.call(:foobar, nil) }
707
802
  future = Future.traverse([1, 2, 3]) { fake_future }
708
803
  future.value.should == [:foobar, :foobar, :foobar]
709
804
  end
@@ -785,9 +880,9 @@ module Ione
785
880
 
786
881
  it 'accepts anything that implements #on_complete as futures' do
787
882
  ff1, ff2, ff3 = double, double, double
788
- ff1.stub(:on_complete) { |&listener| listener.call(nil, 1) }
789
- ff2.stub(:on_complete) { |&listener| listener.call(nil, 2) }
790
- ff3.stub(:on_complete) { |&listener| listener.call(nil, 3) }
883
+ ff1.stub(:on_complete) { |&listener| listener.call(1, nil) }
884
+ ff2.stub(:on_complete) { |&listener| listener.call(2, nil) }
885
+ ff3.stub(:on_complete) { |&listener| listener.call(3, nil) }
791
886
  future = Future.reduce([ff1, ff2, ff3], 0) { |sum, n| sum + n }
792
887
  future.value.should == 6
793
888
  end
@@ -907,9 +1002,9 @@ module Ione
907
1002
 
908
1003
  it 'accepts anything that implements #on_complete as futures' do
909
1004
  ff1, ff2, ff3 = double, double, double
910
- ff1.stub(:on_complete) { |&listener| listener.call(nil, 1) }
911
- ff2.stub(:on_complete) { |&listener| listener.call(nil, 2) }
912
- ff3.stub(:on_complete) { |&listener| listener.call(nil, 3) }
1005
+ ff1.stub(:on_complete) { |&listener| listener.call(1, nil) }
1006
+ ff2.stub(:on_complete) { |&listener| listener.call(2, nil) }
1007
+ ff3.stub(:on_complete) { |&listener| listener.call(3, nil) }
913
1008
  future = Future.all(ff1, ff2, ff3)
914
1009
  future.value.should == [1, 2, 3]
915
1010
  end
@@ -1006,8 +1101,8 @@ module Ione
1006
1101
 
1007
1102
  it 'accepts anything that implements #on_complete as futures' do
1008
1103
  ff1, ff2 = double, double
1009
- ff1.stub(:on_complete) { |&listener| listener.call(nil, 1) }
1010
- ff2.stub(:on_complete) { |&listener| listener.call(nil, 2) }
1104
+ ff1.stub(:on_complete) { |&listener| listener.call(1, nil) }
1105
+ ff2.stub(:on_complete) { |&listener| listener.call(2, nil) }
1011
1106
  future = Future.first(ff1, ff2)
1012
1107
  future.value.should == 1
1013
1108
  end
@@ -1040,11 +1135,21 @@ module Ione
1040
1135
 
1041
1136
  it 'calls its complete callbacks immediately' do
1042
1137
  f, v = nil, nil
1043
- future.on_complete { |ff, vv| f = ff; v = vv }
1138
+ future.on_complete { |vv, _, ff| f = ff; v = vv }
1044
1139
  f.should equal(future)
1045
1140
  v.should == 'hello world'
1046
1141
  end
1047
1142
 
1143
+ it 'calls its complete callbacks with the right arity' do
1144
+ f1, v, f2 = nil, nil, nil
1145
+ future.on_complete { |ff| f1 = ff }
1146
+ future.on_complete { |vv, ee| v = vv }
1147
+ future.on_complete { |vv, ee, ff| f2 = ff }
1148
+ f1.should equal(future)
1149
+ f2.should equal(future)
1150
+ v.should == 'hello world'
1151
+ end
1152
+
1048
1153
  it 'does not block on #value' do
1049
1154
  future.value.should == 'hello world'
1050
1155
  end
@@ -1081,15 +1186,25 @@ module Ione
1081
1186
 
1082
1187
  it 'calls its complete callbacks immediately' do
1083
1188
  f, e = nil, nil
1084
- future.on_complete { |ff, _, ee| f = ff; e = ee }
1189
+ future.on_complete { |_, ee, ff| f = ff; e = ee }
1085
1190
  f.should equal(future)
1086
1191
  e.message.should == 'bork'
1087
1192
  end
1088
1193
 
1194
+ it 'calls its complete callbacks with the right arity' do
1195
+ f1, e, f2 = nil, nil, nil
1196
+ future.on_complete { |ff| f1 = ff }
1197
+ future.on_complete { |vv, ee| e = ee }
1198
+ future.on_complete { |vv, ee, ff| f2 = ff }
1199
+ f1.should equal(future)
1200
+ f2.should equal(future)
1201
+ e.message.should == 'bork'
1202
+ end
1203
+
1089
1204
  it 'does not block on #value' do
1090
1205
  expect { future.value }.to raise_error('bork')
1091
1206
  end
1092
1207
  end
1093
1208
  end
1094
1209
  end
1095
- end
1210
+ end