httpclient 2.8.2.4 → 2.9.0

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
- SHA1:
3
- metadata.gz: 241dd999985ce751afe54cf45ca1d2df8a4b05c7
4
- data.tar.gz: 9a4021e0b3f9f1a9a40ecb56f48b139217d51621
2
+ SHA256:
3
+ metadata.gz: e1df0b78f53d502000683d048be1316f156247e5e17995f5fb04a125302bdb4e
4
+ data.tar.gz: d533eeaf2333f2f35820441a74cdf84075e5227d4fb0648f4e2ea4d2099bd511
5
5
  SHA512:
6
- metadata.gz: 2d306ba29a27b6e1e8507141b83a162c8b4c97ac03b4daf61982883be51ef0831cd79ff1d7e90047c5cda4ca1f775d6609d645a01a7ce289cb7e2a99519637d6
7
- data.tar.gz: c3fe5f9e0e6ab7b2e4afd0560ff2ec8f01e736d18dc66e431d6d3f1b89481e20acee6d4d4eadb8c2a6d03c27b6ecc3f0175e84dccaefa74e461615f579f93716
6
+ metadata.gz: 94024e0c5b5bd08800d9b3989151ab919869fabcaed65e4a375490fde0f6ea3b5bfc3ad4a5a9803bb057c5b8d36efc10c6ae5ade8a974c665d443730c63bc7ba
7
+ data.tar.gz: 768ae9ad96a73740675aca861a81075af3164a4b8875f81368a3228ecfdf523fe6c13cd9355bbe8ddd9155031ff1f908d8ec85e1bd112e0cd31d8b26d809dd6a
data/lib/hexdump.rb CHANGED
@@ -11,13 +11,13 @@ module HexDump
11
11
  result = []
12
12
  while raw = str.slice(offset, 16) and raw.length > 0
13
13
  # data field
14
- data = ''
14
+ data = ''.dup
15
15
  for v in raw.unpack('N* a*')
16
- if v.kind_of? Integer
17
- data << sprintf("%08x ", v)
18
- else
19
- v.each_byte {|c| data << sprintf("%02x", c) }
20
- end
16
+ if v.kind_of? Integer
17
+ data << sprintf("%08x ", v)
18
+ else
19
+ v.each_byte {|c| data << sprintf("%02x", c) }
20
+ end
21
21
  end
22
22
  # text field
23
23
  text = raw.tr("\000-\037\177-\377", ".")
@@ -25,12 +25,12 @@ module HexDump
25
25
  offset += 16
26
26
  # omit duplicate line
