httpclient 2.3.0.1 → 2.8.3

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 (41) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +85 -0
  3. data/bin/httpclient +18 -6
  4. data/bin/jsonclient +85 -0
  5. data/lib/http-access2.rb +1 -1
  6. data/lib/httpclient.rb +262 -88
  7. data/lib/httpclient/auth.rb +269 -244
  8. data/lib/httpclient/cacert.pem +3952 -0
  9. data/lib/httpclient/cacert1024.pem +3866 -0
  10. data/lib/httpclient/connection.rb +1 -1
  11. data/lib/httpclient/cookie.rb +161 -514
  12. data/lib/httpclient/http.rb +57 -21
  13. data/lib/httpclient/include_client.rb +2 -0
  14. data/lib/httpclient/jruby_ssl_socket.rb +588 -0
  15. data/lib/httpclient/session.rb +259 -317
  16. data/lib/httpclient/ssl_config.rb +141 -188
  17. data/lib/httpclient/ssl_socket.rb +150 -0
  18. data/lib/httpclient/timeout.rb +1 -1
  19. data/lib/httpclient/util.rb +62 -1
  20. data/lib/httpclient/version.rb +1 -1
  21. data/lib/httpclient/webagent-cookie.rb +459 -0
  22. data/lib/jsonclient.rb +63 -0
  23. data/lib/oauthclient.rb +2 -1
  24. data/sample/jsonclient.rb +67 -0
  25. data/sample/oauth_twitter.rb +4 -4
  26. data/test/{ca-chain.cert → ca-chain.pem} +0 -0
  27. data/test/client-pass.key +18 -0
  28. data/test/helper.rb +10 -8
  29. data/test/jruby_ssl_socket/test_pemutils.rb +32 -0
  30. data/test/test_auth.rb +175 -4
  31. data/test/test_cookie.rb +147 -243
  32. data/test/test_http-access2.rb +17 -16
  33. data/test/test_httpclient.rb +458 -77
  34. data/test/test_jsonclient.rb +80 -0
  35. data/test/test_ssl.rb +341 -17
  36. data/test/test_webagent-cookie.rb +465 -0
  37. metadata +57 -55
  38. data/README.txt +0 -721
  39. data/lib/httpclient/cacert.p7s +0 -1858
  40. data/lib/httpclient/cacert_sha1.p7s +0 -1858
  41. data/sample/oauth_salesforce_10.rb +0 -63
@@ -0,0 +1,80 @@
1
+ # -*- encoding: utf-8 -*-
2
+ require File.expand_path('helper', File.dirname(__FILE__))
3
+ require 'jsonclient'
4
+
5
+
6
+ class TestJSONClient < Test::Unit::TestCase
7
+ include Helper
8
+
9
+ def setup
10
+ super
11
+ setup_server
12
+ @client = JSONClient.new
13
+ end
14
+
15
+ def teardown
16
+ super
17
+ end
18
+
19
+ def test_post
20
+ res = @client.post(serverurl + 'json', {'a' => 1, 'b' => {'c' => 2}})
21
+ assert_equal(2, res.content['b']['c'])
22
+ assert_equal('application/json; charset=utf-8', res.content_type)
23
+ # #previous contains the original response
24
+ assert_equal(1, JSON.parse(res.previous.content)['a'])
25
+ end
26
+
27
+ def test_post_with_header
28
+ res = @client.post(serverurl + 'json', :header => {'X-foo' => 'bar'}, :body => {'a' => 1, 'b' => {'c' => 2}})
29
+ assert_equal(2, res.content['b']['c'])
30
+ assert_equal('application/json; charset=utf-8', res.content_type)
31
+ end
32
+
33
+ def test_post_with_array_header
34
+ res = @client.post(serverurl + 'json', :header => [['X-foo', 'bar']], :body => {'a' => 1, 'b' => {'c' => 2}})
35
+ assert_equal(2, res.content['b']['c'])
36
+ assert_equal('application/json; charset=utf-8', res.content_type)
37
+ end
38
+
39
+ def test_post_non_json_body
40
+ res = @client.post(serverurl + 'json', 'a=b&c=d')
41
+ assert_equal('a=b&c=d', res.content)
42
+ assert_equal('application/x-www-form-urlencoded', res.content_type)
43
+ end
44
+
45
+ def test_put
46
+ res = @client.put(serverurl + 'json', {'a' => 1, 'b' => {'c' => 2}})
47
+ assert_equal(2, res.content['b']['c'])
48
+ assert_equal('application/json; charset=utf-8', res.content_type)
49
+ end
50
+
51
+ def test_get_not_affected
52
+ res = @client.get(serverurl + 'json', {'a' => 1, 'b' => {'c' => 2}})
53
+ assert_equal('', res.content)
54
+ assert_equal('', res.content_type)
55
+ end
56
+
57
+ class JSONServlet < WEBrick::HTTPServlet::AbstractServlet
58
+ def get_instance(*arg)
59
+ self
60
+ end
61
+
62
+ def service(req, res)
63
+ res['content-type'] = req['content-type']
64
+ res.body = req.body
65
+ end
66
+ end
67
+
68
+ def setup_server
69
+ @server = WEBrick::HTTPServer.new(
70
+ :BindAddress => "localhost",
71
+ :Logger => @logger,
72
+ :Port => 0,
73
+ :AccessLog => [],
74
+ :DocumentRoot => File.dirname(File.expand_path(__FILE__))
75
+ )
76
+ @serverport = @server.config[:Port]
77
+ @server.mount('/json', JSONServlet.new(@server))
78
+ @server_thread = start_server_thread(@server)
79
+ end
80
+ end
@@ -4,13 +4,13 @@ require 'webrick/https'
4
4
 
