webrick 1.3.1

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of webrick might be problematic. Click here for more details.

Files changed (63) hide show
  1. data/README.txt +21 -0
  2. data/lib/webrick.rb +227 -0
  3. data/lib/webrick/accesslog.rb +151 -0
  4. data/lib/webrick/cgi.rb +260 -0
  5. data/lib/webrick/compat.rb +35 -0
  6. data/lib/webrick/config.rb +121 -0
  7. data/lib/webrick/cookie.rb +110 -0
  8. data/lib/webrick/htmlutils.rb +28 -0
  9. data/lib/webrick/httpauth.rb +95 -0
  10. data/lib/webrick/httpauth/authenticator.rb +112 -0
  11. data/lib/webrick/httpauth/basicauth.rb +108 -0
  12. data/lib/webrick/httpauth/digestauth.rb +392 -0
  13. data/lib/webrick/httpauth/htdigest.rb +128 -0
  14. data/lib/webrick/httpauth/htgroup.rb +93 -0
  15. data/lib/webrick/httpauth/htpasswd.rb +121 -0
  16. data/lib/webrick/httpauth/userdb.rb +52 -0
  17. data/lib/webrick/httpproxy.rb +305 -0
  18. data/lib/webrick/httprequest.rb +461 -0
  19. data/lib/webrick/httpresponse.rb +399 -0
  20. data/lib/webrick/https.rb +64 -0
  21. data/lib/webrick/httpserver.rb +264 -0
  22. data/lib/webrick/httpservlet.rb +22 -0
  23. data/lib/webrick/httpservlet/abstract.rb +153 -0
  24. data/lib/webrick/httpservlet/cgi_runner.rb +46 -0
  25. data/lib/webrick/httpservlet/cgihandler.rb +108 -0
  26. data/lib/webrick/httpservlet/erbhandler.rb +87 -0
  27. data/lib/webrick/httpservlet/filehandler.rb +470 -0
  28. data/lib/webrick/httpservlet/prochandler.rb +33 -0
  29. data/lib/webrick/httpstatus.rb +184 -0
  30. data/lib/webrick/httputils.rb +394 -0
  31. data/lib/webrick/httpversion.rb +49 -0
  32. data/lib/webrick/log.rb +136 -0
  33. data/lib/webrick/server.rb +218 -0
  34. data/lib/webrick/ssl.rb +127 -0
  35. data/lib/webrick/utils.rb +241 -0
  36. data/lib/webrick/version.rb +13 -0
  37. data/sample/webrick/demo-app.rb +66 -0
  38. data/sample/webrick/demo-multipart.cgi +12 -0
  39. data/sample/webrick/demo-servlet.rb +6 -0
  40. data/sample/webrick/demo-urlencoded.cgi +12 -0
  41. data/sample/webrick/hello.cgi +11 -0
  42. data/sample/webrick/hello.rb +8 -0
  43. data/sample/webrick/httpd.rb +23 -0
  44. data/sample/webrick/httpproxy.rb +25 -0
  45. data/sample/webrick/httpsd.rb +33 -0
  46. data/test/openssl/utils.rb +313 -0
  47. data/test/ruby/envutil.rb +208 -0
  48. data/test/webrick/test_cgi.rb +134 -0
  49. data/test/webrick/test_cookie.rb +131 -0
  50. data/test/webrick/test_filehandler.rb +285 -0
  51. data/test/webrick/test_httpauth.rb +167 -0
  52. data/test/webrick/test_httpproxy.rb +282 -0
  53. data/test/webrick/test_httprequest.rb +411 -0
  54. data/test/webrick/test_httpresponse.rb +49 -0
  55. data/test/webrick/test_httpserver.rb +305 -0
  56. data/test/webrick/test_httputils.rb +96 -0
  57. data/test/webrick/test_httpversion.rb +40 -0
  58. data/test/webrick/test_server.rb +67 -0
  59. data/test/webrick/test_utils.rb +64 -0
  60. data/test/webrick/utils.rb +58 -0
  61. data/test/webrick/webrick.cgi +36 -0
  62. data/test/webrick/webrick_long_filename.cgi +36 -0
  63. metadata +106 -0
