jruby-openssl 0.9.5-java

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (54) hide show
  1. checksums.yaml +7 -0
  2. data/History.txt +218 -0
  3. data/License.txt +30 -0
  4. data/Mavenfile +44 -0
  5. data/README.txt +13 -0
  6. data/Rakefile +7 -0
  7. data/lib/jopenssl.jar +0 -0
  8. data/lib/jopenssl/load.rb +29 -0
  9. data/lib/jopenssl/version.rb +6 -0
  10. data/lib/jopenssl18/openssl.rb +23 -0
  11. data/lib/jopenssl18/openssl/bn.rb +35 -0
  12. data/lib/jopenssl18/openssl/buffering.rb +241 -0
  13. data/lib/jopenssl18/openssl/cipher.rb +65 -0
  14. data/lib/jopenssl18/openssl/config.rb +316 -0
  15. data/lib/jopenssl18/openssl/digest.rb +61 -0
  16. data/lib/jopenssl18/openssl/pkcs7.rb +25 -0
  17. data/lib/jopenssl18/openssl/ssl-internal.rb +179 -0
  18. data/lib/jopenssl18/openssl/ssl.rb +1 -0
  19. data/lib/jopenssl18/openssl/x509-internal.rb +153 -0
  20. data/lib/jopenssl18/openssl/x509.rb +1 -0
  21. data/lib/jopenssl19/openssl.rb +23 -0
  22. data/lib/jopenssl19/openssl/bn.rb +35 -0
  23. data/lib/jopenssl19/openssl/buffering.rb +449 -0
  24. data/lib/jopenssl19/openssl/cipher.rb +65 -0
  25. data/lib/jopenssl19/openssl/config.rb +313 -0
  26. data/lib/jopenssl19/openssl/digest.rb +72 -0
  27. data/lib/jopenssl19/openssl/ssl-internal.rb +177 -0
  28. data/lib/jopenssl19/openssl/ssl.rb +2 -0
  29. data/lib/jopenssl19/openssl/x509-internal.rb +158 -0
  30. data/lib/jopenssl19/openssl/x509.rb +2 -0
  31. data/lib/jopenssl21/openssl.rb +23 -0
  32. data/lib/jopenssl21/openssl/bn.rb +35 -0
  33. data/lib/jopenssl21/openssl/buffering.rb +449 -0
  34. data/lib/jopenssl21/openssl/cipher.rb +65 -0
  35. data/lib/jopenssl21/openssl/config.rb +313 -0
  36. data/lib/jopenssl21/openssl/digest.rb +89 -0
  37. data/lib/jopenssl21/openssl/ssl.rb +237 -0
  38. data/lib/jopenssl21/openssl/x509.rb +162 -0
  39. data/lib/jruby-openssl.rb +5 -0
  40. data/lib/openssl.rb +1 -0
  41. data/lib/openssl/bn.rb +7 -0
  42. data/lib/openssl/buffering.rb +7 -0
  43. data/lib/openssl/cipher.rb +7 -0
  44. data/lib/openssl/config.rb +7 -0
  45. data/lib/openssl/digest.rb +7 -0
  46. data/lib/openssl/pkcs12.rb +106 -0
  47. data/lib/openssl/pkcs7.rb +7 -0
  48. data/lib/openssl/ssl-internal.rb +7 -0
  49. data/lib/openssl/ssl.rb +7 -0
  50. data/lib/openssl/x509-internal.rb +7 -0
  51. data/lib/openssl/x509.rb +7 -0
  52. data/lib/org/bouncycastle/bcpkix-jdk15on/1.47/bcpkix-jdk15on-1.47.jar +0 -0
  53. data/lib/org/bouncycastle/bcprov-jdk15on/1.47/bcprov-jdk15on-1.47.jar +0 -0
  54. metadata +97 -0
