httpclient 2.6.0.1 → 2.8.3

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,5 +1,5 @@
1
1
  # HTTPClient - HTTP client library.
2
- # Copyright (C) 2000-2009 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
2
+ # Copyright (C) 2000-2015 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
3
3
  #
4
4
  # This program is copyrighted free software by NAKAMURA, Hiroshi. You can
5
5
  # redistribute it and/or modify it under the same terms of Ruby's license;
@@ -3,16 +3,19 @@ unless defined?(HTTPClient::CookieManager)
3
3
  begin # for catching LoadError and load webagent-cookie instead
4
4
 
5
5
  require 'http-cookie'
6
+ require 'httpclient/util'
6
7
 
7
8
  class HTTPClient
8
9
  class CookieManager
9
- attr_reader :format
10
+ include HTTPClient::Util
11
+
12
+ attr_reader :format, :jar
10
13
  attr_accessor :cookies_file
11
14
 
12
- def initialize(cookies_file = nil, format = WebAgentSaver)
15
+ def initialize(cookies_file = nil, format = WebAgentSaver, jar = HTTP::CookieJar.new)
13
16
  @cookies_file = cookies_file
14
17
  @format = format
15
- @jar = HTTP::CookieJar.new
18
+ @jar = jar
16
19
  load_cookies if @cookies_file
17
20
  end
18
21
 
@@ -68,7 +71,7 @@ class HTTPClient
68
71
  end
69
72
 
70
73
  def find(uri)
71
- warn('CookieManager#find is deprecated and will be removed in near future. Use HTTP::Cookie.cookie_value(CookieManager#cookies) instead')
74
+ warning('CookieManager#find is deprecated and will be removed in near future. Use HTTP::Cookie.cookie_value(CookieManager#cookies) instead')
72
75
  if cookie = cookies(uri)
73
76
  HTTP::Cookie.cookie_value(cookie)
74
77
  end
@@ -174,7 +177,7 @@ class WebAgent
174
177
  CookieManager = ::HTTPClient::CookieManager
175
178
 
176
179
  class Cookie < HTTP::Cookie
177
- @@warned = false
180
+ include HTTPClient::Util
178
181
 
179
182
  def url
180
183
  deprecated('url', 'origin')
@@ -194,7 +197,7 @@ class WebAgent
194
197
  alias original_domain domain
195
198
 
196
199
  def domain
197
- warn('Cookie#domain returns dot-less domain name now. Use Cookie#dot_domain if you need "." at the beginning.')
200
+ warning('Cookie#domain returns dot-less domain name now. Use Cookie#dot_domain if you need "." at the beginning.')
198
201
  self.original_domain
199
202
  end
200
203
 
@@ -206,10 +209,7 @@ class WebAgent
206
209
  private
207
210
 
208
211
  def deprecated(old, new)
209
- unless @@warned
210
- warn("WebAgent::Cookie is deprecated and will be replaced with HTTP::Cookie in the near future. Please use Cookie##{new} instead of Cookie##{old} for the replacement.")
211
- @@warned = true
212
- end
212
+ warning("WebAgent::Cookie is deprecated and will be replaced with HTTP::Cookie in the near future. Please use Cookie##{new} instead of Cookie##{old} for the replacement.")
213
213
  end
214
214
  end
215
215
  end
@@ -1,7 +1,7 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
 
3
3
  # HTTPClient - HTTP client library.
4
- # Copyright (C) 2000-2009 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
4
+ # Copyright (C) 2000-2015 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
5
5
  #
6
6
  # This program is copyrighted free software by NAKAMURA, Hiroshi. You can
7
7
  # redistribute it and/or modify it under the same terms of Ruby's license;
@@ -12,6 +12,7 @@ require 'time'
12
12
  if defined?(Encoding::ASCII_8BIT)
13
13
  require 'open-uri' # for encoding
14
14
  end
15
+ require 'httpclient/util'
15
16
 