5
5
  class TestSSL < Test::Unit::TestCase
6
6
  include Helper
7
+
7
8
  DIR = File.dirname(File.expand_path(__FILE__))
8
9
 
9
10
  def setup
10
11
  super
11
12
  @serverpid = @client = nil
12
13
  @verify_callback_called = false
13
- @verbose, $VERBOSE = $VERBOSE, nil
14
14
  setup_server
15
15
  setup_client
16
16
  @url = "https://localhost:#{serverport}/hello"
@@ -18,13 +18,26 @@ class TestSSL < Test::Unit::TestCase
18
18
 
19
19
  def teardown
20
20
  super
21
- $VERBOSE = @verbose
22
21
  end
23
22
 
24
23
  def path(filename)
25
24
  File.expand_path(filename, DIR)
26
25
  end
27
26
 
27
+ def test_proxy_ssl
28
+ setup_proxyserver
29
+ escape_noproxy do
30
+ @client.proxy = proxyurl
31
+ @client.ssl_config.set_client_cert_file(path('client.cert'), path('client.key'))
32
+ @client.ssl_config.add_trust_ca(path('ca.cert'))
33
+ @client.ssl_config.add_trust_ca(path('subca.cert'))
34
+ @client.debug_dev = str = ""
35
+ assert_equal(200, @client.get(@url).status)
36
+ assert(/accept/ =~ @proxyio.string, 'proxy is not used')
37
+ assert(/Host: localhost:#{serverport}/ =~ str)
38
+ end
39
+ end
40
+
28
41
  def test_options
29
42
  cfg = @client.ssl_config
30
43
  assert_nil(cfg.client_cert)
@@ -33,11 +46,16 @@ class TestSSL < Test::Unit::TestCase
33
46
  assert_equal(OpenSSL::SSL::VERIFY_PEER | OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT, cfg.verify_mode)
34
47
  assert_nil(cfg.verify_callback)
35
48
  assert_nil(cfg.timeout)
36
- assert_equal(OpenSSL::SSL::OP_ALL | OpenSSL::SSL::OP_NO_SSLv2, cfg.options)
49
+ expected_options = OpenSSL::SSL::OP_ALL | OpenSSL::SSL::OP_NO_SSLv2 | OpenSSL::SSL::OP_NO_SSLv3
50
+ expected_options &= ~OpenSSL::SSL::OP_DONT_INSERT_EMPTY_FRAGMENTS if defined?(OpenSSL::SSL::OP_DONT_INSERT_EMPTY_FRAGMENTS)
51
+ expected_options |= OpenSSL::SSL::OP_NO_COMPRESSION if defined?(OpenSSL::SSL::OP_NO_COMPRESSION)
52
+ assert_equal(expected_options, cfg.options)
37
53
  assert_equal("ALL:!aNULL:!eNULL:!SSLv2", cfg.ciphers)
38
54
  assert_instance_of(OpenSSL::X509::Store, cfg.cert_store)
39
55
  end
40
56
 
57
+ unless defined?(HTTPClient::JRubySSLSocket)
58
+ # JRubySSLSocket does not support sync mode.
41
59
  def test_sync
42
60
  cfg = @client.ssl_config
43
61
  cfg.set_client_cert_file(path('client.cert'), path('client.key'))
@@ -49,18 +67,29 @@ class TestSSL < Test::Unit::TestCase
49
67
  @client.reset_all
50
68
  assert_equal("hello", @client.get_content(@url))
51
69
  end
70
+ end
52
71
 
53
72
  def test_debug_dev
54
73
  str = @client.debug_dev = ''
55
74
  cfg = @client.ssl_config
56
- cfg.client_cert = cert("client.cert")
57
- cfg.client_key = key("client.key")
75
+ cfg.client_cert = path("client.cert")
76
+ cfg.client_key = path("client.key")
58
77
  cfg.add_trust_ca(path('ca.cert'))
59
78
  cfg.add_trust_ca(path('subca.cert'))
60
79
  assert_equal("hello", @client.get_content(@url))
61
80
  assert(str.scan(/^hello$/)[0])
62
81
  end
63
82
 
83
+ def test_verification_without_httpclient
84
+ raw_cert = "-----BEGIN CERTIFICATE-----\nMIIDOTCCAiGgAwIBAgIBAjANBgkqhkiG9w0BAQsFADBCMRMwEQYKCZImiZPyLGQB\nGRYDb3JnMRkwFwYKCZImiZPyLGQBGRYJcnVieS1sYW5nMRAwDgYDVQQDDAdSdWJ5\nIENBMB4XDTE2MDgxMDE3MjEzNFoXDTE3MDgxMDE3MjEzNFowSzETMBEGCgmSJomT\n8ixkARkWA29yZzEZMBcGCgmSJomT8ixkARkWCXJ1YnktbGFuZzEZMBcGA1UEAwwQ\nUnVieSBjZXJ0aWZpY2F0ZTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB\nAJCfsSXpSMpmZCVa+ZCM+QDgomnhDlvnrGDq6pasTaIspGTXgws+7r8Dt/cNe6EH\nHJpRH2cGRiO4yPcfcT9eS4X7k8OC4f33wHfACOmLu6LeoNE8ujmSk6L6WzLUI+sE\nnLZbFrXxoAo4XHsm8vEG9C+jEoXZ1p+47wrAGaDwDQTnzlMy4dT9pRQEJP2G/Rry\nUkuZn8SUWmh3/YS78iaSzsNF1cgE1ealHOrPPFDjiCGDaH/LHyUPYlbFSLZ/B7Qx\nLxi5sePLcywWq/EJrmWpgeVTDjtNijsdKv/A3qkY+fm/oD0pzt7XsfJaP9YKNyJO\nQFdxWZeiPcDF+Hwf+IwSr+kCAwEAAaMxMC8wDgYDVR0PAQH/BAQDAgeAMB0GA1Ud\nDgQWBBQNvzYzJyXemGhxbA8NMXLolDnPyjANBgkqhkiG9w0BAQsFAAOCAQEARIJV\noKejGlOTn71QutnNnu07UtTu0IHs6YqjYzzND+m4JXLN+wvYm72AFUG0b1L7dRg0\niK8XjQrlNQNVqP1Mc6tffchy20neOPOHeiO6qTdRU8P2S8D3Uwe+1qhgxjfE+cWc\nwZmWxYK4HA8c58PxWMqrkr2QqXDplG9KWLvOgrtPGiLLZcQSKhvvB63QzItHBDU6\nRayiJY3oPkK/HrIvFlySqFqzWmuyknkciOFywEHQMz/tcSFJ2QFpPj/tBz9VXohH\nZ8KscmfhZrTPBjo+ky1lz/WraWoz4LMiLnkC2ABczWLRSawu+v3Irx1NFJngt05e\npqwtqIUeg7j+JLiTaA==\n-----END CERTIFICATE-----"
85
+ raw_ca_cert = "-----BEGIN CERTIFICATE-----\nMIIDYjCCAkqgAwIBAgIBATANBgkqhkiG9w0BAQsFADBCMRMwEQYKCZImiZPyLGQB\nGRYDb3JnMRkwFwYKCZImiZPyLGQBGRYJcnVieS1sYW5nMRAwDgYDVQQDDAdSdWJ5\nIENBMB4XDTE2MDgxMDE3MjA1NFoXDTE4MDgxMDE3MjA1NFowQjETMBEGCgmSJomT\n8ixkARkWA29yZzEZMBcGCgmSJomT8ixkARkWCXJ1YnktbGFuZzEQMA4GA1UEAwwH\nUnVieSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALKGwyM3Ejtl\npo7CqaDlS71gDZn3gm6IwWpmRMLJofSI9LCwAbjijSC2HvO0xUWoYW40FbzjnnEi\ngszsWyPwuQIx9t0bhuAyllNIfImmkaQkrikXKBKzia4jPnbc4iXPnfjuThjESFWl\ntfbN6y1B5TjKhD1KelfakUO+iMu8WlIA9NKQZYfJ/F3QSpP5Iqb3KN/jVifFbDV8\nbAl3Ln4rT2kTCKrZZcl1jmWsJv8jBw6+P7hk0/Mu0JeHAITsjbNbpHd8UXpCfbVs\nsNGZrBU4uJdZ2YTG+Y27/t25jFNQwb+TWbvig7rfdX2sjssuxa00BBxarC08tIVj\nZprM37KcNn8CAwEAAaNjMGEwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC\nAQYwHQYDVR0OBBYEFA2/NjMnJd6YaHFsDw0xcuiUOc/KMB8GA1UdIwQYMBYEFA2/\nNjMnJd6YaHFsDw0xcuiUOc/KMA0GCSqGSIb3DQEBCwUAA4IBAQAJSOw49XqvUll0\n3vU9EAO6yUdeZSsQENIfYbRMQgapbnN1vTyrUjPZkGC5hIE1pVdoHtEoUEICxIwy\nr6BKxiSLBDLp+rvIuDdzMkXIWdUVvTZguVRyKtM2gfnpsPLpVnv+stBmAW2SMyxm\nkymhOpkjdv3He+45uorB3tdfBS9VVomDEUJdg38UE1b5eXRQ3D6gG0iCPFzKszXg\nLoAYhGxtjCJaKlbzduMK0YO6aelgW1+XnVIKcA7DJ9egk5d/dFZBPFfwumwr9hTH\nh7/fp3Fr87weI+CkfmFyJZrsEBlXJBVuvPesMVHTh3Whm5kmCdWcBJU0QmSq42ZL\n72U0PXLR\n-----END CERTIFICATE-----"
86
+ ca_cert = ::OpenSSL::X509::Certificate.new(raw_ca_cert)
87
+ cert = ::OpenSSL::X509::Certificate.new(raw_cert)
88
+ store = ::OpenSSL::X509::Store.new
89
+ store.add_cert(ca_cert)
90
+ assert(store.verify(cert))
91
+ end
92
+
64
93
  def test_verification
65
94
  cfg = @client.ssl_config
66
95
  cfg.verify_callback = method(:verify_callback).to_proc
@@ -69,18 +98,18 @@ class TestSSL < Test::Unit::TestCase
69
98
  @client.get(@url)
70
99
  assert(false)
71
100
  rescue OpenSSL::SSL::SSLError => ssle
72
- assert_match(/certificate verify failed/, ssle.message)
101
+ assert_match(/(certificate verify failed|unable to find valid certification path to requested target)/, ssle.message)
73
102
  assert(@verify_callback_called)
74
103
  end
75
104
  #
76
- cfg.client_cert = cert("client.cert")
77
- cfg.client_key = key("client.key")
105
+ cfg.client_cert = path("client.cert")
106
+ cfg.client_key = path("client.key")
78
107
  @verify_callback_called = false
79
108
  begin
80
109
  @client.get(@url)
81
110
  assert(false)
82
111
  rescue OpenSSL::SSL::SSLError => ssle
83
- assert_match(/certificate verify failed/, ssle.message)
112
+ assert_match(/(certificate verify failed|unable to find valid certification path to requested target)/, ssle.message)
84
113
  assert(@verify_callback_called)
85
114
  end
86
115
  #
@@ -90,7 +119,7 @@ class TestSSL < Test::Unit::TestCase
90
119
  @client.get(@url)
91
120
  assert(false)
92
121
  rescue OpenSSL::SSL::SSLError => ssle
93
- assert_match(/certificate verify failed/, ssle.message)
122
+ assert_match(/(certificate verify failed|unable to find valid certification path to requested target)/, ssle.message)
94
123
  assert(@verify_callback_called)
95
124
  end
96
125
  #
@@ -99,16 +128,16 @@ class TestSSL < Test::Unit::TestCase
99
128
  assert_equal("hello", @client.get_content(@url))
100
129
  assert(@verify_callback_called)
101
130
  #
102
- unless ENV['TRAVIS']
103
- # On travis environment, verify_depth seems to not work properly.
104
- # Ubuntu 10.04 + OpenSSL 0.9.8k issue?
131
+ if false
132
+ # JRubySSLSocket does not support depth.
133
+ # Also on travis environment, verify_depth seems to not work properly.
105
134
  cfg.verify_depth = 1 # 2 required: root-sub
106
135
  @verify_callback_called = false
107
136
  begin
108
137
  @client.get(@url)
109
138
  assert(false, "verify_depth is not supported? #{OpenSSL::OPENSSL_VERSION}")
110
139
  rescue OpenSSL::SSL::SSLError => ssle
111
- assert_match(/certificate verify failed/, ssle.message)
140
+ assert_match(/(certificate verify failed|unable to find valid certification path to requested target)/, ssle.message)
112
141
  assert(@verify_callback_called)
113
142
  end
114
143
  #
@@ -125,16 +154,65 @@ end
125
154
  @client.get_content(@url)
126
155
  assert(false)
127
156
  rescue OpenSSL::SSL::SSLError => ssle
128
- assert_match(/certificate verify failed/, ssle.message)
157
+ assert_match(/(certificate verify failed|unable to find valid certification path to requested target)/, ssle.message)
129
158
  end
130
159
  #
131
160
  cfg.verify_mode = nil
132
161
  assert_equal("hello", @client.get_content(@url))
162
+ cfg.verify_mode = OpenSSL::SSL::VERIFY_NONE
163
+ assert_equal("hello", @client.get_content(@url))
133
164
  end
134
165
 
166
+ def test_cert_store
167
+ cfg = @client.ssl_config
168
+ cfg.cert_store.add_cert(cert('ca.cert'))
169
+ begin
170
+ @client.get(@url)
171
+ assert(false)
172
+ rescue OpenSSL::SSL::SSLError => ssle
173
+ assert_match(/(certificate verify failed|unable to find valid certification path to requested target)/, ssle.message)
174
+ end
175
+ #
176
+ cfg.cert_store.add_cert(cert('subca.cert'))
177
+ assert_equal("hello", @client.get_content(@url))
178
+ cfg.clear_cert_store
179
+ begin
180
+ @client.get(@url)
181
+ assert(false)
182
+ rescue OpenSSL::SSL::SSLError => ssle
183
+ assert_match(/(certificate verify failed|unable to find valid certification path to requested target)/, ssle.message)
184
+ end
185
+ end
186
+
187
+ if defined?(HTTPClient::JRubySSLSocket)
135
188
  def test_ciphers
136
189
  cfg = @client.ssl_config
137
- cfg.set_client_cert_file(path('client.cert'), path('client.key'))
190
+ cfg.set_client_cert_file(path('client.cert'), path('client-pass.key'), 'pass4key')
191
+ cfg.add_trust_ca(path('ca.cert'))
192
+ cfg.add_trust_ca(path('subca.cert'))
193
+ cfg.timeout = 123
194
+ assert_equal("hello", @client.get_content(@url))
195
+ #
196
+ cfg.ciphers = []
197
+ begin
198
+ @client.get(@url)
199
+ assert(false)
200
+ rescue OpenSSL::SSL::SSLError => ssle
201
+ assert_match(/No appropriate protocol/, ssle.message)
202
+ end
203
+ #
204
+ cfg.ciphers = %w(TLS_RSA_WITH_AES_128_CBC_SHA)
205
+ assert_equal("hello", @client.get_content(@url))
206
+ #
207
+ cfg.ciphers = HTTPClient::SSLConfig::CIPHERS_DEFAULT
208
+ assert_equal("hello", @client.get_content(@url))
209
+ end
210
+
211
+ else
212
+
213
+ def test_ciphers
214
+ cfg = @client.ssl_config
215
+ cfg.set_client_cert_file(path('client.cert'), path('client-pass.key'), 'pass4key')
138
216
  cfg.add_trust_ca(path('ca.cert'))
139
217
  cfg.add_trust_ca(path('subca.cert'))
140
218
  cfg.timeout = 123
@@ -154,18 +232,201 @@ end
154
232
  cfg.ciphers = "DEFAULT"
155
233
  assert_equal("hello", @client.get_content(@url))
156
234
  end
235
+ end
157
236
 
158
237
  def test_set_default_paths
159
238
  assert_raise(OpenSSL::SSL::SSLError) do
160
239
  @client.get(@url)
161
240
  end
162
241
  escape_env do
163
- ENV['SSL_CERT_FILE'] = File.join(DIR, 'ca-chain.cert')
242
+ ENV['SSL_CERT_FILE'] = File.join(DIR, 'ca-chain.pem')
164
243
  @client.ssl_config.set_default_paths
165
244
  @client.get(@url)
166
245
  end
167
246
  end
168
247
 
248
+ def test_no_sslv3
249
+ teardown_server
250
+ setup_server_with_ssl_version(:SSLv3)
251
+ assert_raise(OpenSSL::SSL::SSLError) do
252
+ @client.ssl_config.verify_mode = nil
253
+ @client.get("https://localhost:#{serverport}/hello")
254
+ end
255
+ end
256
+
257
+ def test_allow_tlsv1
258
+ teardown_server
259
+ setup_server_with_ssl_version(:TLSv1)
260
+ assert_nothing_raised do
261
+ @client.ssl_config.verify_mode = nil
262
+ @client.get("https://localhost:#{serverport}/hello")
263
+ end
264
+ end
265
+
266
+ def test_use_higher_TLS
267
+ omit('TODO: it does not pass with Java 7 or old openssl ')
268
+ teardown_server
269
+ setup_server_with_ssl_version('TLSv1_2')
270
+ assert_nothing_raised do
271
+ @client.ssl_config.verify_mode = nil
272
+ @client.get("https://localhost:#{serverport}/hello")
273
+ # TODO: should check JRubySSLSocket.ssl_socket.getSession.getProtocol
274
+ # but it's not thread safe. How can I return protocol version to the caller?
275
+ end
276
+ end
277
+
278
+ VERIFY_TEST_CERT_LOCALHOST = OpenSSL::X509::Certificate.new(<<-EOS)
279
+ -----BEGIN CERTIFICATE-----
280
+ MIIB9jCCAV+gAwIBAgIJAIH8Gsm4PcNKMA0GCSqGSIb3DQEBCwUAMBQxEjAQBgNV
281
+ BAMMCWxvY2FsaG9zdDAeFw0xNjA4MTgxMDI2MDVaFw00NDAxMDMxMDI2MDVaMBQx
282
+ EjAQBgNVBAMMCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
283
+ p7D8q0lcx5EZEV5+zPnQsxrbft5xyhH/MCStbH46DRATGPNSOaLRCG5r8gTKQzpD
284
+ 4swGrQFYe2ienQ+7o4aEHErsXp4O/EmDKeiXWWrMqPr23r3HOBDebuynC/sCwy7N
285
+ epnX9u1VLB03eo+suj4d86OoOF+o11t9ZP+GA29Rsf8CAwEAAaNQME4wHQYDVR0O
286
+ BBYEFIxsJuPVvd5KKFcAvHGSeKSsWiUJMB8GA1UdIwQYMBaAFIxsJuPVvd5KKFcA
287
+ vHGSeKSsWiUJMAwGA1UdEwQFMAMBAf8wDQYJKoZIhvcNAQELBQADgYEAMJaVCrrM
288
+ SM2I06Vr4BL+jtDFhZh3HmJFEDpwEFQ5Y9hduwdUGRBGCpkuea3fE2FKwWW9gLM1
289
+ w7rFMzYFtCEqm78dJWIU79MRy0wjO4LgtYfoikgBh6JKWuV5ed/+L3sLyLG0ZTtv
290
+ lrD7lzDtXgwvj007PxDoYRp3JwYzKRmTbH8=
291
+ -----END CERTIFICATE-----
292
+ EOS
293
+
294
+ VERIFY_TEST_CERT_FOO_DOMAIN = OpenSSL::X509::Certificate.new(<<-EOS)
295
+ -----BEGIN CERTIFICATE-----
296
+ MIIB8jCCAVugAwIBAgIJAL/od7Whx7VTMA0GCSqGSIb3DQEBCwUAMBIxEDAOBgNV
297
+ BAMMB2Zvby5jb20wHhcNMTYwODE4MTAyMzUyWhcNNDQwMTAzMTAyMzUyWjASMRAw
298
+ DgYDVQQDDAdmb28uY29tMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCnsPyr
299
+ SVzHkRkRXn7M+dCzGtt+3nHKEf8wJK1sfjoNEBMY81I5otEIbmvyBMpDOkPizAat
300
+ AVh7aJ6dD7ujhoQcSuxeng78SYMp6JdZasyo+vbevcc4EN5u7KcL+wLDLs16mdf2
301
+ 7VUsHTd6j6y6Ph3zo6g4X6jXW31k/4YDb1Gx/wIDAQABo1AwTjAdBgNVHQ4EFgQU
302
+ jGwm49W93kooVwC8cZJ4pKxaJQkwHwYDVR0jBBgwFoAUjGwm49W93kooVwC8cZJ4
303
+ pKxaJQkwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOBgQCVKTvfxx+yezuR
304
+ 5WpVKw1E9qabKOYFB5TqdHMHreRubMJTaoZC+YzhcCwtyLlAA9+axKINAiMM8T+z
305
+ jjfOHQSa2GS2TaaVDJWmXIgsAlEbjd2BEiQF0LZYGJRG9pyq0WbTV+CyFdrghjcO
306
+ xX/t7OG7NfOG9dhv3J+5SX10S5V5Dg==
307
+ -----END CERTIFICATE-----
308
+ EOS
309
+
310
+ VERIFY_TEST_CERT_ALT_NAME = OpenSSL::X509::Certificate.new(<<-EOS)
311
+ -----BEGIN CERTIFICATE-----
312
+ MIICDDCCAXWgAwIBAgIJAOxXY4nOwxhGMA0GCSqGSIb3DQEBCwUAMBQxEjAQBgNV
313
+ BAMMCWxvY2FsaG9zdDAeFw0xNjA4MTgxMDM0NTJaFw00NDAxMDMxMDM0NTJaMBQx
314
+ EjAQBgNVBAMMCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA
315
+ p7D8q0lcx5EZEV5+zPnQsxrbft5xyhH/MCStbH46DRATGPNSOaLRCG5r8gTKQzpD
316
+ 4swGrQFYe2ienQ+7o4aEHErsXp4O/EmDKeiXWWrMqPr23r3HOBDebuynC/sCwy7N
317
+ epnX9u1VLB03eo+suj4d86OoOF+o11t9ZP+GA29Rsf8CAwEAAaNmMGQwFAYDVR0R
318
+ BA0wC4IJKi5mb28uY29tMB0GA1UdDgQWBBSMbCbj1b3eSihXALxxknikrFolCTAf
319
+ BgNVHSMEGDAWgBSMbCbj1b3eSihXALxxknikrFolCTAMBgNVHRMEBTADAQH/MA0G
320
+ CSqGSIb3DQEBCwUAA4GBADJlKNFuOnsDIhHGW72HuQw4naN6lM3eZE9JJ+UF/XIF
321
+ ghGtgqw+00Yy5wMFc1K2Wm4p5NymmDfC/P1FOe34bpxt9/IWm6mEoIWoodC3N4Cm
322
+ PtnSS1/CRWzVIPGMglTGGDcUc70tfeAWgyTxgcNQd4vTFtnN0f0RDdaXa8kfKMTw
323
+ -----END CERTIFICATE-----
324
+ EOS
325
+
326
+ VERIFY_TEST_PKEY = OpenSSL::PKey::RSA.new(<<-EOS)
327
+ -----BEGIN RSA PRIVATE KEY-----
328
+ MIICXQIBAAKBgQCnsPyrSVzHkRkRXn7M+dCzGtt+3nHKEf8wJK1sfjoNEBMY81I5
329
+ otEIbmvyBMpDOkPizAatAVh7aJ6dD7ujhoQcSuxeng78SYMp6JdZasyo+vbevcc4
330
+ EN5u7KcL+wLDLs16mdf27VUsHTd6j6y6Ph3zo6g4X6jXW31k/4YDb1Gx/wIDAQAB
331
+ AoGAe0RHx+WKtQx8/96VmTl951qzxMPho2etTYd4kAsNwzJwx2N9qu57eBYrdWF+
332
+ CQMYievucFhP4Y+bINtC1Eb6btz9TCUwjCfeIxfGRoFf3cxVmxlsRJJmN1kSZlu1
333
+ yYlcMVuP4noeFIMQBRrt5pyLCx2Z9A01NCQT4Y6VoREBIeECQQDWeNhsL6xkrmdB
334
+ M9+zl+SqHdNKhgKwMdp74+UNnAV9I8GB7bGlOWhc83aqMLgS+JBDFXcmNF/KawTR
335
+ zcnkod5xAkEAyClFgr3lZQSnwUwoA/AOcyW0+H63taaaXS/g8n3H8ENK6kL4ldUx
336
+ IgCk2ekbQ5Y3S2WScIGXNxMOza9MlsOvbwJAPUtoPvMZB+U4KVBT/JXKijvf6QqH
337
+ tidpU8L78XnHr84KPcHa5WeUxgvmvBkUYoebYzC9TrPlNIqFZBi2PJtuYQJBAMda
338
+ E5j7eJT75fhm2RPS6xFT5MH5sw6AOA3HucrJ63AoFVzsBpl0E9NBwO4ndLgDzF6T
339
+ cx4Kc4iuunewuB8QFpECQQCfvsHCjIJ/X4kiqeBzxDq2GR/oDgQkOzY+4H9U7Lwl
340
+ e61RBaxk5OHOA0bLtvJblV6NL72ZEZhX60wAWbrOPhpT
341
+ -----END RSA PRIVATE KEY-----
342
+ EOS
343
+
344
+ def test_post_connection_check
345
+ teardown_server
346
+ setup_server_with_server_cert(nil, VERIFY_TEST_CERT_LOCALHOST, VERIFY_TEST_PKEY)
347
+ file = Tempfile.new('cert')
348
+ File.write(file.path, VERIFY_TEST_CERT_LOCALHOST.to_pem)
349
+ @client.ssl_config.add_trust_ca(file.path)
350
+ assert_nothing_raised do
351
+ @client.get("https://localhost:#{serverport}/hello")
352
+ end
353
+ @client.ssl_config.verify_mode = OpenSSL::SSL::VERIFY_NONE
354
+ assert_nothing_raised do
355
+ @client.get("https://localhost:#{serverport}/hello")
356
+ end
357
+ @client.ssl_config.verify_mode = OpenSSL::SSL::VERIFY_PEER
358
+
359
+ teardown_server
360
+ setup_server_with_server_cert(nil, VERIFY_TEST_CERT_FOO_DOMAIN, VERIFY_TEST_PKEY)
361
+ File.write(file.path, VERIFY_TEST_CERT_FOO_DOMAIN.to_pem)
362
+ @client.ssl_config.add_trust_ca(file.path)
363
+ assert_raises(OpenSSL::SSL::SSLError) do
364
+ @client.get("https://localhost:#{serverport}/hello")
365
+ end
366
+ @client.ssl_config.verify_mode = OpenSSL::SSL::VERIFY_NONE
367
+ assert_nothing_raised do
368
+ @client.get("https://localhost:#{serverport}/hello")
369
+ end
370
+ @client.ssl_config.verify_mode = OpenSSL::SSL::VERIFY_PEER
371
+
372
+ teardown_server
373
+ setup_server_with_server_cert(nil, VERIFY_TEST_CERT_ALT_NAME, VERIFY_TEST_PKEY)
374
+ File.write(file.path, VERIFY_TEST_CERT_ALT_NAME.to_pem)
375
+ @client.ssl_config.add_trust_ca(file.path)
376
+ assert_raises(OpenSSL::SSL::SSLError) do
377
+ @client.get("https://localhost:#{serverport}/hello")
378
+ end
379
+ @client.ssl_config.verify_mode = OpenSSL::SSL::VERIFY_NONE
380
+ assert_nothing_raised do
381
+ @client.get("https://localhost:#{serverport}/hello")
382
+ end
383
+ @client.ssl_config.verify_mode = OpenSSL::SSL::VERIFY_PEER
384
+ end
385
+
386
+ def test_x509_store_add_cert_prepend
387
+ store = OpenSSL::X509::Store.new
388
+ assert_equal(store, store.add_cert(OpenSSL::X509::Certificate.new(VERIFY_TEST_CERT_LOCALHOST)))
389
+ end
390
+
391
+ def test_tcp_keepalive
392
+ @client.tcp_keepalive = true
393
+ @client.ssl_config.add_trust_ca(path('ca-chain.pem'))
394
+ @client.get_content(@url)
395
+
396
+ # expecting HTTP keepalive caches the socket
397
+ session = @client.instance_variable_get(:@session_manager).send(:get_cached_session, HTTPClient::Site.new(URI.parse(@url)))
398
+ socket = session.instance_variable_get(:@socket).instance_variable_get(:@socket)
399
+
400
+ assert_true(session.tcp_keepalive)
401
+ if RUBY_ENGINE == 'jruby'
402
+ assert_true(socket.getKeepAlive())
403
+ else
404
+ assert_equal(Socket::SO_KEEPALIVE, socket.getsockopt(Socket::SOL_SOCKET, Socket::SO_KEEPALIVE).optname)
405
+ end
406
+ end
407
+
408
+ def test_timeout
409
+ url = "https://localhost:#{serverport}/"
410
+ @client.ssl_config.add_trust_ca(path('ca-chain.pem'))
411
+ assert_equal('sleep', @client.get_content(url + 'sleep?sec=2'))
412
+ @client.receive_timeout = 1
413
+ @client.reset_all
414
+ assert_equal('sleep', @client.get_content(url + 'sleep?sec=0'))
415
+
416
+ start = Time.now
417
+ assert_raise(HTTPClient::ReceiveTimeoutError) do
418
+ @client.get_content(url + 'sleep?sec=5')
419
+ end
420
+ if Time.now - start > 3
421
+ # before #342 it detected timeout when IO was freed
422
+ fail 'timeout does not work'
423
+ end
424
+
425
+ @client.receive_timeout = 3
426
+ @client.reset_all
427
+ assert_equal('sleep', @client.get_content(url + 'sleep?sec=2'))
428
+ end
429
+
169
430
  private
170
431
 
171
432
  def cert(filename)
@@ -198,6 +459,62 @@ private
198
459
  :SSLCertName => nil
199
460
  )