@@ -0,0 +1,179 @@
1
+ =begin
2
+ = $RCSfile$ -- Ruby-space definitions that completes C-space funcs for SSL
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 licenced under the same licence as Ruby.
11
+ (See the file 'LICENCE'.)
12
+
13
+ = Version
14
+ $Id$
15
+ =end
16
+
17
+ require "openssl/buffering"
18
+ require "fcntl"
19
+
20
+ module OpenSSL
21
+ module SSL
22
+ class SSLContext
23
+ DEFAULT_PARAMS = {
24
+ :ssl_version => "SSLv23",
25
+ :verify_mode => OpenSSL::SSL::VERIFY_PEER,
26
+ :ciphers => "ALL:!ADH:!EXPORT:!SSLv2:RC4+RSA:+HIGH:+MEDIUM:+LOW",
27
+ :options => OpenSSL::SSL::OP_ALL,
28
+ }
29
+
30
+ DEFAULT_CERT_STORE = OpenSSL::X509::Store.new
31
+ DEFAULT_CERT_STORE.set_default_paths
32
+ if defined?(OpenSSL::X509::V_FLAG_CRL_CHECK_ALL)
33
+ DEFAULT_CERT_STORE.flags = OpenSSL::X509::V_FLAG_CRL_CHECK_ALL
34
+ end
35
+
36
+ def set_params(params={})
37
+ params = DEFAULT_PARAMS.merge(params)
38
+ # ssl_version need to be set at first.
39
+ self.ssl_version = params.delete(:ssl_version)
40
+ params.each{|name, value| self.__send__("#{name}=", value) }
41
+ if self.verify_mode != OpenSSL::SSL::VERIFY_NONE
42
+ unless self.ca_file or self.ca_path or self.cert_store
43
+ self.cert_store = DEFAULT_CERT_STORE
44
+ end
45
+ end
46
+ return params
47
+ end
48
+ end
49
+
50
+ module SocketForwarder
51
+ def addr
52
+ to_io.addr
53
+ end
54
+
55
+ def peeraddr
56
+ to_io.peeraddr
57
+ end
58
+
59
+ def setsockopt(level, optname, optval)
60
+ to_io.setsockopt(level, optname, optval)
61
+ end
62
+
63
+ def getsockopt(level, optname)
64
+ to_io.getsockopt(level, optname)
65
+ end
66
+
67
+ def fcntl(*args)
68
+ to_io.fcntl(*args)
69
+ end
70
+
71
+ def closed?
72
+ to_io.closed?
73
+ end
74
+
75
+ def do_not_reverse_lookup=(flag)
76
+ to_io.do_not_reverse_lookup = flag
77
+ end
78
+ end
79
+
80
+ module Nonblock
81
+ def initialize(*args)
82
+ flag = File::NONBLOCK
83
+ flag |= @io.fcntl(Fcntl::F_GETFL) if defined?(Fcntl::F_GETFL)
84
+ @io.fcntl(Fcntl::F_SETFL, flag)
85
+ super
86
+ end
87
+ end
88
+
89
+ def verify_certificate_identity(cert, hostname)
90
+ should_verify_common_name = true
91
+ cert.extensions.each{|ext|
92
+ next if ext.oid != "subjectAltName"
93
+ ext.value.split(/,\s+/).each{|general_name|
94
+ if /\ADNS:(.*)/ =~ general_name
95
+ should_verify_common_name = false
96
+ reg = Regexp.escape($1).gsub(/\\\*/, "[^.]+")
97
+ return true if /\A#{reg}\z/i =~ hostname
98
+ elsif /\AIP Address:(.*)/ =~ general_name
99
+ should_verify_common_name = false
100
+ return true if $1 == hostname
101
+ end
102
+ }
103
+ }
104
+ if should_verify_common_name
105
+ cert.subject.to_a.each{|oid, value|
106
+ if oid == "CN"
107
+ reg = Regexp.escape(value).gsub(/\\\*/, "[^.]+")
108
+ return true if /\A#{reg}\z/i =~ hostname
109
+ end
110
+ }
111
+ end
112
+ return false
113
+ end
114
+ module_function :verify_certificate_identity
115
+
116
+ class SSLSocket
117
+ include Buffering
118
+ include SocketForwarder
119
+ include Nonblock
120
+
121
+ def post_connection_check(hostname)
122
+ unless OpenSSL::SSL.verify_certificate_identity(peer_cert, hostname)
123
+ raise SSLError, "hostname was not match with the server certificate"
124
+ end
125
+ return true
126
+ end
127
+
128
+ def session
129
+ SSL::Session.new(self)
130
+ rescue SSL::Session::SessionError
131
+ nil
132
+ end
133
+ end
134
+
135
+ class SSLServer
136
+ include SocketForwarder
137
+ attr_accessor :start_immediately
138
+
139
+ def initialize(svr, ctx)
140
+ @svr = svr
141
+ @ctx = ctx
142
+ unless ctx.session_id_context
143
+ session_id = OpenSSL::Digest::MD5.hexdigest($0)
144
+ @ctx.session_id_context = session_id
145
+ end
146
+ @start_immediately = true
147
+ end
148
+
149
+ def to_io
150
+ @svr
151
+ end
152
+
153
+ def listen(backlog=5)
154
+ @svr.listen(backlog)
155
+ end
156
+
157
+ def shutdown(how=Socket::SHUT_RDWR)
158
+ @svr.shutdown(how)
159
+ end
160
+
161
+ def accept
162
+ sock = @svr.accept
163
+ begin
164
+ ssl = OpenSSL::SSL::SSLSocket.new(sock, @ctx)
165
+ ssl.sync_close = true
166
+ ssl.accept if @start_immediately
167
+ ssl
168
+ rescue SSLError => ex
169
+ sock.close
170
+ raise ex
171
+ end
172
+ end
173
+
174
+ def close
175
+ @svr.close
176
+ end
177
+ end
178
+ end
179
+ end
@@ -0,0 +1 @@
1
+ require 'openssl'
@@ -0,0 +1,153 @@
1
+ =begin
2
+ = $RCSfile$ -- Ruby-space definitions that completes C-space funcs for X509 and subclasses
3
+
4
+ = Info
5
+ 'OpenSSL for Ruby 2' project
6
+ Copyright (C) 2002 Michal Rokos <m.rokos@sh.cvut.cz>
7
+ All rights reserved.
8
+
9
+ = Licence
10
+ This program is licenced under the same licence as Ruby.
11
+ (See the file 'LICENCE'.)
12
+
13
+ = Version
14
+ $Id$
15
+ =end
16
+
17
+ module OpenSSL
18
+ module X509
19
+ class ExtensionFactory
20
+ def create_extension(*arg)
21
+ if arg.size > 1
22
+ create_ext(*arg)
23
+ else
24
+ send("create_ext_from_"+arg[0].class.name.downcase, arg[0])
25
+ end
26
+ end
27
+
28
+ def create_ext_from_array(ary)
29
+ raise ExtensionError, "unexpected array form" if ary.size > 3
30
+ create_ext(ary[0], ary[1], ary[2])
31
+ end
32
+
33
+ def create_ext_from_string(str) # "oid = critical, value"
34
+ oid, value = str.split(/=/, 2)
35
+ oid.strip!
36
+ value.strip!
37
+ create_ext(oid, value)
38
+ end
39
+
40
+ def create_ext_from_hash(hash)
41
+ create_ext(hash["oid"], hash["value"], hash["critical"])
42
+ end
43
+ end
44
+
45
+ class Extension
46
+ def to_s # "oid = critical, value"
47
+ str = self.oid
48
+ str << " = "
49
+ str << "critical, " if self.critical?
50
+ str << self.value.gsub(/\n/, ", ")
51
+ end
52
+
53
+ def to_h # {"oid"=>sn|ln, "value"=>value, "critical"=>true|false}
54
+ {"oid"=>self.oid,"value"=>self.value,"critical"=>self.critical?}
55
+ end
56
+
57
+ def to_a
58
+ [ self.oid, self.value, self.critical? ]
59
+ end
60
+ end
61
+
62
+ class Name
63
+ module RFC2253DN
64
+ Special = ',=+<>#;'
65
+ HexChar = /[0-9a-fA-F]/
66
+ HexPair = /#{HexChar}#{HexChar}/
67
+ HexString = /#{HexPair}+/
68
+ Pair = /\\(?:[#{Special}]|\\|"|#{HexPair})/
69
+ StringChar = /[^#{Special}\\"]/
70
+ QuoteChar = /[^\\"]/
71
+ AttributeType = /[a-zA-Z][0-9a-zA-Z]*|[0-9]+(?:\.[0-9]+)*/
72
+ AttributeValue = /
73
+ (?!["#])((?:#{StringChar}|#{Pair})*)|
74
+ \#(#{HexString})|
75
+ "((?:#{QuoteChar}|#{Pair})*)"
76
+ /x
77
+ TypeAndValue = /\A(#{AttributeType})=#{AttributeValue}/
78
+
79
+ module_function
80
+
81
+ def expand_pair(str)
82
+ return nil unless str
83
+ return str.gsub(Pair){
84
+ pair = $&
85
+ case pair.size
86
+ when 2 then pair[1,1]
87
+ when 3 then Integer("0x#{pair[1,2]}").chr
88
+ else raise OpenSSL::X509::NameError, "invalid pair: #{str}"
89
+ end
90
+ }
91
+ end
92
+
93
+ def expand_hexstring(str)
94
+ return nil unless str
95
+ der = str.gsub(HexPair){$&.to_i(16).chr }
96
+ a1 = OpenSSL::ASN1.decode(der)
97
+ return a1.value, a1.tag
98
+ end
99
+
100
+ def expand_value(str1, str2, str3)
101
+ value = expand_pair(str1)
102
+ value, tag = expand_hexstring(str2) unless value
103
+ value = expand_pair(str3) unless value
104
+ return value, tag
105
+ end
106
+
107
+ def scan(dn)
108
+ str = dn
109
+ ary = []
110
+ while true
111
+ if md = TypeAndValue.match(str)
112
+ matched = md.to_s
113
+ remain = md.post_match
114
+ type = md[1]
115
+ value, tag = expand_value(md[2], md[3], md[4]) rescue nil
116
+ if value
117
+ type_and_value = [type, value]
118
+ type_and_value.push(tag) if tag
119
+ ary.unshift(type_and_value)
120
+ if remain.length > 2 && remain[0] == ?,
121
+ str = remain[1..-1]
122
+ next
123
+ elsif remain.length > 2 && remain[0] == ?+
124
+ raise OpenSSL::X509::NameError,
125
+ "multi-valued RDN is not supported: #{dn}"
126
+ elsif remain.empty?
127
+ break
128
+ end
129
+ end
130
+ end
131
+ msg_dn = dn[0, dn.length - str.length] + " =>" + str
132
+ raise OpenSSL::X509::NameError, "malformed RDN: #{msg_dn}"
133
+ end
134
+ return ary
135
+ end
136
+ end
137
+
138
+ class <<self
139
+ def parse_rfc2253(str, template=OBJECT_TYPE_TEMPLATE)
140
+ ary = OpenSSL::X509::Name::RFC2253DN.scan(str)
141
+ self.new(ary, template)
142
+ end
143
+
144
+ def parse_openssl(str, template=OBJECT_TYPE_TEMPLATE)
145
+ ary = str.scan(/\s*([^\/,]+)\s*/).collect{|i| i[0].split("=", 2) }
146
+ self.new(ary, template)
147
+ end
148
+
149
+ alias parse parse_openssl
150
+ end
151
+ end
152
+ end
153
+ end
@@ -0,0 +1 @@
1
+ require 'openssl'
@@ -0,0 +1,23 @@
1
+ =begin
2
+ = $RCSfile$ -- Loader for all OpenSSL C-space and Ruby-space definitions
3
+
4
+ = Info
5
+ 'OpenSSL for Ruby 2' project
6
+ Copyright (C) 2002 Michal Rokos <m.rokos@sh.cvut.cz>
7
+ All rights reserved.
8
+
9
+ = Licence
10
+ This program is licenced under the same licence as Ruby.
11
+ (See the file 'LICENCE'.)
12
+
13
+ = Version
14
+ $Id$
15
+ =end
16
+
17
+ require 'openssl/bn'
18
+ require 'openssl/cipher'
19
+ require 'openssl/config'
20
+ require 'openssl/digest'
21
+ require 'openssl/ssl-internal'
22
+ require 'openssl/x509-internal'
23
+ require 'krypt/ossl'
@@ -0,0 +1,35 @@
1
+ #--
2
+ #
3
+ # $RCSfile$
4
+ #
5
+ # = Ruby-space definitions that completes C-space funcs for BN
6
+ #
7
+ # = Info
8
+ # 'OpenSSL for Ruby 2' project
9
+ # Copyright (C) 2002 Michal Rokos <m.rokos@sh.cvut.cz>
10
+ # All rights reserved.
11
+ #
12
+ # = Licence
13
+ # This program is licenced under the same licence as Ruby.
14
+ # (See the file 'LICENCE'.)
15
+ #
16
+ # = Version
17
+ # $Id$
18
+ #
19
+ #++
20
+
21
+ module OpenSSL
22
+ class BN
23
+ include Comparable
24
+ end # BN
25
+ end # OpenSSL
26
+
27
+ ##
28
+ # Add double dispatch to Integer
29
+ #
30
+ class Integer
31
+ def to_bn
32
+ OpenSSL::BN::new(self.to_s(16), 16)
33
+ end
34
+ end # Integer
35
+
@@ -0,0 +1,449 @@
1
+ =begin
2
+ = $RCSfile$ -- Buffering mix-in module.
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 licenced under the same licence as Ruby.
11
+ (See the file 'LICENCE'.)
12
+
13
+ = Version
14
+ $Id$
15
+ =end
16
+
17
+ ##
18
+ # OpenSSL IO buffering mix-in module.
19
+ #
20
+ # This module allows an OpenSSL::SSL::SSLSocket to behave like an IO.
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
+ def initialize(*args)
38
+ @eof = false
39
+ @rbuffer = ""
40
+ @sync = @io.sync
41
+ end
42
+
43
+ #
44
+ # for reading.
45
+ #
46
+ private
47
+
48
+ ##
49
+ # Fills the buffer from the underlying SSLSocket
50
+
51
+ def fill_rbuff
52
+ begin
53
+ @rbuffer << self.sysread(BLOCK_SIZE)
54
+ rescue Errno::EAGAIN
55
+ retry
56
+ rescue EOFError
57
+ @eof = true
58
+ end
59
+ end
60
+
61
+ ##
62
+ # Consumes +size+ bytes from the buffer
63
+
64
+ def consume_rbuff(size=nil)
65
+ if @rbuffer.empty?
66
+ nil
67
+ else
68
+ size = @rbuffer.size unless size
69
+ ret = @rbuffer[0, size]
70
+ @rbuffer[0, size] = ""
71
+ ret
72
+ end
73
+ end
74
+
75
+ public
76
+
77
+ ##
78
+ # Reads +size+ bytes from the stream. If +buf+ is provided it must
79
+ # reference a string which will receive the data.
80
+ #
81
+ # See IO#read for full details.
82
+
83
+ def read(size=nil, buf=nil)
84
+ if size == 0
85
+ if buf
86
+ buf.clear
87
+ return buf
88
+ else
89
+ return ""
90
+ end
91
+ end
92
+ until @eof
93
+ break if size && size <= @rbuffer.size
94
+ fill_rbuff
95
+ end
96
+ ret = consume_rbuff(size) || ""
97
+ if buf
98
+ buf.replace(ret)
99
+ ret = buf
100
+ end
101
+ (size && ret.empty?) ? nil : ret
102
+ end
103
+
104
+ ##
105
+ # Reads at most +maxlen+ bytes from the stream. If +buf+ is provided it
106
+ # must reference a string which will receive the data.
107
+ #
108
+ # See IO#readpartial for full details.
109
+
110
+ def readpartial(maxlen, buf=nil)
111
+ if maxlen == 0
112
+ if buf
113
+ buf.clear
114
+ return buf
115
+ else
116
+ return ""
117
+ end
118
+ end
119
+ if @rbuffer.empty?
120
+ begin
121
+ return sysread(maxlen, buf)
122
+ rescue Errno::EAGAIN
123
+ retry
124
+ end
125
+ end
126
+ ret = consume_rbuff(maxlen)
127
+ if buf
128
+ buf.replace(ret)
129
+ ret = buf
130
+ end
131
+ raise EOFError if ret.empty?
132
+ ret
133
+ end
134
+
135
+ ##
136
+ # Reads at most +maxlen+ bytes in the non-blocking manner.
137
+ #
138
+ # When no data can be read without blocking it raises
139
+ # OpenSSL::SSL::SSLError extended by IO::WaitReadable or IO::WaitWritable.
140
+ #
141
+ # IO::WaitReadable means SSL needs to read internally so read_nonblock
142
+ # should be called again when the underlying IO is readable.
143
+ #
144
+ # IO::WaitWritable means SSL needs to write internally so read_nonblock
145
+ # should be called again after the underlying IO is writable.
146
+ #
147
+ # OpenSSL::Buffering#read_nonblock needs two rescue clause as follows:
148
+ #
149
+ # # emulates blocking read (readpartial).
150
+ # begin
151
+ # result = ssl.read_nonblock(maxlen)
152
+ # rescue IO::WaitReadable
153
+ # IO.select([io])
154
+ # retry
155
+ # rescue IO::WaitWritable
156
+ # IO.select(nil, [io])
157
+ # retry
158
+ # end
159
+ #
160
+ # Note that one reason that read_nonblock writes to the underlying IO is
161
+ # when the peer requests a new TLS/SSL handshake. See openssl the FAQ for
162
+ # more details. http://www.openssl.org/support/faq.html
163
+
164
+ def read_nonblock(maxlen, buf=nil)
165
+ if maxlen == 0
166
+ if buf
167
+ buf.clear
168
+ return buf
169
+ else
170
+ return ""
171
+ end
172
+ end
173
+ if @rbuffer.empty?
174
+ return sysread_nonblock(maxlen, buf)
175
+ end
176
+ ret = consume_rbuff(maxlen)
177
+ if buf
178
+ buf.replace(ret)
179
+ ret = buf
180
+ end
181
+ raise EOFError if ret.empty?
182
+ ret
183
+ end
184
+
185
+ ##
186
+ # Reads the next "line+ from the stream. Lines are separated by +eol+. If
187
+ # +limit+ is provided the result will not be longer than the given number of
188
+ # bytes.
189
+ #
190
+ # +eol+ may be a String or Regexp.
191
+ #
192
+ # Unlike IO#gets the line read will not be assigned to +$_+.
193
+ #
194
+ # Unlike IO#gets the separator must be provided if a limit is provided.
195
+
196
+ def gets(eol=$/, limit=nil)
197
+ idx = @rbuffer.index(eol)
198
+ until @eof
199
+ break if idx
200
+ fill_rbuff
201
+ idx = @rbuffer.index(eol)
202
+ end
203
+ if eol.is_a?(Regexp)
204
+ size = idx ? idx+$&.size : nil
205
+ else
206
+ size = idx ? idx+eol.size : nil
207
+ end
208
+ if limit and limit >= 0
209
+ size = [size, limit].min
210
+ end
211
+ consume_rbuff(size)
212
+ end
213
+
214
+ ##
215
+ # Executes the block for every line in the stream where lines are separated
216
+ # by +eol+.
217
+ #
218
+ # See also #gets
219
+
220
+ def each(eol=$/)
221
+ while line = self.gets(eol)
222
+ yield line
223
+ end
224
+ end
225
+ alias each_line each
226
+
227
+ ##
228
+ # Reads lines from the stream which are separated by +eol+.
229
+ #
230
+ # See also #gets
231
+
232
+ def readlines(eol=$/)
233
+ ary = []
234
+ while line = self.gets(eol)
235
+ ary << line
236
+ end
237
+ ary
238
+ end
239
+
240
+ ##
241
+ # Reads a line from the stream which is separated by +eol+.
242
+ #
243
+ # Raises EOFError if at end of file.
244
+
245
+ def readline(eol=$/)
246
+ raise EOFError if eof?
247
+ gets(eol)
248
+ end
249
+
250
+ ##
251
+ # Reads one character from the stream. Returns nil if called at end of
252
+ # file.
253
+
254
+ def getc
255
+ read(1)
256
+ end
257
+
258
+ ##
259
+ # Calls the given block once for each byte in the stream.
260
+
261
+ def each_byte # :yields: byte
262
+ while c = getc
263
+ yield(c.ord)
264
+ end
265
+ end
266
+
267
+ ##
268
+ # Reads a one-character string from the stream. Raises an EOFError at end
269
+ # of file.
270
+
271
+ def readchar
272
+ raise EOFError if eof?
273
+ getc
274
+ end
275
+
276
+ ##
277
+ # Pushes character +c+ back onto the stream such that a subsequent buffered
278
+ # character read will return it.
279
+ #
280
+ # Unlike IO#getc multiple bytes may be pushed back onto the stream.
281
+ #
282
+ # Has no effect on unbuffered reads (such as #sysread).
283
+
284
+ def ungetc(c)
285
+ @rbuffer[0,0] = c.chr
286
+ end
287
+
288
+ ##
289
+ # Returns true if the stream is at file which means there is no more data to
290
+ # be read.
291
+
292
+ def eof?
293
+ fill_rbuff if !@eof && @rbuffer.empty?
294
+ @eof && @rbuffer.empty?
295
+ end
296
+ alias eof eof?
297
+
298
+ #
299
+ # for writing.
300
+ #
301
+ private
302
+
303
+ ##
304
+ # Writes +s+ to the buffer. When the buffer is full or #sync is true the
305
+ # buffer is flushed to the underlying socket.
306
+
307
+ def do_write(s)
308
+ @wbuffer = "" unless defined? @wbuffer
309
+ @wbuffer << s
310
+ @wbuffer.force_encoding(Encoding::BINARY)
311
+ @sync ||= false
312
+ if @sync or @wbuffer.size > BLOCK_SIZE or idx = @wbuffer.rindex($/)
313
+ remain = idx ? idx + $/.size : @wbuffer.length
314
+ nwritten = 0
315
+ while remain > 0
316
+ str = @wbuffer[nwritten,remain]
317
+ begin
318
+ nwrote = syswrite(str)
319
+ rescue Errno::EAGAIN
320
+ retry
321
+ end
322
+ remain -= nwrote
323
+ nwritten += nwrote
324
+ end
325
+ @wbuffer[0,nwritten] = ""
326
+ end
327
+ end
328
+
329
+ public
330
+
331
+ ##
332
+ # Writes +s+ to the stream. If the argument is not a string it will be
333
+ # converted using String#to_s. Returns the number of bytes written.
334
+
335
+ def write(s)
336
+ do_write(s)
337
+ s.bytesize
338
+ end
339
+
340
+ ##
341
+ # Writes +str+ in the non-blocking manner.
342
+ #
343
+ # If there is buffered data, it is flushed first. This may block.
344
+ #
345
+ # write_nonblock returns number of bytes written to the SSL connection.
346
+ #
347
+ # When no data can be written without blocking it raises
348
+ # OpenSSL::SSL::SSLError extended by IO::WaitReadable or IO::WaitWritable.
349
+ #
350
+ # IO::WaitReadable means SSL needs to read internally so write_nonblock
351
+ # should be called again after the underlying IO is readable.
352
+ #
353
+ # IO::WaitWritable means SSL needs to write internally so write_nonblock
354
+ # should be called again after underlying IO is writable.
355
+ #
356
+ # So OpenSSL::Buffering#write_nonblock needs two rescue clause as follows.
357
+ #
358
+ # # emulates blocking write.
359
+ # begin
360
+ # result = ssl.write_nonblock(str)
361
+ # rescue IO::WaitReadable
362
+ # IO.select([io])
363
+ # retry
364
+ # rescue IO::WaitWritable
365
+ # IO.select(nil, [io])
366
+ # retry
367
+ # end
368
+ #
369
+ # Note that one reason that write_nonblock reads from the underlying IO
370
+ # is when the peer requests a new TLS/SSL handshake. See the openssl FAQ
371
+ # for more details. http://www.openssl.org/support/faq.html
372
+
373
+ def write_nonblock(s)
374
+ flush
375
+ syswrite_nonblock(s)
376
+ end
377
+
378
+ ##
379
+ # Writes +s+ to the stream. +s+ will be converted to a String using
380
+ # String#to_s.
381
+
382
+ def << (s)
383
+ do_write(s)
384
+ self
385
+ end
386
+
387
+ ##
388
+ # Writes +args+ to the stream along with a record separator.
389
+ #
390
+ # See IO#puts for full details.
391
+
392
+ def puts(*args)
393
+ s = ""
394
+ if args.empty?
395
+ s << "\n"
396
+ end
397
+ args.each{|arg|
398
+ s << arg.to_s
399
+ if $/ && /\n\z/ !~ s
400
+ s << "\n"
401
+ end
402
+ }
403
+ do_write(s)
404
+ nil
405
+ end
406
+
407
+ ##
408
+ # Writes +args+ to the stream.
409
+ #
410
+ # See IO#print for full details.
411
+
412
+ def print(*args)
413
+ s = ""
414
+ args.each{ |arg| s << arg.to_s }
415
+ do_write(s)
416
+ nil
417
+ end
418
+
419
+ ##
420
+ # Formats and writes to the stream converting parameters under control of
421
+ # the format string.
422
+ #
423
+ # See Kernel#sprintf for format string details.
424
+
425
+ def printf(s, *args)
426
+ do_write(s % args)
427
+ nil
428
+ end
429
+
430
+ ##
431
+ # Flushes buffered data to the SSLSocket.
432
+
433
+ def flush
434
+ osync = @sync
435
+ @sync = true
436
+ do_write ""
437
+ return self
438
+ ensure
439
+ @sync = osync
440
+ end
441
+
442
+ ##
443
+ # Closes the SSLSocket and flushes any unwritten data.
444
+
445
+ def close
446
+ flush rescue nil
447
+ sysclose
448
+ end
449
+ end