httpclient 2.6.0.1 → 2.7.0

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.
@@ -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;
@@ -20,6 +20,11 @@ require 'zlib'
20
20
  require 'httpclient/timeout' # TODO: remove this once we drop 1.8 support
21
21
  require 'httpclient/ssl_config'
22
22
  require 'httpclient/http'
23
+ if defined?(JRuby)
24
+ require 'httpclient/jruby_ssl_socket'
25
+ else
26
+ require 'httpclient/ssl_socket'
27
+ end
23
28
 
24
29
 
25
30
  class HTTPClient
@@ -288,131 +293,6 @@ class HTTPClient
288
293
  end
289
294
 
290
295
 
291
- # Wraps up OpenSSL::SSL::SSLSocket and offers debugging features.
292
- class SSLSocketWrap
293
- def initialize(socket, context, debug_dev = nil)
294
- unless SSLEnabled
295
- raise ConfigurationError.new('Ruby/OpenSSL module is required')
296
- end
297
- @context = context
298
- @socket = socket
299
- @ssl_socket = create_openssl_socket(@socket)
300
- @debug_dev = debug_dev
301
- end
302
-
303
- def ssl_connect(hostname = nil)
304
- if hostname && @ssl_socket.respond_to?(:hostname=)
305
- @ssl_socket.hostname = hostname
306
- end
307
- @ssl_socket.connect
308
- end
309
-
310
- def post_connection_check(host)
311
- verify_mode = @context.verify_mode || OpenSSL::SSL::VERIFY_NONE
312
- if verify_mode == OpenSSL::SSL::VERIFY_NONE
313
- return
314
- elsif @ssl_socket.peer_cert.nil? and
315
- check_mask(verify_mode, OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT)
316
- raise OpenSSL::SSL::SSLError.new('no peer cert')
317
- end
318
- hostname = host.host
319
- if @ssl_socket.respond_to?(:post_connection_check) and RUBY_VERSION > "1.8.4"
320
- @ssl_socket.post_connection_check(hostname)
321
- else
322
- @context.post_connection_check(@ssl_socket.peer_cert, hostname)
323
- end
324
- end
325
-
326
- def ssl_version
327
- @ssl_socket.ssl_version if @ssl_socket.respond_to?(:ssl_version)
328
- end
329
-
330
- def ssl_cipher
331
- @ssl_socket.cipher
332
- end
333
-
334
- def ssl_state
335
- @ssl_socket.state
336
- end
337
-
338
- def peer_cert
339
- @ssl_socket.peer_cert
340
- end
341
-
342
- def close
343
- @ssl_socket.close
344
- @socket.close
345
- end
346
-
347
- def closed?
348
- @socket.closed?
349
- end
350
-
351
- def eof?
352
- @ssl_socket.eof?
353
- end
354
-
355
- def gets(*args)
356
- str = @ssl_socket.gets(*args)
357
- debug(str)
358
- str
359
- end
360
-
361
- def read(*args)
362
- str = @ssl_socket.read(*args)
363
- debug(str)
364
- str
365
- end
366
-
367
- def readpartial(*args)
368
- str = @ssl_socket.readpartial(*args)
369
- debug(str)
370
- str
371
- end
372
-
373
- def <<(str)
374
- rv = @ssl_socket.write(str)
375
- debug(str)
376
- rv
377
- end
378
-
379
- def flush
380
- @ssl_socket.flush
381
- end
382
-
383
- def sync
384
- @ssl_socket.sync
385
- end
386
-
387
- def sync=(sync)
388
- @ssl_socket.sync = sync
389
- end
390
-
391
- private
392
-
393
- def check_mask(value, mask)
394
- value & mask == mask
395
- end
396
-
397
- def create_openssl_socket(socket)
398
- ssl_socket = nil
399
- if OpenSSL::SSL.const_defined?("SSLContext")
400
- ctx = OpenSSL::SSL::SSLContext.new
401
- @context.set_context(ctx)
402
- ssl_socket = OpenSSL::SSL::SSLSocket.new(socket, ctx)
403
- else
404
- ssl_socket = OpenSSL::SSL::SSLSocket.new(socket)
405
- @context.set_context(ssl_socket)
406
- end
407
- ssl_socket
408
- end
409
-
410
- def debug(str)
411
- @debug_dev << str if @debug_dev && str
412
- end
413
- end
414
-
415
-
416
296
  # Wraps up a Socket for method interception.
417
297
  module SocketWrap
418
298
  def initialize(socket, *args)
@@ -432,20 +312,20 @@ class HTTPClient
432
312
  @socket.eof?
433
313
  end
434
314
 
435
- def gets(*args)
436
- @socket.gets(*args)
315
+ def gets(rs)
316
+ @socket.gets(rs)
437
317
  end