200
461
  @serverport = @server.config[:Port]
462
+ [:hello, :sleep].each do |sym|
463
+ @server.mount(
464
+ "/#{sym}",
465
+ WEBrick::HTTPServlet::ProcHandler.new(method("do_#{sym}").to_proc)
466
+ )
467
+ end
468
+ @server_thread = start_server_thread(@server)
469
+ end
470
+
471
+ def setup_server_with_ssl_version(ssl_version)
472
+ # JRubyOpenSSL does not support "TLSv1_2" as an known version, and some JCE provides TLS v1.2 as "TLSv1.2" not "TLSv1_2"
473
+ if RUBY_ENGINE == 'jruby' && ['TLSv1_1', 'TLSv1_2'].include?(ssl_version)
474
+ ssl_version = ssl_version.tr('_', '.')
475
+ end
476
+ logger = Logger.new(STDERR)
477
+ logger.level = Logger::Severity::FATAL # avoid logging SSLError (ERROR level)
478
+ @server = WEBrick::HTTPServer.new(
479
+ :BindAddress => "localhost",
480
+ :Logger => logger,
481
+ :Port => 0,
482
+ :AccessLog => [],
483
+ :DocumentRoot => DIR,
484
+ :SSLEnable => true,
485
+ :SSLCACertificateFile => File.join(DIR, 'ca.cert'),
486
+ :SSLCertificate => cert('server.cert'),
487
+ :SSLPrivateKey => key('server.key')
488
+ )
489
+ @server.ssl_context.ssl_version = ssl_version
490
+ @serverport = @server.config[:Port]
491
+ [:hello].each do |sym|
492
+ @server.mount(
493
+ "/#{sym}",
494
+ WEBrick::HTTPServlet::ProcHandler.new(method("do_#{sym}").to_proc)
495
+ )
496
+ end
497
+ @server_thread = start_server_thread(@server)
498
+ end
499
+
500
+ def setup_server_with_server_cert(ca_cert, server_cert, server_key)
501
+ logger = Logger.new(STDERR)
502
+ logger.level = Logger::Severity::FATAL # avoid logging SSLError (ERROR level)
503
+ @server = WEBrick::HTTPServer.new(
504
+ :BindAddress => "localhost",
505
+ :Logger => logger,
506
+ :Port => 0,
507
+ :AccessLog => [],
508
+ :DocumentRoot => DIR,
509
+ :SSLEnable => true,
510
+ :SSLCACertificateFile => ca_cert,
511
+ :SSLCertificate => server_cert,
512
+ :SSLPrivateKey => server_key,
513
+ :SSLVerifyClient => nil,
514
+ :SSLClientCA => nil,
515
+ :SSLCertName => nil
516
+ )
517
+ @serverport = @server.config[:Port]
201
518
  [:hello].each do |sym|
202
519
  @server.mount(
203
520
  "/#{sym}",
@@ -212,6 +529,13 @@ private
212
529
  res.body = "hello"
213
530
  end
214
531
 
532
+ def do_sleep(req, res)
533
+ sec = req.query['sec'].to_i
534
+ sleep sec
535
+ res['content-type'] = 'text/html'
536
+ res.body = "sleep"
537
+ end
538
+
215
539
  def start_server_thread(server)
216
540
  t = Thread.new {
217
541
  Thread.current.abort_on_exception = true