jruby-openssl 0.9.12-java → 0.9.13-java

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: fec096b2836ecf41ff7fabe0ad5623d2baaefe61
4
- data.tar.gz: 7f38c9c23b808c4067a676031dcdf919789a2447
3
+ metadata.gz: 53cfa91375f8c240492465413cf80832989950be
4
+ data.tar.gz: 95559557d8c369fc21f72087814edc4b24f0a9db
5
5
  SHA512:
6
- metadata.gz: e947998f76eb5b88011fad21f5d4f99f89ae5f2998901af639a4d8b7f3c764163b2222928b82832ce5a22d7fdd0309b503336c7b3c3a278069ec271c0bcf27ca
7
- data.tar.gz: c6a11ed1cc98646f35f56552c89fe3143621041cbabab2a16f8858b453023430efd0e4ca1292a45b7e815a562456a165f1765263f55023e4be2dc1f1d706ac76
6
+ metadata.gz: f6ece1c6fc0caa3f4fbb395f0383fba916420d1f0fa038793b94a437afca8c743e3316f37d00a9047ffec419a9ac77f817bcbc14f3f76db4148def5b5fa89093
7
+ data.tar.gz: 7699d18401244b3ef64ceaf959b46ef21cf689ed251e1476e722831a71c1679dd622463aab74d4c16fb8624bec496e9e35f6b28d6ac0baaad985789b9ccbf849
data/Rakefile CHANGED
@@ -37,8 +37,9 @@ file('lib/jopenssl.jar') { Rake::Task['jar'].invoke }
37
37
 
38
38
  require 'rake/testtask'
39
39
  Rake::TestTask.new do |task|
40
- task.libs << 'lib'
41
- task.test_files = FileList['src/test/ruby/**/test*.rb']
40
+ task.libs << 'src/test/ruby'
41
+ test_files = FileList['src/test/ruby/**/test*.rb'].to_a
42
+ task.test_files = test_files.map { |path| path.sub('src/test/ruby/', '') }
42
43
  task.verbose = true
43
44
  task.loader = :direct
44
45
  end
@@ -58,6 +59,8 @@ namespace :integration do
58
59
  end
59
60
  loader = "ARGV.each { |f| require f }"
60
61
  test_files = FileList['src/test/integration/*_test.rb'].to_a
61
- ruby "-Ilib -e \"#{loader}\" #{test_files.map { |f| "\"#{f}\"" }.join(' ')}"
62
+ test_files.map! { |path| path.sub('src/test/integration/', '') }
63
+ lib = [ 'lib', 'src/test/integration' ]
64
+ ruby "-I#{lib.join(':')} -e \"#{loader}\" #{test_files.map { |f| "\"#{f}\"" }.join(' ')}"
62
65
  end
63
66
  end
data/lib/jopenssl.jar CHANGED
Binary file
data/lib/jopenssl/load.rb CHANGED
@@ -24,7 +24,9 @@ require 'jruby'
24
24
  require 'jopenssl.jar'
25
25
  org.jruby.ext.openssl.OpenSSL.load(JRuby.runtime)
26
26
 
27
- if RUBY_VERSION > '2.2'
27
+ if RUBY_VERSION > '2.3'
28
+ load 'jopenssl23/openssl.rb'
29
+ elsif RUBY_VERSION > '2.2'
28
30
  load 'jopenssl22/openssl.rb'
29
31
  elsif RUBY_VERSION > '2.1'
30
32
  load 'jopenssl21/openssl.rb'
@@ -1,6 +1,11 @@
1
1
  module Jopenssl
2
+ VERSION = '0.9.13'
3
+ BOUNCY_CASTLE_VERSION = '1.50'
4
+ # @deprecated
2
5
  module Version
3
- VERSION = '0.9.12'
4
- BOUNCY_CASTLE_VERSION = '1.50'
6
+ # @private
7
+ VERSION = Jopenssl::VERSION
8
+ # @private
9
+ BOUNCY_CASTLE_VERSION = Jopenssl::BOUNCY_CASTLE_VERSION
5
10
  end
6
- end
11
+ end
@@ -15,42 +15,154 @@
15
15
  =end
16
16
 
17
17
  require "openssl/buffering"
18
- require 'fcntl' # used by OpenSSL::SSL::Nonblock (if loaded)
18
+ require "fcntl"
19
19
 