438
318
 
439
- def read(*args)
440
- @socket.read(*args)
319
+ def read(size, buf = nil)
320
+ @socket.read(size, buf)
441
321
  end
442
322
 
443
- def readpartial(*args)
323
+ def readpartial(size, buf = nil)
444
324
  # StringIO doesn't support :readpartial
445
325
  if @socket.respond_to?(:readpartial)
446
- @socket.readpartial(*args)
326
+ @socket.readpartial(size, buf)
447
327
  else
448
- @socket.read(*args)
328
+ @socket.read(size, buf)
449
329
  end
450
330
  end
451
331
 
@@ -481,19 +361,19 @@ class HTTPClient
481
361
  debug("! CONNECTION CLOSED\n")
482
362
  end
483
363
 
484
- def gets(*args)
364
+ def gets(rs)
485
365
  str = super
486
366
  debug(str)
487
367
  str
488
368
  end
489
369
 
490
- def read(*args)
370
+ def read(size, buf = nil)
491
371
  str = super
492
372
  debug(str)
493
373
  str
494
374
  end
495
375
 
496
- def readpartial(*args)
376
+ def readpartial(size, buf = nil)
497
377
  str = super
498
378
  debug(str)
499
379
  str
@@ -533,6 +413,10 @@ class HTTPClient
533
413
  def <<(str)
534
414
  # ignored
535
415
  end
416
+
417
+ def peer_cert
418
+ nil
419
+ end
536
420
  end
537
421
 
538
422
 
@@ -679,18 +563,8 @@ class HTTPClient
679
563
  begin
680
564
  read_header if @state == :META
681
565
  return nil if @state != :DATA
682
- if @gzipped and @transparent_gzip_decompression
683
- # zlib itself has a functionality to decompress gzip stream.
684
- # - zlib 1.2.5 Manual
685
- # http://www.zlib.net/manual.html#Advanced
686
- # > windowBits can also be greater than 15 for optional gzip decoding. Add 32 to
687
- # > windowBits to enable zlib and gzip decoding with automatic header detection,
688
- # > or add 16 to decode only the gzip format
689
- inflate_stream = Zlib::Inflate.new(Zlib::MAX_WBITS + 32)
690
- original_block = block
691
- block = Proc.new { |buf|
692
- original_block.call(inflate_stream.inflate(buf))
693
- }
566
+ if @transparent_gzip_decompression
567
+ block = content_inflater_block(@content_encoding, block)
694
568
  end
695
569
  if @chunked
696
570
  read_body_chunked(&block)
@@ -713,8 +587,122 @@ class HTTPClient
713
587
  nil
714
588
  end
715
589
 
590
+ def create_socket(host, port)
591
+ socket = nil
592
+ begin
593
+ @debug_dev << "! CONNECT TO #{host}:#{port}\n" if @debug_dev
594
+ clean_host = host.delete("[]")
595
+ if @socket_local == Site::EMPTY
596
+ socket = TCPSocket.new(clean_host, port)
597
+ else
598
+ clean_local = @socket_local.host.delete("[]")
599
+ socket = TCPSocket.new(clean_host, port, clean_local, @socket_local.port)
600
+ end
601
+ if @debug_dev
602
+ @debug_dev << "! CONNECTION ESTABLISHED\n"
603
+ socket.extend(DebugSocket)
604
+ socket.debug_dev = @debug_dev
605
+ end
606
+ rescue SystemCallError => e
607
+ e.message << " (#{host}:#{port})"
608
+ raise
609
+ rescue SocketError => e
610
+ e.message << " (#{host}:#{port})"
611
+ raise
612
+ end
613
+ socket
614
+ end
615
+
616
+ def create_loopback_socket(host, port, str)
617
+ @debug_dev << "! CONNECT TO #{host}:#{port}\n" if @debug_dev
618
+ socket = LoopBackSocket.new(host, port, str)
619
+ if @debug_dev
620
+ @debug_dev << "! CONNECTION ESTABLISHED\n"
621
+ socket.extend(DebugSocket)
622
+ socket.debug_dev = @debug_dev
623
+ end
624
+ if https?(@dest) && @proxy
625
+ connect_ssl_proxy(socket, Util.urify(@dest.to_s))
626
+ end
627
+ socket
628
+ end
629
+
630
+ def connect_ssl_proxy(socket, uri)
631
+ req = HTTP::Message.new_connect_request(uri)
632
+ @client.request_filter.each do |filter|
633
+ filter.filter_request(req)
634
+ end
635
+ set_header(req)
636
+ req.dump(socket)
637
+ socket.flush unless @socket_sync
638
+ res = HTTP::Message.new_response('')
639
+ parse_header(socket)
640
+ res.http_version, res.status, res.reason = @version, @status, @reason
641
+ @headers.each do |key, value|
642
+ res.header.set(key.to_s, value)
643
+ end
644
+ commands = @client.request_filter.collect { |filter|
645
+ filter.filter_response(req, res)
646
+ }
647
+ if commands.find { |command| command == :retry }
648
+ raise RetryableResponse.new(res)
649
+ end
650
+ unless @status == 200
651
+ raise BadResponseError.new("connect to ssl proxy failed with status #{@status} #{@reason}", res)
652
+ end
653
+ end
654
+
716
655
  private
