Object
# File lib/httpclient/session.rb, line 485 485: def initialize(client, dest, agent_name, from) 486: @client = client 487: @dest = dest 488: @proxy = nil 489: @socket_sync = true 490: @requested_version = nil 491: 492: @debug_dev = nil 493: 494: @connect_timeout = nil 495: @connect_retry = 1 496: @send_timeout = nil 497: @receive_timeout = nil 498: @read_block_size = nil 499: @protocol_retry_count = 5 500: 501: @ssl_config = nil 502: @ssl_peer_cert = nil 503: 504: @test_loopback_http_response = nil 505: 506: @agent_name = agent_name 507: @from = from 508: @state = :INIT 509: 510: @requests = [] 511: 512: @status = nil 513: @reason = nil 514: @headers = [] 515: 516: @socket = nil 517: @readbuf = nil 518: end
# File lib/httpclient/session.rb, line 550 550: def close 551: if !@socket.nil? and !@socket.closed? 552: # @socket.flush may block when it the socket is already closed by 553: # foreign host and the client runs under MT-condition. 554: @socket.close 555: end 556: @state = :INIT 557: end
# File lib/httpclient/session.rb, line 559 559: def closed? 560: @state == :INIT 561: end
# File lib/httpclient/session.rb, line 576 576: def eof? 577: if !@content_length.nil? 578: @content_length == 0 579: else 580: @socket.closed? or @socket.eof? 581: end 582: end
# File lib/httpclient/session.rb, line 584 584: def get_body(&block) 585: begin 586: read_header if @state == :META 587: return nil if @state != :DATA 588: if @chunked 589: read_body_chunked(&block) 590: elsif @content_length 591: read_body_length(&block) 592: else 593: read_body_rest(&block) 594: end 595: rescue 596: close 597: raise 598: end 599: if eof? 600: if @next_connection 601: @state = :WAIT 602: else 603: close 604: end 605: end 606: nil 607: end
# File lib/httpclient/session.rb, line 563 563: def get_header 564: begin 565: if @state != :META 566: raise RuntimeError.new("get_status must be called at the beginning of a session") 567: end 568: read_header 569: rescue 570: close 571: raise 572: end 573: [@version, @status, @reason, @headers] 574: end
Send a request to the server
# File lib/httpclient/session.rb, line 521 521: def query(req) 522: connect if @state == :INIT 523: req.header.request_via_proxy = !@proxy.nil? 524: begin 525: timeout(@send_timeout, SendTimeoutError) do 526: set_header(req) 527: req.dump(@socket) 528: # flush the IO stream as IO::sync mode is false 529: @socket.flush unless @socket_sync 530: end 531: rescue Errno::ECONNABORTED, Errno::ECONNRESET, Errno::EPIPE 532: close 533: raise KeepAliveDisconnected.new 534: rescue HTTPClient::TimeoutError 535: close 536: raise 537: rescue 538: if SSLEnabled and $!.is_a?(OpenSSL::SSL::SSLError) 539: raise KeepAliveDisconnected.new 540: else 541: raise 542: end 543: end 544: 545: @state = :META if @state == :WAIT 546: @next_connection = nil 547: @requests.push(req) 548: end
Connect to the server
# File lib/httpclient/session.rb, line 627 627: def connect 628: site = @proxy || @dest 629: retry_number = 0 630: begin 631: timeout(@connect_timeout, ConnectTimeoutError) do 632: @socket = create_socket(site) 633: if @dest.scheme == 'https' 634: if @socket.is_a?(LoopBackSocket) 635: connect_ssl_proxy(@socket, URI.parse(@dest.to_s)) if @proxy 636: else 637: @socket = create_ssl_socket(@socket) 638: connect_ssl_proxy(@socket, URI.parse(@dest.to_s)) if @proxy 639: @socket.ssl_connect 640: @socket.post_connection_check(@dest) 641: @ssl_peer_cert = @socket.peer_cert 642: end 643: end 644: # Use Ruby internal buffering instead of passing data immediately 645: # to the underlying layer 646: # => we need to to call explicitly flush on the socket 647: @socket.sync = @socket_sync 648: end 649: rescue RetryableResponse 650: retry_number += 1 651: if retry_number < @protocol_retry_count 652: retry 653: end 654: raise BadResponseError.new("connect to the server failed with status #{@status} #{@reason}") 655: rescue TimeoutError 656: if @connect_retry == 0 657: retry 658: else 659: retry_number += 1 660: retry if retry_number < @connect_retry 661: end 662: close 663: raise 664: end 665: @state = :WAIT 666: end
# File lib/httpclient/session.rb, line 697 697: def connect_ssl_proxy(socket, uri) 698: req = HTTP::Message.new_connect_request(uri) 699: @client.request_filter.each do |filter| 700: filter.filter_request(req) 701: end 702: set_header(req) 703: req.dump(@socket) 704: @socket.flush unless @socket_sync 705: res = HTTP::Message.new_response('') 706: parse_header 707: res.version, res.status, res.reason = @version, @status, @reason 708: @headers.each do |key, value| 709: res.header.set(key, value) 710: end 711: commands = @client.request_filter.collect { |filter| 712: filter.filter_response(req, res) 713: } 714: if commands.find { |command| command == :retry } 715: raise RetryableResponse.new 716: end 717: unless @status == 200 718: raise BadResponseError.new("connect to ssl proxy failed with status #{@status} #{@reason}", res) 719: end 720: end
# File lib/httpclient/session.rb, line 668 668: def create_socket(site) 669: socket = nil 670: begin 671: @debug_dev << "! CONNECT TO #{site.host}:#{site.port}\n" if @debug_dev 672: if str = @test_loopback_http_response.shift 673: socket = LoopBackSocket.new(site.host, site.port, str) 674: else 675: socket = TCPSocket.new(site.host, site.port) 676: end 677: if @debug_dev 678: @debug_dev << "! CONNECTION ESTABLISHED\n" 679: socket.extend(DebugSocket) 680: socket.debug_dev = @debug_dev 681: end 682: rescue SystemCallError => e 683: e.message << " (#{site})" 684: raise 685: rescue SocketError => e 686: e.message << " (#{site})" 687: raise 688: end 689: socket 690: end
wrap socket with OpenSSL.
# File lib/httpclient/session.rb, line 693 693: def create_ssl_socket(raw_socket) 694: SSLSocketWrap.new(raw_socket, @ssl_config, @debug_dev) 695: end
# File lib/httpclient/session.rb, line 745 745: def parse_header 746: timeout(@receive_timeout, ReceiveTimeoutError) do 747: begin 748: initial_line = @socket.gets("\n") 749: if initial_line.nil? 750: raise KeepAliveDisconnected.new 751: end 752: if StatusParseRegexp !~ initial_line 753: @version = '0.9' 754: @status = nil 755: @reason = nil 756: @next_connection = false 757: @content_length = nil 758: @readbuf = initial_line 759: break 760: end 761: @version, @status, @reason = $1, $2.to_i, $3 762: @next_connection = HTTP::Message.keep_alive_enabled?(@version.to_f) 763: @headers = [] 764: while true 765: line = @socket.gets("\n") 766: unless line 767: raise BadResponseError.new('unexpected EOF') 768: end 769: line.chomp! 770: break if line.empty? 771: key, value = line.split(/\s*:\s*/, 2) 772: parse_keepalive_header(key, value) 773: @headers << [key, value] 774: end 775: end while (@version == '1.1' && @status == 100) 776: end 777: end
# File lib/httpclient/session.rb, line 779 779: def parse_keepalive_header(key, value) 780: key = key.downcase 781: if key == 'content-length' 782: @content_length = value.to_i 783: elsif key == 'transfer-encoding' and value.downcase == 'chunked' 784: @chunked = true 785: @chunk_length = 0 786: @content_length = nil 787: elsif key == 'connection' or key == 'proxy-connection' 788: if value.downcase == 'keep-alive' 789: @next_connection = true 790: else 791: @next_connection = false 792: end 793: end 794: end
# File lib/httpclient/session.rb, line 820 820: def read_body_chunked(&block) 821: buf = '' 822: while true 823: len = @socket.gets(RS) 824: @chunk_length = len.hex 825: if @chunk_length == 0 826: @content_length = 0 827: @socket.gets(RS) 828: return 829: end 830: timeout(@receive_timeout, ReceiveTimeoutError) do 831: @socket.read(@chunk_length + 2, buf) 832: end 833: unless buf.empty? 834: yield buf.slice(0, @chunk_length) 835: end 836: end 837: end
# File lib/httpclient/session.rb, line 796 796: def read_body_length(&block) 797: return nil if @content_length == 0 798: buf = '' 799: while true 800: maxbytes = @read_block_size 801: maxbytes = @content_length if maxbytes > @content_length 802: timeout(@receive_timeout, ReceiveTimeoutError) do 803: begin 804: @socket.readpartial(maxbytes, buf) 805: rescue EOFError 806: buf = nil 807: end 808: end 809: if buf && buf.length > 0 810: @content_length -= buf.length 811: yield buf 812: else 813: @content_length = 0 814: end 815: return if @content_length == 0 816: end 817: end
# File lib/httpclient/session.rb, line 839 839: def read_body_rest 840: if @readbuf and @readbuf.length > 0 841: yield @readbuf 842: @readbuf = nil 843: end 844: buf = '' 845: while true 846: timeout(@receive_timeout, ReceiveTimeoutError) do 847: begin 848: @socket.readpartial(@read_block_size, buf) 849: rescue EOFError 850: buf = nil 851: end 852: end 853: if buf && buf.length > 0 854: yield buf 855: else 856: return 857: end 858: end 859: end
Read status block.
# File lib/httpclient/session.rb, line 723 723: def read_header 724: @content_length = nil 725: @chunked = false 726: @chunk_length = 0 727: parse_header 728: 729: # Head of the request has been parsed. 730: @state = :DATA 731: req = @requests.shift 732: 733: if req.header.request_method == 'HEAD' 734: @content_length = 0 735: if @next_connection 736: @state = :WAIT 737: else 738: close 739: end 740: end 741: @next_connection = false unless @content_length 742: end
# File lib/httpclient/session.rb, line 611 611: def set_header(req) 612: if @requested_version 613: if /^(?:HTTP\/|)(\d+.\d+)$/ =~ @requested_version 614: req.version = $1.to_f 615: end 616: end 617: if @agent_name 618: req.header.set('User-Agent', "#{@agent_name} #{LIB_NAME}") 619: end 620: if @from 621: req.header.set('From', @from) 622: end 623: req.header.set('Date', Time.now.httpdate) 624: end
Disabled; run with --debug to generate this.
Generated with the Darkfish Rdoc Generator 1.1.6.