20
20
  module OpenSSL
21
21
  module SSL
22
+ class SSLContext
23
+ DEFAULT_PARAMS = {
24
+ :ssl_version => "SSLv23",
25
+ :verify_mode => OpenSSL::SSL::VERIFY_PEER,
26
+ :ciphers => %w{
27
+ ECDHE-ECDSA-AES128-GCM-SHA256
28
+ ECDHE-RSA-AES128-GCM-SHA256
29
+ ECDHE-ECDSA-AES256-GCM-SHA384
30
+ ECDHE-RSA-AES256-GCM-SHA384
31
+ DHE-RSA-AES128-GCM-SHA256
32
+ DHE-DSS-AES128-GCM-SHA256
33
+ DHE-RSA-AES256-GCM-SHA384
34
+ DHE-DSS-AES256-GCM-SHA384
35
+ ECDHE-ECDSA-AES128-SHA256
36
+ ECDHE-RSA-AES128-SHA256
37
+ ECDHE-ECDSA-AES128-SHA
38
+ ECDHE-RSA-AES128-SHA
39
+ ECDHE-ECDSA-AES256-SHA384
40
+ ECDHE-RSA-AES256-SHA384
41
+ ECDHE-ECDSA-AES256-SHA
42
+ ECDHE-RSA-AES256-SHA
43
+ DHE-RSA-AES128-SHA256
44
+ DHE-RSA-AES256-SHA256
45
+ DHE-RSA-AES128-SHA
46
+ DHE-RSA-AES256-SHA
47
+ DHE-DSS-AES128-SHA256
48
+ DHE-DSS-AES256-SHA256
49
+ DHE-DSS-AES128-SHA
50
+ DHE-DSS-AES256-SHA
51
+ AES128-GCM-SHA256
52
+ AES256-GCM-SHA384
53
+ AES128-SHA256
54
+ AES256-SHA256
55
+ AES128-SHA
56
+ AES256-SHA
57
+ ECDHE-ECDSA-RC4-SHA
58
+ ECDHE-RSA-RC4-SHA
59
+ RC4-SHA
60
+ }.join(":"),
61
+ :options => -> {
62
+ opts = OpenSSL::SSL::OP_ALL
63
+ opts &= ~OpenSSL::SSL::OP_DONT_INSERT_EMPTY_FRAGMENTS if defined?(OpenSSL::SSL::OP_DONT_INSERT_EMPTY_FRAGMENTS)
64
+ opts |= OpenSSL::SSL::OP_NO_COMPRESSION if defined?(OpenSSL::SSL::OP_NO_COMPRESSION)
65
+ opts |= OpenSSL::SSL::OP_NO_SSLv2 if defined?(OpenSSL::SSL::OP_NO_SSLv2)
66
+ opts |= OpenSSL::SSL::OP_NO_SSLv3 if defined?(OpenSSL::SSL::OP_NO_SSLv3)
67
+ opts
68
+ }.call
69
+ } unless const_defined? :DEFAULT_PARAMS # JRuby does it in Java
70
+
71
+ unless const_defined? :DEFAULT_CERT_STORE # JRuby specific
72
+ DEFAULT_CERT_STORE = OpenSSL::X509::Store.new
73
+ DEFAULT_CERT_STORE.set_default_paths
74
+ if defined?(OpenSSL::X509::V_FLAG_CRL_CHECK_ALL)
75
+ DEFAULT_CERT_STORE.flags = OpenSSL::X509::V_FLAG_CRL_CHECK_ALL
76
+ end
77
+ end
78
+
79
+ ##
80
+ # Sets the parameters for this SSL context to the values in +params+.
81
+ # The keys in +params+ must be assignment methods on SSLContext.
82
+ #
83
+ # If the verify_mode is not VERIFY_NONE and ca_file, ca_path and
84
+ # cert_store are not set then the system default certificate store is
85
+ # used.
86
+
87
+ def set_params(params={})
88
+ params = DEFAULT_PARAMS.merge(params)
89
+ params.each{|name, value| self.__send__("#{name}=", value) }
90
+ if self.verify_mode != OpenSSL::SSL::VERIFY_NONE
91
+ unless self.ca_file or self.ca_path or self.cert_store
92
+ self.cert_store = DEFAULT_CERT_STORE
93
+ end
94
+ end
95
+ return params
96
+ end unless method_defined? :set_params # JRuby: hooked up in "native" Java
97
+ end
98
+
99
+ module SocketForwarder
100
+ def addr
101
+ to_io.addr
102
+ end
103
+
104
+ def peeraddr
105
+ to_io.peeraddr
106
+ end
107
+
108
+ def setsockopt(level, optname, optval)
109
+ to_io.setsockopt(level, optname, optval)
110
+ end
111
+
112
+ def getsockopt(level, optname)
113
+ to_io.getsockopt(level, optname)
114
+ end
115
+
116
+ def fcntl(*args)
117
+ to_io.fcntl(*args)
118
+ end
119
+
120
+ def closed?
121
+ to_io.closed?
122
+ end
123
+
124
+ def do_not_reverse_lookup=(flag)
125
+ to_io.do_not_reverse_lookup = flag
126
+ end
127
+ end unless const_defined? :SocketForwarder # JRuby: hooked up in "native" Java
128
+
129
+ module Nonblock
130
+ def initialize(*args)
131
+ flag = File::NONBLOCK
132
+ flag |= @io.fcntl(Fcntl::F_GETFL) if defined?(Fcntl::F_GETFL)
133
+ @io.fcntl(Fcntl::F_SETFL, flag)
134
+ super
135
+ end
136
+ end unless const_defined? :Nonblock # JRuby: hooked up in "native" Java
22
137
 