717
656
 
657
+ # This inflater allows deflate compression with/without zlib header
658
+ class LenientInflater
659
+ def initialize
660
+ @inflater = Zlib::Inflate.new(Zlib::MAX_WBITS)
661
+ @first = true
662
+ end
663
+
664
+ def inflate(body)
665
+ if @first
666
+ first_inflate(body)
667
+ else
668
+ @inflater.inflate(body)
669
+ end
670
+ end
671
+
672
+ private
673
+
674
+ def first_inflate(body)
675
+ @first = false
676
+ begin
677
+ @inflater.inflate(body)
678
+ rescue Zlib::DataError
679
+ # fallback to deflate without zlib header
680
+ @inflater = Zlib::Inflate.new(-Zlib::MAX_WBITS)
681
+ @inflater.inflate(body)
682
+ end
683
+ end
684
+ end
685
+
686
+ def content_inflater_block(content_encoding, block)
687
+ case content_encoding
688
+ when 'gzip', 'x-gzip'
689
+ # zlib itself has a functionality to decompress gzip stream.
690
+ # - zlib 1.2.5 Manual
691
+ # http://www.zlib.net/manual.html#Advanced
692
+ # > windowBits can also be greater than 15 for optional gzip decoding. Add 32 to
693
+ # > windowBits to enable zlib and gzip decoding with automatic header detection,
694
+ # > or add 16 to decode only the gzip format
695
+ inflate_stream = Zlib::Inflate.new(Zlib::MAX_WBITS + 32)
696
+ when 'deflate'
697
+ inflate_stream = LenientInflater.new
698
+ else
699
+ return block
700
+ end
701
+ Proc.new { |buf|
702
+ block.call(inflate_stream.inflate(buf))
703
+ }
704
+ end
705
+
718
706
  def set_header(req)
719
707
  if @requested_version
720
708
  if /^(?:HTTP\/|)(\d+.\d+)$/ =~ @requested_version
@@ -744,29 +732,14 @@ class HTTPClient
744
732
  retry_number = 0
745
733
  begin
746
734
  timeout(@connect_timeout, ConnectTimeoutError) do
747
- @socket = create_socket(site)
748
- if https?(@dest)
749
- if @socket.is_a?(LoopBackSocket)
750
- connect_ssl_proxy(@socket, urify(@dest.to_s)) if @proxy
751
- else
752
- @socket = create_ssl_socket(@socket)
753
- connect_ssl_proxy(@socket, urify(@dest.to_s)) if @proxy
754
- begin
755
- @socket.ssl_connect(@dest.host)
756
- ensure
757
- if $DEBUG
758
- warn("Protocol version: #{@socket.ssl_version}")
759
- warn("Cipher: #{@socket.ssl_cipher.inspect}")
760
- warn("State: #{@socket.ssl_state}")
761
- end
762
- end
763
- @socket.post_connection_check(@dest)
764
- @ssl_peer_cert = @socket.peer_cert
765
- end
735
+ if str = @test_loopback_http_response.shift
736
+ @socket = create_loopback_socket(site.host, site.port, str)
737
+ elsif https?(@dest)
738
+ @socket = SSLSocket.create_socket(self)
739
+ @ssl_peer_cert = @socket.peer_cert
740
+ else
741
+ @socket = create_socket(site.host, site.port)
766
742
  end
767
- # Use Ruby internal buffering instead of passing data immediately
768
- # to the underlying layer
769
- # => we need to to call explicitly flush on the socket
770
743
  @socket.sync = @socket_sync
771
744
  end
772
745
  rescue RetryableResponse
@@ -788,71 +761,13 @@ class HTTPClient
788
761
  @state = :WAIT
789
762
  end
790
763
 