@@ -0,0 +1,313 @@
1
+ begin
2
+ require "openssl"
3
+ rescue LoadError
4
+ end
5
+ require "test/unit"
6
+ require "digest/md5"
7
+ require 'tempfile'
8
+ require "rbconfig"
9
+ require "socket"
10
+ require_relative '../ruby/envutil'
11
+
12
+ module OpenSSL::TestUtils
13
+ TEST_KEY_RSA1024 = OpenSSL::PKey::RSA.new <<-_end_of_pem_
14
+ -----BEGIN RSA PRIVATE KEY-----
15
+ MIICXgIBAAKBgQDLwsSw1ECnPtT+PkOgHhcGA71nwC2/nL85VBGnRqDxOqjVh7Cx
16
+ aKPERYHsk4BPCkE3brtThPWc9kjHEQQ7uf9Y1rbCz0layNqHyywQEVLFmp1cpIt/
17
+ Q3geLv8ZD9pihowKJDyMDiN6ArYUmZczvW4976MU3+l54E6lF/JfFEU5hwIDAQAB
18
+ AoGBAKSl/MQarye1yOysqX6P8fDFQt68VvtXkNmlSiKOGuzyho0M+UVSFcs6k1L0
19
+ maDE25AMZUiGzuWHyaU55d7RXDgeskDMakD1v6ZejYtxJkSXbETOTLDwUWTn618T
20
+ gnb17tU1jktUtU67xK/08i/XodlgnQhs6VoHTuCh3Hu77O6RAkEA7+gxqBuZR572
21
+ 74/akiW/SuXm0SXPEviyO1MuSRwtI87B02D0qgV8D1UHRm4AhMnJ8MCs1809kMQE
22
+ JiQUCrp9mQJBANlt2ngBO14us6NnhuAseFDTBzCHXwUUu1YKHpMMmxpnGqaldGgX
23
+ sOZB3lgJsT9VlGf3YGYdkLTNVbogQKlKpB8CQQDiSwkb4vyQfDe8/NpU5Not0fII
24
+ 8jsDUCb+opWUTMmfbxWRR3FBNu8wnym/m19N4fFj8LqYzHX4KY0oVPu6qvJxAkEA
25
+ wa5snNekFcqONLIE4G5cosrIrb74sqL8GbGb+KuTAprzj5z1K8Bm0UW9lTjVDjDi
26
+ qRYgZfZSL+x1P/54+xTFSwJAY1FxA/N3QPCXCjPh5YqFxAMQs2VVYTfg+t0MEcJD
27
+ dPMQD5JX6g5HKnHFg2mZtoXQrWmJSn7p8GJK8yNTopEErA==
28
+ -----END RSA PRIVATE KEY-----
29
+ _end_of_pem_
30
+
31
+ TEST_KEY_RSA2048 = OpenSSL::PKey::RSA.new <<-_end_of_pem_
32
+ -----BEGIN RSA PRIVATE KEY-----
33
+ MIIEpAIBAAKCAQEAuV9ht9J7k4NBs38jOXvvTKY9gW8nLICSno5EETR1cuF7i4pN
34
+ s9I1QJGAFAX0BEO4KbzXmuOvfCpD3CU+Slp1enenfzq/t/e/1IRW0wkJUJUFQign
35
+ 4CtrkJL+P07yx18UjyPlBXb81ApEmAB5mrJVSrWmqbjs07JbuS4QQGGXLc+Su96D
36
+ kYKmSNVjBiLxVVSpyZfAY3hD37d60uG+X8xdW5v68JkRFIhdGlb6JL8fllf/A/bl
37
+ NwdJOhVr9mESHhwGjwfSeTDPfd8ZLE027E5lyAVX9KZYcU00mOX+fdxOSnGqS/8J
38
+ DRh0EPHDL15RcJjV2J6vZjPb0rOYGDoMcH+94wIDAQABAoIBAAzsamqfYQAqwXTb
39
+ I0CJtGg6msUgU7HVkOM+9d3hM2L791oGHV6xBAdpXW2H8LgvZHJ8eOeSghR8+dgq
40
+ PIqAffo4x1Oma+FOg3A0fb0evyiACyrOk+EcBdbBeLo/LcvahBtqnDfiUMQTpy6V
41
+ seSoFCwuN91TSCeGIsDpRjbG1vxZgtx+uI+oH5+ytqJOmfCksRDCkMglGkzyfcl0
42
+ Xc5CUhIJ0my53xijEUQl19rtWdMnNnnkdbG8PT3LZlOta5Do86BElzUYka0C6dUc
43
+ VsBDQ0Nup0P6rEQgy7tephHoRlUGTYamsajGJaAo1F3IQVIrRSuagi7+YpSpCqsW
44
+ wORqorkCgYEA7RdX6MDVrbw7LePnhyuaqTiMK+055/R1TqhB1JvvxJ1CXk2rDL6G
45
+ 0TLHQ7oGofd5LYiemg4ZVtWdJe43BPZlVgT6lvL/iGo8JnrncB9Da6L7nrq/+Rvj
46
+ XGjf1qODCK+LmreZWEsaLPURIoR/Ewwxb9J2zd0CaMjeTwafJo1CZvcCgYEAyCgb
47
+ aqoWvUecX8VvARfuA593Lsi50t4MEArnOXXcd1RnXoZWhbx5rgO8/ATKfXr0BK/n
48
+ h2GF9PfKzHFm/4V6e82OL7gu/kLy2u9bXN74vOvWFL5NOrOKPM7Kg+9I131kNYOw
49
+ Ivnr/VtHE5s0dY7JChYWE1F3vArrOw3T00a4CXUCgYEA0SqY+dS2LvIzW4cHCe9k
50
+ IQqsT0yYm5TFsUEr4sA3xcPfe4cV8sZb9k/QEGYb1+SWWZ+AHPV3UW5fl8kTbSNb
51
+ v4ng8i8rVVQ0ANbJO9e5CUrepein2MPL0AkOATR8M7t7dGGpvYV0cFk8ZrFx0oId
52
+ U0PgYDotF/iueBWlbsOM430CgYEAqYI95dFyPI5/AiSkY5queeb8+mQH62sdcCCr
53
+ vd/w/CZA/K5sbAo4SoTj8dLk4evU6HtIa0DOP63y071eaxvRpTNqLUOgmLh+D6gS
54
+ Cc7TfLuFrD+WDBatBd5jZ+SoHccVrLR/4L8jeodo5FPW05A+9gnKXEXsTxY4LOUC
55
+ 9bS4e1kCgYAqVXZh63JsMwoaxCYmQ66eJojKa47VNrOeIZDZvd2BPVf30glBOT41
56
+ gBoDG3WMPZoQj9pb7uMcrnvs4APj2FIhMU8U15LcPAj59cD6S6rWnAxO8NFK7HQG
57
+ 4Jxg3JNNf8ErQoCHb1B3oVdXJkmbJkARoDpBKmTCgKtP8ADYLmVPQw==
58
+ -----END RSA PRIVATE KEY-----
59
+ _end_of_pem_
60
+
61
+ TEST_KEY_DSA256 = OpenSSL::PKey::DSA.new <<-_end_of_pem_
62
+ -----BEGIN DSA PRIVATE KEY-----
63
+ MIH3AgEAAkEAhk2libbY2a8y2Pt21+YPYGZeW6wzaW2yfj5oiClXro9XMR7XWLkE
64
+ 9B7XxLNFCS2gmCCdMsMW1HulaHtLFQmB2wIVAM43JZrcgpu6ajZ01VkLc93gu/Ed
65
+ AkAOhujZrrKV5CzBKutKLb0GVyVWmdC7InoNSMZEeGU72rT96IjM59YzoqmD0pGM
66
+ 3I1o4cGqg1D1DfM1rQlnN1eSAkBq6xXfEDwJ1mLNxF6q8Zm/ugFYWR5xcX/3wFiT
67
+ b4+EjHP/DbNh9Vm5wcfnDBJ1zKvrMEf2xqngYdrV/3CiGJeKAhRvL57QvJZcQGvn
68
+ ISNX5cMzFHRW3Q==
69
+ -----END DSA PRIVATE KEY-----
70
+ _end_of_pem_
71
+
72
+ TEST_KEY_DSA512 = OpenSSL::PKey::DSA.new <<-_end_of_pem_
73
+ -----BEGIN DSA PRIVATE KEY-----
74
+ MIH4AgEAAkEA5lB4GvEwjrsMlGDqGsxrbqeFRh6o9OWt6FgTYiEEHaOYhkIxv0Ok
75
+ RZPDNwOG997mDjBnvDJ1i56OmS3MbTnovwIVAJgub/aDrSDB4DZGH7UyarcaGy6D
76
+ AkB9HdFw/3td8K4l1FZHv7TCZeJ3ZLb7dF3TWoGUP003RCqoji3/lHdKoVdTQNuR
77
+ S/m6DlCwhjRjiQ/lBRgCLCcaAkEAjN891JBjzpMj4bWgsACmMggFf57DS0Ti+5++
78
+ Q1VB8qkJN7rA7/2HrCR3gTsWNb1YhAsnFsoeRscC+LxXoXi9OAIUBG98h4tilg6S
79
+ 55jreJD3Se3slps=
80
+ -----END DSA PRIVATE KEY-----
81
+ _end_of_pem_
82
+
83
+ if defined?(OpenSSL::PKey::EC)
84
+
85
+ TEST_KEY_EC_P256V1 = OpenSSL::PKey::EC.new <<-_end_of_pem_
86
+ -----BEGIN EC PRIVATE KEY-----
87
+ MHcCAQEEIID49FDqcf1O1eO8saTgG70UbXQw9Fqwseliit2aWhH1oAoGCCqGSM49
88
+ AwEHoUQDQgAEFglk2c+oVUIKQ64eZG9bhLNPWB7lSZ/ArK41eGy5wAzU/0G51Xtt
89
+ CeBUl+MahZtn9fO1JKdF4qJmS39dXnpENg==
90
+ -----END EC PRIVATE KEY-----
91
+ _end_of_pem_
92
+
93
+ end
94
+
95
+ TEST_KEY_DH512 = OpenSSL::PKey::DH.new <<-_end_of_pem_
96
+ -----BEGIN DH PARAMETERS-----
97
+ MEYCQQDmWXGPqk76sKw/edIOdhAQD4XzjJ+AR/PTk2qzaGs+u4oND2yU5D2NN4wr
98
+ aPgwHyJBiK1/ebK3tYcrSKrOoRyrAgEC
99
+ -----END DH PARAMETERS-----
100
+ _end_of_pem_
101
+
102
+ module_function
103
+
104
+ def issue_cert(dn, key, serial, not_before, not_after, extensions,
105
+ issuer, issuer_key, digest)
106
+ cert = OpenSSL::X509::Certificate.new
107
+ issuer = cert unless issuer
108
+ issuer_key = key unless issuer_key
109
+ cert.version = 2
110
+ cert.serial = serial
111
+ cert.subject = dn
112
+ cert.issuer = issuer.subject
113
+ cert.public_key = key.public_key
114
+ cert.not_before = not_before
115
+ cert.not_after = not_after
116
+ ef = OpenSSL::X509::ExtensionFactory.new
117
+ ef.subject_certificate = cert
118
+ ef.issuer_certificate = issuer
119
+ extensions.each{|oid, value, critical|
120
+ cert.add_extension(ef.create_extension(oid, value, critical))
121
+ }
122
+ cert.sign(issuer_key, digest)
123
+ cert
124
+ end
125
+
126
+ def issue_crl(revoke_info, serial, lastup, nextup, extensions,
127
+ issuer, issuer_key, digest)
128
+ crl = OpenSSL::X509::CRL.new
129
+ crl.issuer = issuer.subject
130
+ crl.version = 1
131
+ crl.last_update = lastup
132
+ crl.next_update = nextup
133
+ revoke_info.each{|rserial, time, reason_code|
134
+ revoked = OpenSSL::X509::Revoked.new
135
+ revoked.serial = rserial
136
+ revoked.time = time
137
+ enum = OpenSSL::ASN1::Enumerated(reason_code)
138
+ ext = OpenSSL::X509::Extension.new("CRLReason", enum)
139
+ revoked.add_extension(ext)
140
+ crl.add_revoked(revoked)
141
+ }
142
+ ef = OpenSSL::X509::ExtensionFactory.new
143
+ ef.issuer_certificate = issuer
144
+ ef.crl = crl
145
+ crlnum = OpenSSL::ASN1::Integer(serial)
146
+ crl.add_extension(OpenSSL::X509::Extension.new("crlNumber", crlnum))
147
+ extensions.each{|oid, value, critical|
148
+ crl.add_extension(ef.create_extension(oid, value, critical))
149
+ }
150
+ crl.sign(issuer_key, digest)
151
+ crl
152
+ end
153
+
154
+ def get_subject_key_id(cert)
155
+ asn1_cert = OpenSSL::ASN1.decode(cert)
156
+ tbscert = asn1_cert.value[0]
157
+ pkinfo = tbscert.value[6]
158
+ publickey = pkinfo.value[1]
159
+ pkvalue = publickey.value
160
+ OpenSSL::Digest::SHA1.hexdigest(pkvalue).scan(/../).join(":").upcase
161
+ end
162
+
163
+ def silent
164
+ begin
165
+ back, $VERBOSE = $VERBOSE, nil
166
+ yield
167
+ ensure
168
+ $VERBOSE = back
169
+ end
170
+ end
171
+
172
+ class OpenSSL::SSLTestCase < Test::Unit::TestCase
173
+ RUBY = EnvUtil.rubybin
174
+ SSL_SERVER = File.join(File.dirname(__FILE__), "ssl_server.rb")
175
+ PORT = 20443
176
+ ITERATIONS = ($0 == __FILE__) ? 100 : 10
177
+
178
+ def setup
179
+ @ca_key = OpenSSL::TestUtils::TEST_KEY_RSA2048
180
+ @svr_key = OpenSSL::TestUtils::TEST_KEY_RSA1024
181
+ @cli_key = OpenSSL::TestUtils::TEST_KEY_DSA256
182
+ @ca = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=CA")
183
+ @svr = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=localhost")
184
+ @cli = OpenSSL::X509::Name.parse("/DC=org/DC=ruby-lang/CN=localhost")
185
+ now = Time.at(Time.now.to_i)
186
+ ca_exts = [
187
+ ["basicConstraints","CA:TRUE",true],
188
+ ["keyUsage","cRLSign,keyCertSign",true],
189
+ ]
190
+ ee_exts = [
191
+ ["keyUsage","keyEncipherment,digitalSignature",true],
192
+ ]
193
+ @ca_cert = issue_cert(@ca, @ca_key, 1, now, now+3600, ca_exts, nil, nil, OpenSSL::Digest::SHA1.new)
194
+ @svr_cert = issue_cert(@svr, @svr_key, 2, now, now+1800, ee_exts, @ca_cert, @ca_key, OpenSSL::Digest::SHA1.new)
195
+ @cli_cert = issue_cert(@cli, @cli_key, 3, now, now+1800, ee_exts, @ca_cert, @ca_key, OpenSSL::Digest::SHA1.new)
196
+ @server = nil
197
+ end
198
+
199
+ def teardown
200
+ end
201
+
202
+ def issue_cert(*arg)
203
+ OpenSSL::TestUtils.issue_cert(*arg)
204
+ end
205
+
206
+ def issue_crl(*arg)
207
+ OpenSSL::TestUtils.issue_crl(*arg)
208
+ end
209
+
210
+ def readwrite_loop(ctx, ssl)
211
+ while line = ssl.gets
212
+ if line =~ /^STARTTLS$/
213
+ ssl.accept
214
+ next
215
+ end
216
+ ssl.write(line)
217
+ end
218
+ rescue OpenSSL::SSL::SSLError
219
+ rescue IOError
220
+ ensure
221
+ ssl.close rescue nil
222
+ end
223
+
224
+ def server_loop(ctx, ssls, server_proc)
225
+ loop do
226
+ ssl = nil
227
+ begin
228
+ ssl = ssls.accept
229
+ rescue OpenSSL::SSL::SSLError
230
+ retry
231
+ end
232
+
233
+ Thread.start do
234
+ Thread.current.abort_on_exception = true
235
+ server_proc.call(ctx, ssl)
236
+ end
237
+ end
238
+ rescue Errno::EBADF, IOError, Errno::EINVAL, Errno::ECONNABORTED, Errno::ENOTSOCK
239
+ end
240
+
241
+ DHParam = OpenSSL::PKey::DH.new(128)
242
+ def start_server(port0, verify_mode, start_immediately, args = {}, &block)
243
+ ctx_proc = args[:ctx_proc]
244
+ server_proc = args[:server_proc]
245
+ server_proc ||= method(:readwrite_loop)
246
+
247
+ store = OpenSSL::X509::Store.new
248
+ store.add_cert(@ca_cert)
249
+ store.purpose = OpenSSL::X509::PURPOSE_SSL_CLIENT
250
+ ctx = OpenSSL::SSL::SSLContext.new
251
+ ctx.cert_store = store
252
+ #ctx.extra_chain_cert = [ ca_cert ]
253
+ ctx.cert = @svr_cert
254
+ ctx.key = @svr_key
255
+ ctx.tmp_dh_callback = proc { DHParam }
256
+ ctx.verify_mode = verify_mode
257
+ ctx_proc.call(ctx) if ctx_proc
258
+
259
+ Socket.do_not_reverse_lookup = true
260
+ tcps = nil
261
+ port = port0
262
+ begin
263
+ tcps = TCPServer.new("127.0.0.1", port)
264
+ rescue Errno::EADDRINUSE
265
+ port += 1
266
+ retry
267
+ end
268
+
269
+ ssls = OpenSSL::SSL::SSLServer.new(tcps, ctx)
270
+ ssls.start_immediately = start_immediately
271
+
272
+ begin
273
+ server = Thread.new do
274
+ Thread.current.abort_on_exception = true
275
+ server_loop(ctx, ssls, server_proc)
276
+ end
277
+
278
+ $stderr.printf("%s started: pid=%d port=%d\n", SSL_SERVER, $$, port) if $DEBUG
279
+
280
+ block.call(server, port.to_i)
281
+ ensure
282
+ begin
283
+ begin
284
+ tcps.shutdown
285
+ rescue Errno::ENOTCONN
286
+ # when `Errno::ENOTCONN: Socket is not connected' on some platforms,
287
+ # call #close instead of #shutdown.
288
+ tcps.close
289
+ tcps = nil
290
+ end if (tcps)
291
+ if (server)
292
+ server.join(5)
293
+ if server.alive?
294
+ server.kill
295
+ server.join
296
+ flunk("TCPServer was closed and SSLServer is still alive") unless $!
297
+ end
298
+ end
299
+ ensure
300
+ tcps.close if (tcps)
301
+ end
302
+ end
303
+ end
304
+
305
+ def starttls(ssl)
306
+ ssl.puts("STARTTLS")
307
+ sleep 1 # When this line is eliminated, process on Cygwin blocks
308
+ # forever at ssl.connect. But I don't know why it does.
309
+ ssl.connect
310
+ end
311
+ end
312
+
313
+ end if defined?(OpenSSL)
@@ -0,0 +1,208 @@
1
+ require "open3"
2
+ require "timeout"
3
+
4
+ module EnvUtil
5
+ def rubybin
6
+ unless ENV["RUBYOPT"]
7
+
8
+ end
9
+ if ruby = ENV["RUBY"]
10
+ return ruby
11
+ end
12
+ ruby = "ruby"
13
+ rubyexe = ruby+".exe"
14
+ 3.times do
15
+ if File.exist? ruby and File.executable? ruby and !File.directory? ruby
16
+ return File.expand_path(ruby)
17
+ end
18
+ if File.exist? rubyexe and File.executable? rubyexe
19
+ return File.expand_path(rubyexe)
20
+ end
21
+ ruby = File.join("..", ruby)
22
+ end
23
+ if defined?(RbConfig.ruby)
24
+ RbConfig.ruby
25
+ else
26
+ "ruby"
27
+ end
28
+ end
29
+ module_function :rubybin
30
+
31
+ LANG_ENVS = %w"LANG LC_ALL LC_CTYPE"
32
+
33
+ def invoke_ruby(args, stdin_data="", capture_stdout=false, capture_stderr=false, opt={})
34
+ in_c, in_p = IO.pipe
35
+ out_p, out_c = IO.pipe if capture_stdout
36
+ err_p, err_c = IO.pipe if capture_stderr && capture_stderr != :merge_to_stdout
37
+ opt = opt.dup
38
+ opt[:in] = in_c
39
+ opt[:out] = out_c if capture_stdout
40
+ opt[:err] = capture_stderr == :merge_to_stdout ? out_c : err_c if capture_stderr
41
+ if enc = opt.delete(:encoding)
42
+ out_p.set_encoding(enc) if out_p
43
+ err_p.set_encoding(enc) if err_p
44
+ end
45
+ timeout = opt.delete(:timeout) || 10
46
+ c = "C"
47
+ child_env = {}
48
+ LANG_ENVS.each {|lc| child_env[lc] = c}
49
+ if Array === args and Hash === args.first
50
+ child_env.update(args.shift)
51
+ end
52
+ args = [args] if args.kind_of?(String)
53
+ pid = spawn(child_env, EnvUtil.rubybin, *args, opt)
54
+ in_c.close
55
+ out_c.close if capture_stdout
56
+ err_c.close if capture_stderr && capture_stderr != :merge_to_stdout
57
+ if block_given?
58
+ return yield in_p, out_p, err_p
59
+ else
60
+ th_stdout = Thread.new { out_p.read } if capture_stdout
61
+ th_stderr = Thread.new { err_p.read } if capture_stderr && capture_stderr != :merge_to_stdout
62
+ in_p.write stdin_data.to_str
63
+ in_p.close
64
+ if (!th_stdout || th_stdout.join(timeout)) && (!th_stderr || th_stderr.join(timeout))
65
+ stdout = th_stdout.value if capture_stdout
66
+ stderr = th_stderr.value if capture_stderr && capture_stderr != :merge_to_stdout
67
+ else
68
+ raise Timeout::Error
69
+ end
70
+ out_p.close if capture_stdout
71
+ err_p.close if capture_stderr && capture_stderr != :merge_to_stdout
72
+ Process.wait pid
73
+ status = $?
74
+ return stdout, stderr, status
75
+ end
76
+ ensure
77
+ [in_c, in_p, out_c, out_p, err_c, err_p].each do |io|
78
+ io.close if io && !io.closed?
79
+ end
80
+ [th_stdout, th_stderr].each do |th|
81
+ (th.kill; th.join) if th
82
+ end
83
+ end
84
+ module_function :invoke_ruby
85
+
86
+ alias rubyexec invoke_ruby
87
+ class << self
88
+ alias rubyexec invoke_ruby
89
+ end
90
+
91
+ def verbose_warning
92
+ class << (stderr = "")
93
+ alias write <<
94
+ end
95
+ stderr, $stderr, verbose, $VERBOSE = $stderr, stderr, $VERBOSE, true
96
+ yield stderr
97
+ ensure
98
+ stderr, $stderr, $VERBOSE = $stderr, stderr, verbose
99
+ return stderr
100
+ end
101
+ module_function :verbose_warning
102
+
103
+ def suppress_warning
104
+ verbose, $VERBOSE = $VERBOSE, nil
105
+ yield
106
+ ensure
107
+ $VERBOSE = verbose
108
+ end
109
+ module_function :suppress_warning
110
+
111
+ def under_gc_stress
112
+ stress, GC.stress = GC.stress, true
113
+ yield
114
+ ensure
115
+ GC.stress = stress
116
+ end
117
+ module_function :under_gc_stress
118
+ end
119
+
120
+ module Test
121
+ module Unit
122
+ module Assertions
123
+ public
124
+ def assert_normal_exit(testsrc, message = '', opt = {})
125
+ if opt.include?(:child_env)
126
+ opt = opt.dup
127
+ child_env = [opt.delete(:child_env)] || []
128
+ else
129
+ child_env = []
130
+ end
131
+ out, _, status = EnvUtil.invoke_ruby(child_env + %W'-W0', testsrc, true, :merge_to_stdout, opt)
132
+ pid = status.pid
133
+ faildesc = proc do
134
+ signo = status.termsig
135
+ signame = Signal.list.invert[signo]
136
+ sigdesc = "signal #{signo}"
137
+ if signame
138
+ sigdesc = "SIG#{signame} (#{sigdesc})"
139
+ end
140
+ if status.coredump?
141
+ sigdesc << " (core dumped)"
142
+ end
143
+ full_message = ''
144
+ if !message.empty?
145
+ full_message << message << "\n"
146
+ end
147
+ full_message << "pid #{pid} killed by #{sigdesc}"
148
+ if !out.empty?
149
+ out << "\n" if /\n\z/ !~ out
150
+ full_message << "\n#{out.gsub(/^/, '| ')}"
151
+ end
152
+ full_message
153
+ end
154
+ assert !status.signaled?, faildesc
155
+ end
156
+
157
+ def assert_in_out_err(args, test_stdin = "", test_stdout = [], test_stderr = [], message = nil, opt={})
158
+ stdout, stderr, status = EnvUtil.invoke_ruby(args, test_stdin, true, true, opt)
159
+ if block_given?
160
+ yield(stdout.lines.map {|l| l.chomp }, stderr.lines.map {|l| l.chomp })
161
+ else
162
+ if test_stdout.is_a?(Regexp)
163
+ assert_match(test_stdout, stdout, message)
164
+ else
165
+ assert_equal(test_stdout, stdout.lines.map {|l| l.chomp }, message)
166
+ end
167
+ if test_stderr.is_a?(Regexp)
168
+ assert_match(test_stderr, stderr, message)
169
+ else
170
+ assert_equal(test_stderr, stderr.lines.map {|l| l.chomp }, message)
171
+ end
172
+ status
173
+ end
174
+ end
175
+
176
+ def assert_ruby_status(args, test_stdin="", message=nil, opt={})
177
+ _, _, status = EnvUtil.invoke_ruby(args, test_stdin, false, false, opt)
178
+ m = message ? "#{message} (#{status.inspect})" : "ruby exit status is not success: #{status.inspect}"
179
+ assert(status.success?, m)
180
+ end
181
+
182
+ def assert_warn(msg)
183
+ stderr = EnvUtil.verbose_warning { yield }
184
+ assert(msg === stderr, "warning message #{stderr.inspect} is expected to match #{msg.inspect}")
185
+ end
186
+
187
+ end
188
+ end
189
+ end
190
+
191
+ begin
192
+ require 'rbconfig'
193
+ rescue LoadError
194
+ else
195
+ module RbConfig
196
+ @ruby = EnvUtil.rubybin
197
+ class << self
198
+ undef ruby if method_defined?(:ruby)
199
+ attr_reader :ruby
200
+ end
201
+ dir = File.dirname(ruby)
202
+ name = File.basename(ruby, CONFIG['EXEEXT'])
203
+ CONFIG['bindir'] = dir
204
+ CONFIG['ruby_install_name'] = name
205
+ CONFIG['RUBY_INSTALL_NAME'] = name
206
+ Gem::ConfigMap[:bindir] = dir if defined?(Gem::ConfigMap)
207
+ end
208
+ end