16
17
 
17
18
  # A namespace module for HTTP Message definitions used by HTTPClient.
@@ -95,6 +96,7 @@ module HTTP
95
96
  # p res.header['last-modified'].first
96
97
  #
97
98
  class Message
99
+ include HTTPClient::Util
98
100
 
99
101
  CRLF = "\r\n"
100
102
 
@@ -698,8 +700,9 @@ module HTTP
698
700
 
699
701
  def params_from_file(value)
700
702
  params = {}
703
+ original_filename = value.respond_to?(:original_filename) ? value.original_filename : nil
701
704
  path = value.respond_to?(:path) ? value.path : nil
702
- params['filename'] = File.basename(path || '')
705
+ params['filename'] = original_filename || File.basename(path || '')
703
706
  # Creation time is not available from File::Stat
704
707
  if value.respond_to?(:mtime)
705
708
  params['modification-date'] = value.mtime.rfc822
@@ -806,6 +809,8 @@ module HTTP
806
809
  case path
807
810
  when /\.txt$/i
808
811
  'text/plain'
812
+ when /\.xml$/i
813
+ 'text/xml'
809
814
  when /\.(htm|html)$/i
810
815
  'text/html'
811
816
  when /\.doc$/i
@@ -980,12 +985,12 @@ module HTTP
980
985
 
981
986
  VERSION_WARNING = 'Message#version (Float) is deprecated. Use Message#http_version (String) instead.'
982
987
  def version
983
- warn(VERSION_WARNING)
988
+ warning(VERSION_WARNING)
984
989
  @http_header.http_version.to_f
985
990
  end
986
991
 
987
992
  def version=(version)
988
- warn(VERSION_WARNING)
993
+ warning(VERSION_WARNING)
989
994
  @http_header.http_version = version
990
995
  end
991
996
 