791
- def create_socket(site)
792
- socket = nil
793
- begin
794
- @debug_dev << "! CONNECT TO #{site.host}:#{site.port}\n" if @debug_dev
795
- clean_host = site.host.delete("[]")
796
- if str = @test_loopback_http_response.shift
797
- socket = LoopBackSocket.new(clean_host, site.port, str)
798
- elsif @socket_local == Site::EMPTY
799
- socket = TCPSocket.new(clean_host, site.port)
800
- else
801
- clean_local = @socket_local.host.delete("[]")
802
- socket = TCPSocket.new(clean_host, site.port, clean_local, @socket_local.port)
803
- end
804
- if @debug_dev
805
- @debug_dev << "! CONNECTION ESTABLISHED\n"
806
- socket.extend(DebugSocket)
807
- socket.debug_dev = @debug_dev
808
- end
809
- rescue SystemCallError => e
810
- e.message << " (#{site})"
811
- raise
812
- rescue SocketError => e
813
- e.message << " (#{site})"
814
- raise
815
- end
816
- socket
817
- end
818
-
819
- # wrap socket with OpenSSL.
820
- def create_ssl_socket(raw_socket)
821
- SSLSocketWrap.new(raw_socket, @ssl_config, @debug_dev)
822
- end
823
-
824
- def connect_ssl_proxy(socket, uri)
825
- req = HTTP::Message.new_connect_request(uri)
826
- @client.request_filter.each do |filter|
827
- filter.filter_request(req)
828
- end
829
- set_header(req)
830
- req.dump(@socket)
831
- @socket.flush unless @socket_sync
832
- res = HTTP::Message.new_response('')
833
- parse_header
834
- res.http_version, res.status, res.reason = @version, @status, @reason
835
- @headers.each do |key, value|
836
- res.header.set(key.to_s, value)
837
- end
838
- commands = @client.request_filter.collect { |filter|
839
- filter.filter_response(req, res)
840
- }
841
- if commands.find { |command| command == :retry }
842
- raise RetryableResponse.new(res)
843
- end
844
- unless @status == 200
845
- raise BadResponseError.new("connect to ssl proxy failed with status #{@status} #{@reason}", res)
846
- end
847
- end
848
-
849
764
  # Read status block.
850
765
  def read_header
851
766
  @content_length = nil
852
767
  @chunked = false
853
- @gzipped = false
768
+ @content_encoding = nil
854
769
  @chunk_length = 0
855
- parse_header
770
+ parse_header(@socket)
856
771
  # Header of the request has been parsed.
857
772
  @state = :DATA
858
773
  req = @requests.shift
@@ -868,12 +783,12 @@ class HTTPClient
868
783
  end
869
784
 
870
785
  StatusParseRegexp = %r(\AHTTP/(\d+\.\d+)\s+(\d\d\d)\s*([^\r\n]+)?\r?\n\z)
871
- def parse_header
786
+ def parse_header(socket)
872
787
  timeout(@receive_timeout, ReceiveTimeoutError) do
873
788
  initial_line = nil
874
789
  begin
875
790
  begin
876
- initial_line = @socket.gets("\n")
791
+ initial_line = socket.gets("\n")
877
792
  if initial_line.nil?
878
793
  close
879
794
  raise KeepAliveDisconnected.new(self)
@@ -896,7 +811,7 @@ class HTTPClient
896
811
  @next_connection = HTTP::Message.keep_alive_enabled?(@version)
897
812
  @headers = []
898
813
  while true
899
- line = @socket.gets("\n")
814
+ line = socket.gets("\n")
900
815
  unless line
901
816
  raise BadResponseError.new('unexpected EOF')
902
817
  end
@@ -908,7 +823,7 @@ class HTTPClient
908
823
  last << line.strip
909
824
  else
910
825
  key, value = line.strip.split(/\s*:\s*/, 2)
911
- parse_keepalive_header(key, value)
826
+ parse_content_header(key, value)
912
827
  @headers << [key, value]
913
828
  end
914
829
  end
@@ -921,18 +836,20 @@ class HTTPClient
921
836
  ((status >= 100 && status < 200) || status == 204 || status == 304)
922
837
  end
923
838
 
924
- def parse_keepalive_header(key, value)
839
+ def parse_content_header(key, value)
925
840
  key = key.downcase
926
- if key == 'content-length'
841
+ case key
842
+ when 'content-length'
927
843
  @content_length = value.to_i
928
- elsif key == 'content-encoding' and ( value.downcase == 'gzip' or
929
- value.downcase == 'x-gzip' or value.downcase == 'deflate' )
930
- @gzipped = true
931
- elsif key == 'transfer-encoding' and value.downcase == 'chunked'
932
- @chunked = true
933
- @chunk_length = 0
934
- @content_length = nil
935
- elsif key == 'connection' or key == 'proxy-connection'
844
+ when 'content-encoding'
845
+ @content_encoding = value.downcase
846
+ when 'transfer-encoding'
847
+ if value.downcase == 'chunked'
848
+ @chunked = true
849
+ @chunk_length = 0
850
+ @content_length = nil
851
+ end
852
+ when 'connection', 'proxy-connection'
936
853
  if value.downcase == 'keep-alive'
937
854
  @next_connection = true
938
855
  else