23
- # FIXME: Using the old non-ASN1 logic here because our ASN1 appears to
24
- # return the wrong types for some decoded objects.
25
- # @see https://github.com/jruby/jruby/issues/1102
26
- # @private
27
138
  def verify_certificate_identity(cert, hostname)
28
139
  should_verify_common_name = true
29
140
  cert.extensions.each { |ext|
30
141
  next if ext.oid != "subjectAltName"
31
142
  ext.value.split(/,\s+/).each { |general_name|
32
- # MRI 1.9.3 (since we parse ASN.1 differently)
33
- # when 2 # dNSName in GeneralName (RFC5280)
143
+ #case san.tag
144
+ # MRI 2.2.3 (JRuby parses ASN.1 differently)
145
+ #when 2 # dNSName in GeneralName (RFC5280)
34
146
  if /\ADNS:(.*)/ =~ general_name
35
147
  should_verify_common_name = false
36
148
  return true if verify_hostname(hostname, $1)
37
- # MRI 1.9.3 (since we parse ASN.1 differently)
38
- # when 7 # iPAddress in GeneralName (RFC5280)
149
+ # MRI 2.2.3 (JRuby parses ASN.1 differently)
150
+ #when 7 # iPAddress in GeneralName (RFC5280)
39
151
  elsif /\AIP(?: Address)?:(.*)/ =~ general_name
40
152
  should_verify_common_name = false
41
153
  return true if $1 == hostname
42
- # NOTE: bellow logic makes little sense as we read exts differently
43
- #value = $1 # follows GENERAL_NAME_print() in x509v3/v3_alt.c
44
- #if value.size == 4
45
- # return true if value.unpack('C*').join('.') == hostname
46
- #elsif value.size == 16
47
- # return true if value.unpack('n*').map { |e| sprintf("%X", e) }.join(':') == hostname
154
+ # NOTE: bellow logic makes little sense JRuby reads exts differently
155
+ # follows GENERAL_NAME_print() in x509v3/v3_alt.c
156
+ #if san.value.size == 4
157
+ # return true if san.value.unpack('C*').join('.') == hostname
158
+ #elsif san.value.size == 16
159
+ # return true if san.value.unpack('n*').map { |e| sprintf("%X", e) }.join(':') == hostname
48
160
  #end
49
161
  end
50
162
  }
51
163
  }
52
164
  if should_verify_common_name