@@ -0,0 +1,588 @@
1
+ # HTTPClient - HTTP client library.
2
+ # Copyright (C) 2000-2015 NAKAMURA, Hiroshi <nahi@ruby-lang.org>.
3
+ #
4
+ # This program is copyrighted free software by NAKAMURA, Hiroshi. You can
5
+ # redistribute it and/or modify it under the same terms of Ruby's license;
6
+ # either the dual license version in 2003, or any later version.
7
+
8
+
9
+ require 'java'
10
+ require 'httpclient/ssl_config'
11
+
12
+
13
+ class HTTPClient
14
+
15
+ unless defined?(SSLSocket)
16
+
17
+ class JavaSocketWrap
18
+ java_import 'java.net.InetSocketAddress'
19
+ java_import 'java.io.BufferedInputStream'
20
+
21
+ BUF_SIZE = 1024 * 16
22
+
23
+ def self.connect(socket, site, opts = {})
24
+ socket_addr = InetSocketAddress.new(site.host, site.port)
25
+ if opts[:connect_timeout]
26
+ socket.connect(socket_addr, opts[:connect_timeout])
27
+ else
28
+ socket.connect(socket_addr)
29
+ end
30
+ socket.setSoTimeout(opts[:so_timeout]) if opts[:so_timeout]
31
+ socket.setKeepAlive(true) if opts[:tcp_keepalive]
32
+ socket
33
+ end
34
+
35
+ def initialize(socket, debug_dev = nil)
36
+ @socket = socket
37
+ @debug_dev = debug_dev
38
+ @outstr = @socket.getOutputStream
39
+ @instr = BufferedInputStream.new(@socket.getInputStream)
40
+ @buf = (' ' * BUF_SIZE).to_java_bytes
41
+ @bufstr = ''
42
+ end
43
+
44
+ def close
45
+ @socket.close
46
+ end
47
+
48
+ def closed?
49
+ @socket.isClosed
50
+ end
51
+
52
+ def eof?
53
+ @socket.isClosed
54
+ end
55
+
56
+ def gets(rs)
57
+ while (size = @bufstr.index(rs)).nil?
58
+ if fill() == -1
59
+ size = @bufstr.size
60
+ break
61
+ end
62
+ end
63
+ str = @bufstr.slice!(0, size + rs.size)
64
+ debug(str)
65
+ str
66
+ end
67
+
68
+ def read(size, buf = nil)
69
+ while @bufstr.size < size
70
+ if fill() == -1
71
+ break
72
+ end
73
+ end
74
+ str = @bufstr.slice!(0, size)
75
+ debug(str)
76
+ if buf
77
+ buf.replace(str)
78
+ else
79
+ str
80
+ end
81
+ end
82
+
83
+ def readpartial(size, buf = nil)
84
+ while @bufstr.size == 0
85
+ if fill() == -1
86
+ raise EOFError.new('end of file reached')
87
+ end
88
+ end
89
+ str = @bufstr.slice!(0, size)
90
+ debug(str)
91
+ if buf
92
+ buf.replace(str)
93
+ else
94
+ str
95
+ end
96
+ end
97
+
98
+ def <<(str)
99
+ rv = @outstr.write(str.to_java_bytes)
100
+ debug(str)
101
+ rv
102
+ end
103
+
104
+ def flush
105
+ @socket.flush
106
+ end
107
+
108
+ def sync
109
+ true
110
+ end
111
+
112
+ def sync=(sync)
113
+ unless sync
114
+ raise "sync = false is not supported. This option was introduced for backward compatibility just in case."
115
+ end
116
+ end
117
+
118
+ private
119
+
120
+ def fill
121
+ begin
122
+ size = @instr.read(@buf)
123
+ if size > 0
124
+ @bufstr << String.from_java_bytes(@buf, Encoding::BINARY)[0, size]
125
+ end
126
+ size
127
+ rescue java.io.IOException => e
128
+ raise OpenSSL::SSL::SSLError.new("#{e.class}: #{e.getMessage}")
129
+ end
130
+ end
131
+
132
+ def debug(str)
133
+ @debug_dev << str if @debug_dev && str
134
+ end
135
+ end
136
+
137
+ class JRubySSLSocket < JavaSocketWrap
138
+ java_import 'java.io.ByteArrayInputStream'
139
+ java_import 'java.io.InputStreamReader'
140
+ java_import 'java.net.Socket'
141
+ java_import 'java.security.KeyStore'
142
+ java_import 'java.security.cert.Certificate'
143
+ java_import 'java.security.cert.CertificateFactory'
144
+ java_import 'javax.net.ssl.KeyManagerFactory'
145
+ java_import 'javax.net.ssl.SSLContext'
146
+ java_import 'javax.net.ssl.SSLSocketFactory'
147
+ java_import 'javax.net.ssl.TrustManager'
148
+ java_import 'javax.net.ssl.TrustManagerFactory'
149
+ java_import 'javax.net.ssl.X509TrustManager'
150
+ java_import 'org.jruby.ext.openssl.x509store.PEMInputOutput'
151
+
152
+ class JavaCertificate
153
+ attr_reader :cert
154
+
155
+ def initialize(cert)
156
+ @cert = cert
157
+ end
158
+
159
+ def subject
160
+ @cert.getSubjectDN
161
+ end
162
+
163
+ def to_text
164
+ @cert.toString
165
+ end
166
+
167
+ def to_pem
168
+ '(not in PEM format)'
169
+ end
170
+ end
171
+
172
+ class SSLStoreContext
173
+ attr_reader :current_cert, :chain, :error_depth, :error, :error_string
174
+
175
+ def initialize(current_cert, chain, error_depth, error, error_string)
176
+ @current_cert, @chain, @error_depth, @error, @error_string =
177
+ current_cert, chain, error_depth, error, error_string
178
+ end
179
+ end
180
+
181
+ class JSSEVerifyCallback
182
+ def initialize(verify_callback)
183
+ @verify_callback = verify_callback
184
+ end
185
+
186
+ def call(is_ok, chain, error_depth = -1, error = -1, error_string = '(unknown)')
187
+ if @verify_callback
188
+ ruby_chain = chain.map { |cert|
189
+ JavaCertificate.new(cert)
190
+ }.reverse
191
+ # NOTE: The order depends on provider implementation
192
+ ruby_chain.each do |cert|
193
+ is_ok = @verify_callback.call(
194
+ is_ok,
195
+ SSLStoreContext.new(cert, ruby_chain, error_depth, error, error_string)
196
+ )
197
+ end
198
+ end
199
+ is_ok
200
+ end
201
+ end
202
+
203
+ class VerifyNoneTrustManagerFactory
204
+ class VerifyNoneTrustManager
205
+ include X509TrustManager
206
+
207
+ def initialize(verify_callback)
208
+ @verify_callback = JSSEVerifyCallback.new(verify_callback)
209
+ end
210
+
211
+ def checkServerTrusted(chain, authType)
212
+ @verify_callback.call(true, chain)
213
+ end
214
+
215
+ def checkClientTrusted(chain, authType); end
216
+ def getAcceptedIssuers; end
217
+ end
218
+
219
+ def initialize(verify_callback = nil)
220
+ @verify_callback = verify_callback
221
+ end
222
+
223
+ def init(trustStore)
224
+ @managers = [VerifyNoneTrustManager.new(@verify_callback)].to_java(X509TrustManager)
225
+ end
226
+
227
+ def getTrustManagers
228
+ @managers
229
+ end
230
+ end
231
+
232
+ class SystemTrustManagerFactory
233
+ class SystemTrustManager
234
+ include X509TrustManager
235
+
236
+ def initialize(original, verify_callback)
237
+ @original = original
238
+ @verify_callback = JSSEVerifyCallback.new(verify_callback)
239
+ end
240
+
241
+ def checkServerTrusted(chain, authType)
242
+ is_ok = false
243
+ excn = nil
244
+ # TODO can we detect the depth from excn?
245
+ error_depth = -1
246
+ error = nil
247
+ error_message = nil
248
+ begin
249
+ @original.checkServerTrusted(chain, authType)
250
+ is_ok = true
251
+ rescue java.security.cert.CertificateException => excn
252
+ is_ok = false
253
+ error = excn.class.name
254
+ error_message = excn.getMessage
255
+ end
256
+ is_ok = @verify_callback.call(is_ok, chain, error_depth, error, error_message)
257
+ unless is_ok
258
+ excn ||= OpenSSL::SSL::SSLError.new('verifycallback failed')
259
+ raise excn
260
+ end
261
+ end
262
+
263
+ def checkClientTrusted(chain, authType); end
264
+ def getAcceptedIssuers; end
265
+ end
266
+
267
+ def initialize(verify_callback = nil)
268
+ @verify_callback = verify_callback
269
+ end
270
+
271
+ def init(trust_store)
272
+ tmf = TrustManagerFactory.getInstance(TrustManagerFactory.getDefaultAlgorithm)
273
+ tmf.java_method(:init, [KeyStore]).call(trust_store)
274
+ @original = tmf.getTrustManagers.find { |tm|
275
+ tm.is_a?(X509TrustManager)
276
+ }
277
+ @managers = [SystemTrustManager.new(@original, @verify_callback)].to_java(X509TrustManager)
278
+ end
279
+
280
+ def getTrustManagers
281
+ @managers
282
+ end
283
+ end
284
+
285
+ module PEMUtils
286
+ def self.read_certificate(pem)
287
+ cert = pem.sub(/.*?-----BEGIN CERTIFICATE-----/m, '').sub(/-----END CERTIFICATE-----.*?/m, '')
288
+ der = cert.unpack('m*').first
289
+ cf = CertificateFactory.getInstance('X.509')
290
+ cf.generateCertificate(ByteArrayInputStream.new(der.to_java_bytes))
291
+ end
292
+
293
+ def self.read_private_key(pem, password)
294
+ if password
295
+ password = password.unpack('C*').to_java(:char)
296
+ end
297
+ PEMInputOutput.read_private_key(InputStreamReader.new(ByteArrayInputStream.new(pem.to_java_bytes)), password)
298
+ end
299
+ end
300
+
301
+ class KeyStoreLoader
302
+ PASSWORD = 16.times.map { rand(256) }.to_java(:char)
303
+
304
+ def initialize
305
+ @keystore = KeyStore.getInstance('JKS')
306
+ @keystore.load(nil)
307
+ end
308
+
309
+ def add(cert_source, key_source, password)
310
+ cert_str = cert_source.respond_to?(:to_pem) ? cert_source.to_pem : File.read(cert_source.to_s)
311
+ cert = PEMUtils.read_certificate(cert_str)
312
+ @keystore.setCertificateEntry('client_cert', cert)
313
+ key_str = key_source.respond_to?(:to_pem) ? key_source.to_pem : File.read(key_source.to_s)
314
+ key_pair = PEMUtils.read_private_key(key_str, password)
315
+ @keystore.setKeyEntry('client_key', key_pair.getPrivate, PASSWORD, [cert].to_java(Certificate))
316
+ end
317
+
318
+ def keystore
319
+ @keystore
320
+ end
321
+ end
322
+
323
+ class TrustStoreLoader
324
+ attr_reader :size
325
+
326
+ def initialize
327
+ @trust_store = KeyStore.getInstance('JKS')
328
+ @trust_store.load(nil)
329
+ @size = 0
330
+ end
331
+
332
+ def add(cert_source)
333
+ return if cert_source == :default
334
+ if cert_source.respond_to?(:to_pem)
335
+ pem = cert_source.to_pem
336
+ load_pem(pem)
337
+ elsif File.directory?(cert_source)
338
+ warn("#{cert_source}: directory not yet supported")
339
+ return
340
+ else
341
+ pem = nil
342
+ File.read(cert_source).each_line do |line|
343
+ case line
344
+ when /-----BEGIN CERTIFICATE-----/
345
+ pem = ''
346
+ when /-----END CERTIFICATE-----/
347
+ load_pem(pem)
348
+ # keep parsing in case where multiple certificates in a file
349
+ else
350
+ if pem
351
+ pem << line
352
+ end
353
+ end
354
+ end
355
+ end
356
+ end
357
+
358
+ def trust_store
359
+ if @size == 0
360
+ nil
361
+ else
362
+ @trust_store
363
+ end
364
+ end
365
+
366
+ private
367
+
368
+ def load_pem(pem)
369
+ cert = PEMUtils.read_certificate(pem)
370
+ @size += 1
371
+ @trust_store.setCertificateEntry("cert_#{@size}", cert)
372
+ end
373
+ end
374
+
375
+ # Ported from commons-httpclient 'BrowserCompatHostnameVerifier'
376
+ class BrowserCompatHostnameVerifier
377
+ BAD_COUNTRY_2LDS = %w(ac co com ed edu go gouv gov info lg ne net or org).sort
378
+ require 'ipaddr'
379
+
380
+ def extract_sans(cert, subject_type)
381
+ sans = cert.getSubjectAlternativeNames rescue nil
382
+ if sans.nil?
383
+ return nil
384
+ end
385
+ sans.find_all { |san|
386
+ san.first.to_i == subject_type
387
+ }.map { |san|
388
+ san[1]
389
+ }
390
+ end
391
+
392
+ def extract_cn(cert)
393
+ subject = cert.getSubjectX500Principal()
394
+ if subject
395
+ subject_dn = javax.naming.ldap.LdapName.new(subject.toString)
396
+ subject_dn.getRdns.to_a.reverse.each do |rdn|
397
+ attributes = rdn.toAttributes
398
+ cn = attributes.get('cn')
399
+ if cn
400
+ if value = cn.get
401
+ return value.to_s
402
+ end
403
+ end
404
+ end
405
+ end
406
+ end
407
+
408
+ def ipaddr?(addr)
409
+ !(IPAddr.new(addr) rescue nil).nil?
410
+ end
411
+
412
+ def verify(hostname, cert)
413
+ is_ipaddr = ipaddr?(hostname)
414
+ sans = extract_sans(cert, is_ipaddr ? 7 : 2)
415
+ cn = extract_cn(cert)
416
+ if sans
417
+ sans.each do |san|
418
+ return true if match_identify(hostname, san)
419
+ end
420
+ raise OpenSSL::SSL::SSLError.new("Certificate for <#{hostname}> doesn't match any of the subject alternative names: #{sans}")
421
+ elsif cn
422
+ return true if match_identify(hostname, cn)
423
+ raise OpenSSL::SSL::SSLError.new("Certificate for <#{hostname}> doesn't match common name of the certificate subject: #{cn}")
424
+ end
425
+ raise OpenSSL::SSL::SSLError.new("Certificate subject for for <#{hostname}> doesn't contain a common name and does not have alternative names")
426
+ end
427
+
428
+ def match_identify(hostname, identity)
429
+ if hostname.nil?
430
+ return false
431
+ end
432
+ hostname = hostname.downcase
433
+ identity = identity.downcase
434
+ parts = identity.split('.')
435
+ if parts.length >= 3 && parts.first.end_with?('*') && valid_country_wildcard(parts)
436
+ create_wildcard_regexp(identity) =~ hostname
437
+ else
438
+ hostname == identity
439
+ end
440
+ end
441
+
442
+ def create_wildcard_regexp(value)
443
+ # Escape first then search '\*' for meta-char interpolation
444
+ labels = value.split('.').map { |e| Regexp.escape(e) }
445
+ # Handle '*'s only at the left-most label, exclude A-label and U-label
446
+ labels[0].gsub!(/\\\*/, '[^.]+') if !labels[0].start_with?('xn\-\-') and labels[0].ascii_only?
447
+ /\A#{labels.join('\.')}\z/i
448
+ end
449
+
450
+ def valid_country_wildcard(parts)
451
+ if parts.length != 3 || parts[2].length != 2
452
+ true
453
+ else
454
+ !BAD_COUNTRY_2LDS.include?(parts[1])
455
+ end
456
+ end
457
+ end
458
+
459
+ def self.create_socket(session)
460
+ opts = {
461
+ :connect_timeout => session.connect_timeout * 1000,
462
+ # send_timeout is ignored in JRuby
463
+ :so_timeout => session.receive_timeout * 1000,
464
+ :tcp_keepalive => session.tcp_keepalive,
465
+ :debug_dev => session.debug_dev
466
+ }
467
+ socket = nil
468
+ begin
469
+ if session.proxy
470
+ site = session.proxy || session.dest
471
+ socket = JavaSocketWrap.connect(Socket.new, site, opts)
472
+ session.connect_ssl_proxy(JavaSocketWrap.new(socket), Util.urify(session.dest.to_s))
473
+ end
474
+ new(socket, session.dest, session.ssl_config, opts)
475
+ rescue
476
+ socket.close if socket
477
+ raise
478
+ end
479
+ end
480
+
481
+ DEFAULT_SSL_PROTOCOL = (java.lang.System.getProperty('java.specification.version') == '1.7') ? 'TLSv1.2' : 'TLS'
482
+ def initialize(socket, dest, config, opts = {})
483
+ @config = config
484
+ begin
485
+ @ssl_socket = create_ssl_socket(socket, dest, config, opts)
486
+ ssl_version = java_ssl_version(config)
487
+ @ssl_socket.setEnabledProtocols([ssl_version].to_java(java.lang.String)) if ssl_version != DEFAULT_SSL_PROTOCOL
488
+ if config.ciphers != SSLConfig::CIPHERS_DEFAULT
489
+ @ssl_socket.setEnabledCipherSuites(config.ciphers.to_java(java.lang.String))
490
+ end
491
+ ssl_connect(dest.host)
492
+ rescue java.security.GeneralSecurityException => e
493
+ raise OpenSSL::SSL::SSLError.new(e.getMessage)
494
+ rescue java.io.IOException => e
495
+ raise OpenSSL::SSL::SSLError.new("#{e.class}: #{e.getMessage}")
496
+ end
497
+
498
+ super(@ssl_socket, opts[:debug_dev])
499
+ end
500
+
501
+ def java_ssl_version(config)
502
+ if config.ssl_version == :auto
503
+ DEFAULT_SSL_PROTOCOL
504
+ else
505
+ config.ssl_version.to_s.tr('_', '.')
506
+ end
507
+ end
508
+
509
+ def create_ssl_context(config)
510
+ unless config.cert_store_crl_items.empty?
511
+ raise NotImplementedError.new('Manual CRL configuration is not yet supported')
512
+ end
513
+
514
+ km = nil
515
+ if config.client_cert && config.client_key
516
+ loader = KeyStoreLoader.new
517
+ loader.add(config.client_cert, config.client_key, config.client_key_pass)
518
+ kmf = KeyManagerFactory.getInstance(KeyManagerFactory.getDefaultAlgorithm)
519
+ kmf.init(loader.keystore, KeyStoreLoader::PASSWORD)
520
+ km = kmf.getKeyManagers
521
+ end
522
+
523
+ trust_store = nil
524
+ verify_callback = config.verify_callback || config.method(:default_verify_callback)
525
+ if !config.verify?
526
+ tmf = VerifyNoneTrustManagerFactory.new(verify_callback)
527
+ else
528
+ tmf = SystemTrustManagerFactory.new(verify_callback)
529
+ loader = TrustStoreLoader.new
530
+ config.cert_store_items.each do |item|
531
+ loader.add(item)
532
+ end
533
+ trust_store = loader.trust_store
534
+ end
535
+ tmf.init(trust_store)
536
+ tm = tmf.getTrustManagers
537
+
538
+ ctx = SSLContext.getInstance(java_ssl_version(config))
539
+ ctx.init(km, tm, nil)
540
+ if config.timeout
541
+ ctx.getClientSessionContext.setSessionTimeout(config.timeout)
542
+ end
543
+ ctx
544
+ end
545
+
546
+ def create_ssl_socket(socket, dest, config, opts)
547
+ ctx = create_ssl_context(config)
548
+ factory = ctx.getSocketFactory
549
+ if socket
550
+ ssl_socket = factory.createSocket(socket, dest.host, dest.port, true)
551
+ else
552
+ ssl_socket = factory.createSocket
553
+ JavaSocketWrap.connect(ssl_socket, dest, opts)
554
+ end
555
+ ssl_socket
556
+ end
557
+
558
+ def peer_cert
559
+ @peer_cert
560
+ end
561
+
562
+ private
563
+
564
+ def ssl_connect(hostname)
565
+ @ssl_socket.startHandshake
566
+ ssl_session = @ssl_socket.getSession
567
+ @peer_cert = JavaCertificate.new(ssl_session.getPeerCertificates.first)
568
+ if $DEBUG
569
+ warn("Protocol version: #{ssl_session.getProtocol}")
570
+ warn("Cipher: #{@ssl_socket.getSession.getCipherSuite}")
571
+ end
572
+ post_connection_check(hostname)
573
+ end
574
+
575
+ def post_connection_check(hostname)
576
+ if !@config.verify?
577
+ return
578
+ else
579
+ BrowserCompatHostnameVerifier.new.verify(hostname, @peer_cert.cert)
580
+ end
581
+ end
582
+ end
583
+
584
+ SSLSocket = JRubySSLSocket
585
+
586
+ end
587
+
588
+ end