27
27
  if /^(#{regex_quote_n(raw)})+/n =~ str[offset .. -1]
28
- result << sprintf("%08x ...", offset)
29
- offset += $&.length
30
- # should print at the end
31
- if offset == str.length
32
- result << sprintf("%08x %-36s %s", offset-16, data, text)
33
- end
28
+ result << sprintf("%08x ...", offset)
29
+ offset += $&.length
30
+ # should print at the end
31
+ if offset == str.length
32
+ result << sprintf("%08x %-36s %s", offset-16, data, text)
33
+ end
34
34
  end
35
35
  end
36
36
  result
@@ -238,7 +238,7 @@ module HTTP
238
238
  if defined?(Encoding::ASCII_8BIT)
239
239
  def set_body_encoding
240
240
  if type = self.content_type
241
- OpenURI::Meta.init(o = '')
241
+ OpenURI::Meta.init(o = ''.dup)
242
242
  o.meta_add_field('content-type', type)
243
243
  @body_encoding = o.encoding
244
244
  end
@@ -491,7 +491,7 @@ module HTTP
491
491
  # String.
492
492
  #
493
493
  # assert: @size is not nil
494
- def dump(header = '', dev = '')
494
+ def dump(header = '', dev = ''.dup)
495
495
  if @body.is_a?(Parts)
496
496
  dev << header
497
497
  @body.parts.each do |part|
@@ -521,7 +521,7 @@ module HTTP
521
521
  # reason. (header is dumped to dev, too)
522
522
  # If no dev (the second argument) given, this method returns a dumped
523
523
  # String.
524
- def dump_chunked(header = '', dev = '')
524
+ def dump_chunked(header = '', dev = ''.dup)
525
525
  dev << header
526
526
  if @body.is_a?(Parts)
527
527
  @body.parts.each do |part|
@@ -574,7 +574,7 @@ module HTTP
574
574
  end
575
575
 
576
576
  def dump_file(io, dev, sz)
577
- buf = ''
577
+ buf = ''.dup
578
578
  rest = sz
579
579
  while rest > 0
580
580
  n = io.read([rest, @chunk_size].min, buf)
@@ -585,7 +585,7 @@ module HTTP
585
585
  end
586
586
 
587
587
  def dump_chunks(io, dev)
588
- buf = ''
588
+ buf = ''.dup
589
589
  while !io.read(@chunk_size, buf).nil?
590
590
  dev << dump_chunk(buf)
591
591
  end
@@ -618,8 +618,8 @@ module HTTP
618
618
  if Message.file?(part)
619
619
  @as_stream = true
620
620
  @body << part
621
- if part.respond_to?(:lstat)
622
- sz = part.lstat.size
621
+ if part.respond_to?(:stat)
622
+ sz = part.stat.size
623
623
  add_size(part, sz)
624
624
  elsif part.respond_to?(:size)
625
625
  if sz = part.size
@@ -954,7 +954,7 @@ module HTTP
954
954
 
955
955
  # Dumps message (header and body) to given dev.
956
956
  # dev needs to respond to <<.
957
- def dump(dev = '')
957
+ def dump(dev = ''.dup)
958
958
  str = @http_header.dump + CRLF
959
959
  if @http_header.chunked
960
960
  dev = @http_body.dump_chunked(str, dev)
@@ -15,9 +15,27 @@ class HTTPClient
15
15
  unless defined?(SSLSocket)
16
16
 
17
17
  class JavaSocketWrap
18
+ java_import 'java.net.InetSocketAddress'
18
19
  java_import 'java.io.BufferedInputStream'
20
+
19
21
  BUF_SIZE = 1024 * 16
20
22
 
23
+ def self.normalize_timeout(timeout)
24
+ [Java::JavaLang::Integer::MAX_VALUE, timeout].min
25
+ end
26
+
27
+ def self.connect(socket, site, opts = {})
28
+ socket_addr = InetSocketAddress.new(site.host, site.port)
29
+ if opts[:connect_timeout]
30
+ socket.connect(socket_addr, normalize_timeout(opts[:connect_timeout]))
31
+ else
32
+ socket.connect(socket_addr)
33
+ end
34
+ socket.setSoTimeout(normalize_timeout(opts[:so_timeout])) if opts[:so_timeout]
35
+ socket.setKeepAlive(true) if opts[:tcp_keepalive]
36
+ socket
37
+ end
38
+
21
39
  def initialize(socket, debug_dev = nil)
22
40
  @socket = socket
23
41
  @debug_dev = debug_dev
@@ -39,7 +57,6 @@ unless defined?(SSLSocket)
39
57
  @socket.isClosed
40
58
  end
41
59
 
42
-
43
60
  def gets(rs)
44
61
  while (size = @bufstr.index(rs)).nil?
45
62
  if fill() == -1
@@ -105,11 +122,15 @@ unless defined?(SSLSocket)
105
122
  private
106
123
 
107
124
  def fill
108
- size = @instr.read(@buf)
109
- if size > 0
110
- @bufstr << String.from_java_bytes(@buf, Encoding::BINARY)[0, size]
125
+ begin
126
+ size = @instr.read(@buf)
127
+ if size > 0
128
+ @bufstr << String.from_java_bytes(@buf, Encoding::BINARY)[0, size]
129
+ end
130
+ size
131
+ rescue java.io.IOException => e
132
+ raise OpenSSL::SSL::SSLError.new("#{e.class}: #{e.getMessage}")
111
133
  end
112
- size
113
134
  end
114
135
 
115
136
  def debug(str)
@@ -267,8 +288,8 @@ unless defined?(SSLSocket)
267
288
 
268
289
  module PEMUtils
269
290
  def self.read_certificate(pem)
270
- pem = pem.sub(/-----BEGIN CERTIFICATE-----/, '').sub(/-----END CERTIFICATE-----/, '')
271
- der = pem.unpack('m*').first
291
+ cert = pem.sub(/.*?-----BEGIN CERTIFICATE-----/m, '').sub(/-----END CERTIFICATE-----.*?/m, '')
292
+ der = cert.unpack('m*').first
272
293
  cf = CertificateFactory.getInstance('X.509')
273
294
  cf.generateCertificate(ByteArrayInputStream.new(der.to_java_bytes))
274
295
  end
@@ -440,27 +461,58 @@ unless defined?(SSLSocket)
440
461
  end
441
462
 
442
463
  def self.create_socket(session)
443
- site = session.proxy || session.dest
444
- socket = Socket.new(site.host, site.port)
464
+ opts = {
465
+ :connect_timeout => session.connect_timeout * 1000,
466
+ # send_timeout is ignored in JRuby
467
+ :so_timeout => session.receive_timeout * 1000,
468
+ :tcp_keepalive => session.tcp_keepalive,
469
+ :debug_dev => session.debug_dev
470
+ }
471
+ socket = nil
445
472
  begin
446
473
  if session.proxy
474
+ site = session.proxy || session.dest
475
+ socket = JavaSocketWrap.connect(Socket.new, site, opts)
447
476
  session.connect_ssl_proxy(JavaSocketWrap.new(socket), Util.urify(session.dest.to_s))
448
477
  end
478
+ new(socket, session.dest, session.ssl_config, opts)
449
479
  rescue
450
- socket.close
480
+ socket.close if socket
451
481
  raise
452
482
  end
453
- new(socket, session.dest, session.ssl_config, session.debug_dev)
454
483
  end
455
484
 
456
485
  DEFAULT_SSL_PROTOCOL = (java.lang.System.getProperty('java.specification.version') == '1.7') ? 'TLSv1.2' : 'TLS'
457
- def initialize(socket, dest, config, debug_dev = nil)
486
+ def initialize(socket, dest, config, opts = {})
458
487
  @config = config
488
+ begin
489
+ @ssl_socket = create_ssl_socket(socket, dest, config, opts)
490
+ ssl_version = java_ssl_version(config)
491
+ @ssl_socket.setEnabledProtocols([ssl_version].to_java(java.lang.String)) if ssl_version != DEFAULT_SSL_PROTOCOL
492
+ if config.ciphers != SSLConfig::CIPHERS_DEFAULT
493
+ @ssl_socket.setEnabledCipherSuites(config.ciphers.to_java(java.lang.String))
494
+ end
495
+ ssl_connect(dest.host)
496
+ rescue java.security.GeneralSecurityException => e
497
+ raise OpenSSL::SSL::SSLError.new(e.getMessage)
498
+ rescue java.net.SocketTimeoutException => e
499
+ raise HTTPClient::ConnectTimeoutError.new(e.getMessage)
500
+ rescue java.io.IOException => e
501
+ raise OpenSSL::SSL::SSLError.new("#{e.class}: #{e.getMessage}")
502
+ end
503
+
504
+ super(@ssl_socket, opts[:debug_dev])
505
+ end
506
+
507
+ def java_ssl_version(config)
459
508
  if config.ssl_version == :auto
460
- ssl_version = DEFAULT_SSL_PROTOCOL
509
+ DEFAULT_SSL_PROTOCOL
461
510
  else
462
- ssl_version = config.ssl_version.to_s.tr('_', '.')
511
+ config.ssl_version.to_s.tr('_', '.')
463
512
  end
513
+ end
514
+
515
+ def create_ssl_context(config)
464
516
  unless config.cert_store_crl_items.empty?
465
517
  raise NotImplementedError.new('Manual CRL configuration is not yet supported')
466
518
  end
@@ -489,36 +541,24 @@ unless defined?(SSLSocket)
489
541
  tmf.init(trust_store)
490
542
  tm = tmf.getTrustManagers
491
543
 
492
- ctx = SSLContext.getInstance(ssl_version)
544
+ ctx = SSLContext.getInstance(java_ssl_version(config))
493
545
  ctx.init(km, tm, nil)
494
546
  if config.timeout
495
547
  ctx.getClientSessionContext.setSessionTimeout(config.timeout)
496
548
  end
549
+ ctx
550
+ end
497
551
 
552
+ def create_ssl_socket(socket, dest, config, opts)
553
+ ctx = create_ssl_context(config)
498
554
  factory = ctx.getSocketFactory
499
- begin
500
- ssl_socket = factory.createSocket(socket, dest.host, dest.port, true)
501
- ssl_socket.setEnabledProtocols([ssl_version].to_java(java.lang.String)) if ssl_version != DEFAULT_SSL_PROTOCOL
502
- if config.ciphers != SSLConfig::CIPHERS_DEFAULT
503
- ssl_socket.setEnabledCipherSuites(config.ciphers.to_java(java.lang.String))
504
- end
505
- ssl_socket.startHandshake
506
- ssl_session = ssl_socket.getSession
507
- @peer_cert = JavaCertificate.new(ssl_session.getPeerCertificates.first)
508
- if $DEBUG
509
- warn("Protocol version: #{ssl_session.getProtocol}")
510
- warn("Cipher: #{ssl_socket.getSession.getCipherSuite}")
511
- end
512
- post_connection_check(dest.host, @peer_cert)
513
- rescue java.security.GeneralSecurityException => e
514
- raise OpenSSL::SSL::SSLError.new(e.getMessage)
515
- rescue javax.net.ssl.SSLException => e
516
- raise OpenSSL::SSL::SSLError.new(e.getMessage)
517
- rescue java.net.SocketException => e
518
- raise OpenSSL::SSL::SSLError.new(e.getMessage)
555
+ unless socket
556
+ # Create a plain socket first to set connection timeouts on,
557
+ # then wrap it in a SSL socket so that SNI gets setup on it.
558
+ socket = javax.net.SocketFactory.getDefault.createSocket
559
+ JavaSocketWrap.connect(socket, dest, opts)
519
560
  end
520
-
521
- super(ssl_socket, debug_dev)
561
+ factory.createSocket(socket, dest.host, dest.port, true)
522
562
  end
523
563
 
524
564
  def peer_cert
@@ -527,11 +567,22 @@ unless defined?(SSLSocket)
527
567
 
528
568
  private
529
569
 
530
- def post_connection_check(hostname, wrap_cert)
570
+ def ssl_connect(hostname)
571
+ @ssl_socket.startHandshake
572
+ ssl_session = @ssl_socket.getSession
573
+ @peer_cert = JavaCertificate.new(ssl_session.getPeerCertificates.first)
574
+ if $DEBUG
575
+ warn("Protocol version: #{ssl_session.getProtocol}")
576
+ warn("Cipher: #{@ssl_socket.getSession.getCipherSuite}")
577
+ end
578
+ post_connection_check(hostname)
579
+ end
580
+
581
+ def post_connection_check(hostname)
531
582
  if !@config.verify?
532
583
  return
533
584
  else
534
- BrowserCompatHostnameVerifier.new.verify(hostname, wrap_cert.cert)
585
+ BrowserCompatHostnameVerifier.new.verify(hostname, @peer_cert.cert)
535
586
  end
536
587
  end
537
588
  end
@@ -21,7 +21,7 @@ require 'zlib'
21
21
  require 'httpclient/timeout' # TODO: remove this once we drop 1.8 support
22
22
  require 'httpclient/ssl_config'
23
23
  require 'httpclient/http'
24
- if RUBY_ENGINE == 'jruby'
24
+ if defined? JRUBY_VERSION
25
25
  require 'httpclient/jruby_ssl_socket'
26
26
  else
27
27
  require 'httpclient/ssl_socket'
@@ -76,7 +76,7 @@ class HTTPClient
76
76
  def to_s # :nodoc:
77
77
  addr
78
78
  end
79
-
79
+
80
80
  # Returns true if scheme, host and port of the given URI matches with this.
81
81
  def match(uri)
82
82
  (@scheme == uri.scheme) and (@host == uri.host) and (@port == uri.port.to_i)
@@ -105,6 +105,8 @@ class HTTPClient
105
105
  attr_accessor :debug_dev
106
106
  # Boolean value for Socket#sync
107
107
  attr_accessor :socket_sync
108
+ # Boolean value to send TCP keepalive packets; no timing settings exist at present
109
+ attr_accessor :tcp_keepalive
108
110
 
109
111
  attr_accessor :connect_timeout
110
112
  # Maximum retry count. 0 for infinite.
@@ -137,6 +139,7 @@ class HTTPClient
137
139
  @protocol_version = nil
138
140
  @debug_dev = client.debug_dev
139
141
  @socket_sync = true
142
+ @tcp_keepalive = false
140
143
  @chunk_size = ::HTTP::Message::Body::DEFAULT_CHUNK_SIZE
141
144
 
142
145
  @connect_timeout = 60
@@ -216,6 +219,7 @@ class HTTPClient
216
219
  sess = Session.new(@client, site, @agent_name, @from)
217
220
  sess.proxy = via_proxy ? @proxy : nil
218
221
  sess.socket_sync = @socket_sync
222
+ sess.tcp_keepalive = @tcp_keepalive
219
223
  sess.requested_version = @protocol_version if @protocol_version
220
224
  sess.connect_timeout = @connect_timeout
221
225
  sess.connect_retry = @connect_retry
@@ -437,6 +441,8 @@ class HTTPClient
437
441
  attr_accessor :proxy
438
442
  # Boolean value for Socket#sync
439
443
  attr_accessor :socket_sync
444
+ # Boolean value to send TCP keepalive packets; no timing settings exist at present
445
+ attr_accessor :tcp_keepalive
440
446
  # Requested protocol version
441
447
  attr_accessor :requested_version
442
448
  # Device for dumping log for debugging
@@ -464,6 +470,7 @@ class HTTPClient
464
470
  @dest = dest
465
471
  @proxy = nil
466
472
  @socket_sync = true
473
+ @tcp_keepalive = false
467
474
  @requested_version = nil
468
475
 
469
476
  @debug_dev = nil
@@ -606,17 +613,16 @@ class HTTPClient
606
613
  clean_local = @socket_local.host.delete("[]")
607
614
  socket = TCPSocket.new(clean_host, port, clean_local, @socket_local.port)
608
615
  end
616
+ socket.setsockopt(Socket::SOL_SOCKET, Socket::SO_KEEPALIVE, true) if @tcp_keepalive
609
617
  if @debug_dev
610
618
  @debug_dev << "! CONNECTION ESTABLISHED\n"
611
619
  socket.extend(DebugSocket)
612
620
  socket.debug_dev = @debug_dev
613
621
  end
614
622
  rescue SystemCallError => e
615
- e.message << " (#{host}:#{port})"
616
- raise
623
+ raise e.class, e.message + " (#{host}:#{port})"
617
624
  rescue SocketError => e
618
- e.message << " (#{host}:#{port})"
619
- raise
625
+ raise e.class, e.message + " (#{host}:#{port})"
620
626
  end
621
627
  socket
622
628
  end
@@ -944,7 +950,7 @@ class HTTPClient
944
950
  end
945
951
 
946
952
  def empty_bin_str
947
- str = ''
953
+ str = ''.dup
948
954
  str.force_encoding('BINARY') if str.respond_to?(:force_encoding)
949
955
  str
950
956
  end