53
- cert.subject.to_a.each { |oid, value|
165
+ cert.subject.to_a.each{|oid, value|
54
166
  if oid == "CN"
55
167
  return true if verify_hostname(hostname, value)
56
168
  end
@@ -122,12 +234,33 @@ module OpenSSL
122
234
  # This method MUST be called after calling #connect to ensure that the
123
235
  # hostname of a remote peer has been verified.
124
236
  def post_connection_check(hostname)
237
+ if peer_cert.nil?
238
+ msg = "Peer verification enabled, but no certificate received."
239
+ if using_anon_cipher?
240
+ msg += " Anonymous cipher suite #{cipher[0]} was negotiated. Anonymous suites must be disabled to use peer verification."
241
+ end
242
+ raise SSLError, msg
243
+ end
244
+
125
245
  unless OpenSSL::SSL.verify_certificate_identity(peer_cert, hostname)
126
246
  raise SSLError, "hostname \"#{hostname}\" does not match the server certificate"
127
247
  end
128
248
  return true
129
249
  end
130
250
 
251
+ #def session
252
+ # SSL::Session.new(self)
253
+ #rescue SSL::Session::SessionError
254
+ # nil
255
+ #end
256
+
257
+ private
258
+
259
+ def using_anon_cipher?
260
+ ctx = OpenSSL::SSL::SSLContext.new
261
+ ctx.ciphers = "aNULL"
262
+ ctx.ciphers.include?(cipher)
263
+ end
131
264
  end
132
265
 
133
266
  ##
@@ -178,8 +311,12 @@ module OpenSSL
178
311
  ssl.sync_close = true
179
312
  ssl.accept if @start_immediately
180
313
  ssl
181
- rescue SSLError => ex
182
- sock.close
314
+ rescue Exception => ex
315
+ if ssl
316
+ ssl.close
317
+ else
318
+ sock.close
319
+ end
183
320
  raise ex
184
321
  end
185
322
  end
@@ -0,0 +1,19 @@
1
+ # frozen_string_literal: false
2
+ =begin
3
+ = Info
4
+ 'OpenSSL for Ruby 2' project
5
+ Copyright (C) 2002 Michal Rokos <m.rokos@sh.cvut.cz>
6
+ All rights reserved.
7
+
8
+ = Licence
9
+ This program is licensed under the same licence as Ruby.
10
+ (See the file 'LICENCE'.)
11
+ =end
12
+
13
+ require 'openssl/bn'
14
+ require 'openssl/pkey'
15
+ require 'openssl/cipher'
16
+ require 'openssl/config'
17
+ require 'openssl/digest'
18
+ require 'openssl/x509'
19
+ require 'openssl/ssl'
@@ -0,0 +1,37 @@
1
+ # frozen_string_literal: false
2
+ #--
3
+ #
4
+ # = Ruby-space definitions that completes C-space funcs for BN
5
+ #
6
+ # = Info
7
+ # 'OpenSSL for Ruby 2' project
8
+ # Copyright (C) 2002 Michal Rokos <m.rokos@sh.cvut.cz>
9
+ # All rights reserved.
10
+ #
11
+ # = Licence
12
+ # This program is licensed under the same licence as Ruby.
13
+ # (See the file 'LICENCE'.)
14
+ #++
15
+
16
+ module OpenSSL
17
+ class BN
18
+ def pretty_print(q)
19
+ q.object_group(self) {
20
+ q.text ' '
21
+ q.text to_i.to_s
22
+ }
23
+ end
24
+ end # BN
25
+ end # OpenSSL
26
+
27
+ ##
28
+ # Add double dispatch to Integer
29
+ #
30
+ class Integer
31
+ # Casts an Integer as an OpenSSL::BN
32
+ #
33
+ # See `man bn` for more info.
34
+ def to_bn
35
+ OpenSSL::BN::new(self)
36
+ end
37
+ end # Integer
@@ -0,0 +1,453 @@
1
+ # coding: binary
2
+ # frozen_string_literal: false
3
+ #--
4
+ #= Info
5
+ # 'OpenSSL for Ruby 2' project
6
+ # Copyright (C) 2001 GOTOU YUUZOU <gotoyuzo@notwork.org>
7
+ # All rights reserved.
8
+ #
9
+ #= Licence
10
+ # This program is licensed under the same licence as Ruby.
11
+ # (See the file 'LICENCE'.)
12
+ #++
13
+
14
+ ##
15
+ # OpenSSL IO buffering mix-in module.
16
+ #
17
+ # This module allows an OpenSSL::SSL::SSLSocket to behave like an IO.
18
+ #
19
+ # You typically won't use this module directly, you can see it implemented in
20
+ # OpenSSL::SSL::SSLSocket.
21
+
22
+ module OpenSSL::Buffering
23
+ include Enumerable
24
+
25
+ ##
26
+ # The "sync mode" of the SSLSocket.
27
+ #
28
+ # See IO#sync for full details.
29
+
30
+ attr_accessor :sync
31
+
32
+ ##
33
+ # Default size to read from or write to the SSLSocket for buffer operations.
34
+
35
+ BLOCK_SIZE = 1024*16
36
+
37
+ ##
38
+ # Creates an instance of OpenSSL's buffering IO module.
39
+
40
+ def initialize(*)
41
+ # super
42
+ @eof = false
43
+ @rbuffer = ""
44
+ @sync = @io.sync
45
+ end
46
+
47
+ #
48
+ # for reading.
49
+ #
50
+ private
51
+
52
+ ##
53
+ # Fills the buffer from the underlying SSLSocket
54
+
55
+ def fill_rbuff
56
+ begin
57
+ @rbuffer << self.sysread(BLOCK_SIZE)
58
+ rescue Errno::EAGAIN
59
+ retry
60
+ rescue EOFError
61
+ @eof = true
62
+ end
63
+ end
64
+
65
+ ##
66
+ # Consumes +size+ bytes from the buffer
67
+
68
+ def consume_rbuff(size=nil)
69
+ if @rbuffer.empty?
70
+ nil
71
+ else
72
+ size = @rbuffer.size unless size
73
+ ret = @rbuffer[0, size]
74
+ @rbuffer[0, size] = ""
75
+ ret
76
+ end
77
+ end
78
+
79
+ public
80
+
81
+ ##
82
+ # Reads +size+ bytes from the stream. If +buf+ is provided it must
83
+ # reference a string which will receive the data.
84
+ #
85
+ # See IO#read for full details.
86
+
87
+ def read(size=nil, buf=nil)
88
+ if size == 0
89
+ if buf
90
+ buf.clear
91
+ return buf
92
+ else
93
+ return ""
94
+ end
95
+ end
96
+ until @eof
97
+ break if size && size <= @rbuffer.size
98
+ fill_rbuff
99
+ end
100
+ ret = consume_rbuff(size) || ""
101
+ if buf
102
+ buf.replace(ret)
103
+ ret = buf
104
+ end
105
+ (size && ret.empty?) ? nil : ret
106
+ end
107
+
108
+ ##
109
+ # Reads at most +maxlen+ bytes from the stream. If +buf+ is provided it
110
+ # must reference a string which will receive the data.
111
+ #
112
+ # See IO#readpartial for full details.
113
+
114
+ def readpartial(maxlen, buf=nil)
115
+ if maxlen == 0
116
+ if buf
117
+ buf.clear
118
+ return buf
119
+ else
120
+ return ""
121
+ end
122
+ end
123
+ if @rbuffer.empty?
124
+ begin
125
+ return sysread(maxlen, buf)
126
+ rescue Errno::EAGAIN
127
+ retry
128
+ end
129
+ end
130
+ ret = consume_rbuff(maxlen)
131
+ if buf
132
+ buf.replace(ret)
133
+ ret = buf
134
+ end
135
+ raise EOFError if ret.empty?
136
+ ret
137
+ end
138
+
139
+ ##
140
+ # Reads at most +maxlen+ bytes in the non-blocking manner.
141
+ #
142
+ # When no data can be read without blocking it raises
143
+ # OpenSSL::SSL::SSLError extended by IO::WaitReadable or IO::WaitWritable.
144
+ #
145
+ # IO::WaitReadable means SSL needs to read internally so read_nonblock
146
+ # should be called again when the underlying IO is readable.
147
+ #
148
+ # IO::WaitWritable means SSL needs to write internally so read_nonblock
149
+ # should be called again after the underlying IO is writable.
150
+ #
151
+ # OpenSSL::Buffering#read_nonblock needs two rescue clause as follows:
152
+ #
153
+ # # emulates blocking read (readpartial).
154
+ # begin
155
+ # result = ssl.read_nonblock(maxlen)
156
+ # rescue IO::WaitReadable
157
+ # IO.select([io])
158
+ # retry
159
+ # rescue IO::WaitWritable
160
+ # IO.select(nil, [io])
161
+ # retry
162
+ # end
163
+ #
164
+ # Note that one reason that read_nonblock writes to the underlying IO is
165
+ # when the peer requests a new TLS/SSL handshake. See openssl the FAQ for
166
+ # more details. http://www.openssl.org/support/faq.html
167
+
168
+ def read_nonblock(maxlen, buf=nil, exception: true)
169
+ if maxlen == 0
170
+ if buf
171
+ buf.clear
172
+ return buf
173
+ else
174
+ return ""
175
+ end
176
+ end
177
+ if @rbuffer.empty?
178
+ return sysread_nonblock(maxlen, buf, exception: exception)
179
+ end
180
+ ret = consume_rbuff(maxlen)
181
+ if buf
182
+ buf.replace(ret)
183
+ ret = buf
184
+ end
185
+ raise EOFError if ret.empty?
186
+ ret
187
+ end
188
+
189
+ ##
190
+ # Reads the next "line+ from the stream. Lines are separated by +eol+. If
191
+ # +limit+ is provided the result will not be longer than the given number of
192
+ # bytes.
193
+ #
194
+ # +eol+ may be a String or Regexp.
195
+ #
196
+ # Unlike IO#gets the line read will not be assigned to +$_+.
197
+ #
198
+ # Unlike IO#gets the separator must be provided if a limit is provided.
199
+
200
+ def gets(eol=$/, limit=nil)
201
+ idx = @rbuffer.index(eol)
202
+ until @eof
203
+ break if idx
204
+ fill_rbuff
205
+ idx = @rbuffer.index(eol)
206
+ end
207
+ if eol.is_a?(Regexp)
208
+ size = idx ? idx+$&.size : nil
209
+ else
210
+ size = idx ? idx+eol.size : nil
211
+ end
212
+ if size && limit && limit >= 0
213
+ size = [size, limit].min
214
+ end
215
+ consume_rbuff(size)
216
+ end
217
+
218
+ ##
219
+ # Executes the block for every line in the stream where lines are separated
220
+ # by +eol+.
221
+ #
222
+ # See also #gets
223
+
224
+ def each(eol=$/)
225
+ while line = self.gets(eol)
226
+ yield line
227
+ end
228
+ end
229
+ alias each_line each
230
+
231
+ ##
232
+ # Reads lines from the stream which are separated by +eol+.
233
+ #
234
+ # See also #gets
235
+
236
+ def readlines(eol=$/)
237
+ ary = []
238
+ while line = self.gets(eol)
239
+ ary << line
240
+ end
241
+ ary
242
+ end
243
+
244
+ ##
245
+ # Reads a line from the stream which is separated by +eol+.
246
+ #
247
+ # Raises EOFError if at end of file.
248
+
249
+ def readline(eol=$/)
250
+ raise EOFError if eof?
251
+ gets(eol)
252
+ end
253
+
254
+ ##
255
+ # Reads one character from the stream. Returns nil if called at end of
256
+ # file.
257
+
258
+ def getc
259
+ read(1)
260
+ end
261
+
262
+ ##
263
+ # Calls the given block once for each byte in the stream.
264
+
265
+ def each_byte # :yields: byte
266
+ while c = getc
267
+ yield(c.ord)
268
+ end
269
+ end
270
+
271
+ ##
272
+ # Reads a one-character string from the stream. Raises an EOFError at end
273
+ # of file.
274
+
275
+ def readchar
276
+ raise EOFError if eof?
277
+ getc
278
+ end
279
+
280
+ ##
281
+ # Pushes character +c+ back onto the stream such that a subsequent buffered
282
+ # character read will return it.
283
+ #
284
+ # Unlike IO#getc multiple bytes may be pushed back onto the stream.
285
+ #
286
+ # Has no effect on unbuffered reads (such as #sysread).
287
+
288
+ def ungetc(c)
289
+ @rbuffer[0,0] = c.chr
290
+ end
291
+
292
+ ##
293
+ # Returns true if the stream is at file which means there is no more data to
294
+ # be read.
295
+
296
+ def eof?
297
+ fill_rbuff if !@eof && @rbuffer.empty?
298
+ @eof && @rbuffer.empty?
299
+ end
300
+ alias eof eof?
301
+
302
+ #
303
+ # for writing.
304
+ #
305
+ private
306
+
307
+ ##
308
+ # Writes +s+ to the buffer. When the buffer is full or #sync is true the
309
+ # buffer is flushed to the underlying socket.
310
+
311
+ def do_write(s)
312
+ @wbuffer = "" unless defined? @wbuffer
313
+ @wbuffer << s
314
+ @wbuffer.force_encoding(Encoding::BINARY)
315
+ @sync ||= false
316
+ if @sync or @wbuffer.size > BLOCK_SIZE or idx = @wbuffer.rindex($/)
317
+ remain = idx ? idx + $/.size : @wbuffer.length
318
+ nwritten = 0
319
+ while remain > 0
320
+ str = @wbuffer[nwritten,remain]
321
+ begin
322
+ nwrote = syswrite(str)
323
+ rescue Errno::EAGAIN
324
+ retry
325
+ end
326
+ remain -= nwrote
327
+ nwritten += nwrote
328
+ end
329
+ @wbuffer[0,nwritten] = ""
330
+ end
331
+ end
332
+
333
+ public
334
+
335
+ ##
336
+ # Writes +s+ to the stream. If the argument is not a string it will be
337
+ # converted using String#to_s. Returns the number of bytes written.
338
+
339
+ def write(s)
340
+ do_write(s)
341
+ s.bytesize
342
+ end
343
+
344
+ ##
345
+ # Writes +str+ in the non-blocking manner.
346
+ #
347
+ # If there is buffered data, it is flushed first. This may block.
348
+ #
349
+ # write_nonblock returns number of bytes written to the SSL connection.
350
+ #
351
+ # When no data can be written without blocking it raises
352
+ # OpenSSL::SSL::SSLError extended by IO::WaitReadable or IO::WaitWritable.
353
+ #
354
+ # IO::WaitReadable means SSL needs to read internally so write_nonblock
355
+ # should be called again after the underlying IO is readable.
356
+ #
357
+ # IO::WaitWritable means SSL needs to write internally so write_nonblock
358
+ # should be called again after underlying IO is writable.
359
+ #
360
+ # So OpenSSL::Buffering#write_nonblock needs two rescue clause as follows.
361
+ #
362
+ # # emulates blocking write.
363
+ # begin
364
+ # result = ssl.write_nonblock(str)
365
+ # rescue IO::WaitReadable
366
+ # IO.select([io])
367
+ # retry
368
+ # rescue IO::WaitWritable
369
+ # IO.select(nil, [io])
370
+ # retry
371
+ # end
372
+ #
373
+ # Note that one reason that write_nonblock reads from the underlying IO
374
+ # is when the peer requests a new TLS/SSL handshake. See the openssl FAQ
375
+ # for more details. http://www.openssl.org/support/faq.html
376
+
377
+ def write_nonblock(s, exception: true)
378
+ flush
379
+ syswrite_nonblock(s, exception: exception)
380
+ end
381
+
382
+ ##
383
+ # Writes +s+ to the stream. +s+ will be converted to a String using
384
+ # String#to_s.
385
+
386
+ def << (s)
387
+ do_write(s)
388
+ self
389
+ end
390
+
391
+ ##
392
+ # Writes +args+ to the stream along with a record separator.
393
+ #
394
+ # See IO#puts for full details.
395
+
396
+ def puts(*args)
397
+ s = ""
398
+ if args.empty?
399
+ s << "\n"
400
+ end
401
+ args.each{|arg|
402
+ s << arg.to_s
403
+ if $/ && /\n\z/ !~ s
404
+ s << "\n"
405
+ end
406
+ }
407
+ do_write(s)
408
+ nil
409
+ end
410
+
411
+ ##
412
+ # Writes +args+ to the stream.
413
+ #
414
+ # See IO#print for full details.
415
+
416
+ def print(*args)
417
+ s = ""
418
+ args.each{ |arg| s << arg.to_s }
419
+ do_write(s)
420
+ nil
421
+ end
422
+
423
+ ##
424
+ # Formats and writes to the stream converting parameters under control of
425
+ # the format string.
426
+ #
427
+ # See Kernel#sprintf for format string details.
428
+
429
+ def printf(s, *args)
430
+ do_write(s % args)
431
+ nil
432
+ end
433
+
434
+ ##
435
+ # Flushes buffered data to the SSLSocket.
436
+
437
+ def flush
438
+ osync = @sync
439
+ @sync = true
440
+ do_write ""
441
+ return self
442
+ ensure
443
+ @sync = osync
444
+ end
445
+
446
+ ##
447
+ # Closes the SSLSocket and flushes any unwritten data.
448
+
449
+ def close
450
+ flush rescue nil
451
+ sysclose
452
+ end
453
+ end