httpclient 2.1.7.2 → 2.2.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.
@@ -50,13 +50,23 @@ require 'httpclient/cookie'
50
50
  #
51
51
  # === How to retrieve web resources
52
52
  #
53
- # See get_content.
53
+ # See get and get_content.
54
54
  #
55
- # 1. Get content of specified URL. It returns a String of whole result.
55
+ # 1. Get content of specified URL. It returns HTTP::Message object and
56
+ # calling 'body' method of it returns a content String.
57
+ #
58
+ # puts clnt.get('http://dev.ctor.org/').body
59
+ #
60
+ # 2. For getting content directly, use get_content. It follows redirect
61
+ # response and returns a String of whole result.
56
62
  #
57
63
  # puts clnt.get_content('http://dev.ctor.org/')
58
64
  #
59
- # 2. Get content as chunks of String. It yields chunks of String.
65
+ # 3. You can pass :follow_redirect option to follow redirect response in get.
66
+ #
67
+ # puts clnt.get('http://dev.ctor.org/', :foolow_redirect => true)
68
+ #
69
+ # 4. Get content as chunks of String. It yields chunks of String.
60
70
  #
61
71
  # clnt.get_content('http://dev.ctor.org/') do |chunk|
62
72
  # puts chunk
@@ -79,7 +89,11 @@ require 'httpclient/cookie'
79
89
  # p res.status
80
90
  # p res.contenttype
81
91
  # p res.header['X-Custom']
82
- # puts res.content
92
+ # puts res.body
93
+ #
94
+ # You can also use keyword argument style.
95
+ #
96
+ # res = clnt.get(uri, :query => { :keyword => 'ruby', :lang => 'en' })
83
97
  #
84
98
  # === How to POST
85
99
  #
@@ -90,6 +104,10 @@ require 'httpclient/cookie'
90
104
  # body = { 'keyword' => 'ruby', 'lang' => 'en' }
91
105
  # res = clnt.post(uri, body)
92
106
  #
107
+ # Keyword argument style.
108
+ #
109
+ # res = clnt.post(uri, :body => ...)
110
+ #
93
111
  # 2. Do multipart file upload with POST. No need to set extra header by
94
112
  # yourself from httpclient/2.1.4.
95
113
  #
@@ -117,7 +135,7 @@ require 'httpclient/cookie'
117
135
  # Just pass an URL which starts with 'https://'.
118
136
  #
119
137
  # https_url = 'https://www.rsa.com'
120
- # clnt.get_content(https_url)
138
+ # clnt.get(https_url)
121
139
  #
122
140
  # 2. Getting peer certificate from response.
123
141
  #
@@ -129,22 +147,23 @@ require 'httpclient/cookie'
129
147
  # user_cert_file = 'cert.pem'
130
148
  # user_key_file = 'privkey.pem'
131
149
  # clnt.ssl_config.set_client_cert_file(user_cert_file, user_key_file)
132
- # clnt.get_content(https_url)
150
+ # clnt.get(https_url)
133
151
  #
134
152
  # === Handling Cookies
135
153
  #
136
154
  # 1. Using volatile Cookies. Nothing to do. HTTPClient handles Cookies.
137
155
  #
138
156
  # clnt = HTTPClient.new
139
- # clnt.get_content(url1) # receives Cookies.
140
- # clnt.get_content(url2) # sends Cookies if needed.
157
+ # res = clnt.get(url1) # receives Cookies.
158
+ # res = clnt.get(url2) # sends Cookies if needed.
159
+ # p res.cookies
141
160
  #
142
161
  # 2. Saving non volatile Cookies to a specified file. Need to set a file at
143
162
  # first and invoke save method at last.
144
163
  #
145
164
  # clnt = HTTPClient.new
146
165
  # clnt.set_cookie_store('/home/nahi/cookie.dat')
147
- # clnt.get_content(url)
166
+ # clnt.get(url)
148
167
  # ...
149
168
  # clnt.save_cookie_store
150
169
  #
@@ -163,7 +182,7 @@ require 'httpclient/cookie'
163
182
  # user = 'user'
164
183
  # password = 'user'
165
184
  # clnt.set_auth(domain, user, password)
166
- # p clnt.get_content('http://dev.ctor.org/http-access2/login').status
185
+ # p clnt.get('http://dev.ctor.org/http-access2/login').status
167
186
  #
168
187
  # 2. Authentication with Proxy server. Supports BasicAuth and NTLM
169
188
  # (requires win32/sspi)
@@ -172,17 +191,17 @@ require 'httpclient/cookie'
172
191
  # user = 'proxy'
173
192
  # password = 'proxy'
174
193
  # clnt.set_proxy_auth(user, password)
175
- # p clnt.get_content(url)
194
+ # p clnt.get(url)
176
195
  #
177
196
  # === Invoking HTTP methods with custom header
178
197
  #
179
- # Pass a Hash or an Array for extheader argument.
198
+ # Pass a Hash or an Array for header argument.
180
199
  #
181
- # extheader = { 'Accept' => '*/*' }
182
- # clnt.get_content(uri, query, extheader)
200
+ # header = { 'Accept' => '*/*' }
201
+ # clnt.get(uri, query, header)
183
202
  #
184
- # extheader = [['Accept', 'image/jpeg'], ['Accept', 'image/png']]
185
- # clnt.get_content(uri, query, extheader)
203
+ # header = [['Accept', 'image/jpeg'], ['Accept', 'image/png']]
204
+ # clnt.get_content(uri, query, header)
186
205
  #
187
206
  # === Invoking HTTP methods asynchronously
188
207
  #
@@ -200,7 +219,7 @@ require 'httpclient/cookie'
200
219
  # puts '.'
201
220
  # res = connection.pop
202
221
  # p res.status
203
- # p res.content.read # res.content is an IO for the res of async method.
222
+ # p res.body.read # res.body is an IO for the res of async method.
204
223
  #
205
224
  # === Shortcut methods
206
225
  #
@@ -210,7 +229,7 @@ require 'httpclient/cookie'
210
229
  # ruby -rhttpclient -e 'p HTTPClient.head(ARGV.shift).header["last-modified"]' http://dev.ctor.org/
211
230
  #
212
231
  class HTTPClient
213
- VERSION = '2.1.7.2'
232
+ VERSION = '2.2.0'
214
233
  RUBY_VERSION_STRING = "ruby #{RUBY_VERSION} (#{RUBY_RELEASE_DATE}) [#{RUBY_PLATFORM}]"
215
234
  /: (\S+) (\S+)/ =~ %q$Id$
216
235
  LIB_NAME = "(#{$1}/#{$2}, #{RUBY_VERSION_STRING})"
@@ -333,7 +352,7 @@ class HTTPClient
333
352
  # Local socket address. Set HTTPClient#socket_local.host and HTTPClient#socket_local.port to specify local binding hostname and port of TCP socket.
334
353
  attr_proxy(:socket_local, true)
335
354
 
336
- # Default extheader for PROPFIND request.
355
+ # Default header for PROPFIND request.
337
356
  PROPFIND_DEFAULT_EXTHEADER = { 'Depth' => '0' }
338
357
 
339
358
  # Creates a HTTPClient instance which manages sessions, cookies, etc.
@@ -497,6 +516,13 @@ class HTTPClient
497
516
  @cookie_manager.save_cookies
498
517
  end
499
518
 
519
+ # Returns stored cookies.
520
+ def cookies
521
+ if @cookie_manager
522
+ @cookie_manager.cookies
523
+ end
524
+ end
525
+
500
526
  # Sets callback proc when HTTP redirect status is returned for get_content
501
527
  # and post_content. default_redirect_uri_callback is used by default.
502
528
  #
@@ -516,9 +542,9 @@ class HTTPClient
516
542
  # e.g. { "a" => "b" } => 'http://host/part?a=b'.
517
543
  # Give an array to pass multiple value like
518
544
  # [["a", "b"], ["a", "c"]] => 'http://host/part?a=b&a=c'.
519
- # extheader:: a Hash or an Array of extra headers. e.g.
520
- # { 'Accept' => '*/*' } or
521
- # [['Accept', 'image/jpeg'], ['Accept', 'image/png']].
545
+ # header:: a Hash or an Array of extra headers. e.g.
546
+ # { 'Accept' => '*/*' } or
547
+ # [['Accept', 'image/jpeg'], ['Accept', 'image/png']].
522
548
  # &block:: Give a block to get chunked message-body of response like
523
549
  # get_content(uri) { |chunked_body| ... }.
524
550
  # Size of each chunk may not be the same.
@@ -530,8 +556,9 @@ class HTTPClient
530
556
  # If you need to get full HTTP response including HTTP status and headers,
531
557
  # use get method. get returns HTTP::Message as a response and you need to
532
558
  # follow HTTP redirect by yourself if you need.
533
- def get_content(uri, query = nil, extheader = {}, &block)
534
- follow_redirect(:get, uri, query, nil, extheader, &block).content
559
+ def get_content(uri, *args, &block)
560
+ query, header = keyword_argument(args, :query, :header)
561
+ follow_redirect(:get, uri, query, nil, header || {}, &block).content
535
562
  end
536
563
 
537
564
  # Posts a content.
@@ -550,10 +577,10 @@ class HTTPClient
550
577
  # [{ 'Content-Type' => 'text/plain', :content => "some text" },
551
578
  # { 'Content-Type' => 'video/mp4', :content => File.new('video.mp4') }]
552
579
  # => <Two parts with custom Content-Type header>
553
- # extheader:: a Hash or an Array of extra headers. e.g.
554
- # { 'Accept' => '*/*' }
555
- # or
556
- # [['Accept', 'image/jpeg'], ['Accept', 'image/png']].
580
+ # header:: a Hash or an Array of extra headers. e.g.
581
+ # { 'Accept' => '*/*' }
582
+ # or
583
+ # [['Accept', 'image/jpeg'], ['Accept', 'image/png']].
557
584
  # &block:: Give a block to get chunked message-body of response like
558
585
  # post_content(uri) { |chunked_body| ... }.
559
586
  # Size of each chunk may not be the same.
@@ -564,8 +591,9 @@ class HTTPClient
564
591
  #
565
592
  # If you need to get full HTTP response including HTTP status and headers,
566
593
  # use post method.
567
- def post_content(uri, body = nil, extheader = {}, &block)
568
- follow_redirect(:post, uri, nil, body, extheader, &block).content
594
+ def post_content(uri, *args, &block)
595
+ body, header = keyword_argument(args, :body, :header)
596
+ follow_redirect(:post, uri, nil, body, header || {}, &block).content
569
597
  end
570
598
 
571
599
  # A method for redirect uri callback. How to use:
@@ -605,48 +633,48 @@ class HTTPClient
605
633
  end
606
634
 
607
635
  # Sends HEAD request to the specified URL. See request for arguments.
608
- def head(uri, query = nil, extheader = {})
609
- request(:head, uri, query, nil, extheader)
636
+ def head(uri, *args)
637
+ request(:head, uri, argument_to_hash(args, :query, :header))
610
638
  end
611
639
 
612
640
  # Sends GET request to the specified URL. See request for arguments.
613
- def get(uri, query = nil, extheader = {}, &block)
614
- request(:get, uri, query, nil, extheader, &block)
641
+ def get(uri, *args, &block)
642
+ request(:get, uri, argument_to_hash(args, :query, :header, :follow_redirect), &block)
615
643
  end
616
644
 
617
645
  # Sends POST request to the specified URL. See request for arguments.
618
- def post(uri, body = '', extheader = {}, &block)
619
- request(:post, uri, nil, body, extheader, &block)
646
+ def post(uri, *args, &block)
647
+ request(:post, uri, argument_to_hash(args, :body, :header, :follow_redirect), &block)
620
648
  end
621
649
 
622
650
  # Sends PUT request to the specified URL. See request for arguments.
623
- def put(uri, body = '', extheader = {}, &block)
624
- request(:put, uri, nil, body, extheader, &block)
651
+ def put(uri, *args, &block)
652
+ request(:put, uri, argument_to_hash(args, :body, :header), &block)
625
653
  end
626
654
 
627
655
  # Sends DELETE request to the specified URL. See request for arguments.
628
- def delete(uri, extheader = {}, &block)
629
- request(:delete, uri, nil, nil, extheader, &block)
656
+ def delete(uri, *args, &block)
657
+ request(:delete, uri, argument_to_hash(args, :header), &block)
630
658
  end
631
659
 
632
660
  # Sends OPTIONS request to the specified URL. See request for arguments.
633
- def options(uri, extheader = {}, &block)
634
- request(:options, uri, nil, nil, extheader, &block)
661
+ def options(uri, *args, &block)
662
+ request(:options, uri, argument_to_hash(args, :header), &block)
635
663
  end
636
664
 
637
665
  # Sends PROPFIND request to the specified URL. See request for arguments.
638
- def propfind(uri, extheader = PROPFIND_DEFAULT_EXTHEADER, &block)
639
- request(:propfind, uri, nil, nil, extheader, &block)
666
+ def propfind(uri, *args, &block)
667
+ request(:propfind, uri, argument_to_hash(args, :header), &block)
640
668
  end
641
669
 
642
670
  # Sends PROPPATCH request to the specified URL. See request for arguments.
643
- def proppatch(uri, body = nil, extheader = {}, &block)
644
- request(:proppatch, uri, nil, body, extheader, &block)
671
+ def proppatch(uri, *args, &block)
672
+ request(:proppatch, uri, argument_to_hash(args, :body, :header), &block)
645
673
  end
646
674
 
647
675
  # Sends TRACE request to the specified URL. See request for arguments.
648
- def trace(uri, query = nil, body = nil, extheader = {}, &block)
649
- request('TRACE', uri, query, body, extheader, &block)
676
+ def trace(uri, *args, &block)
677
+ request('TRACE', uri, argument_to_hash(args, :query, :body, :header), &block)
650
678
  end
651
679
 
652
680
  # Sends a request to the specified URL.
@@ -673,9 +701,9 @@ class HTTPClient
673
701
  # { 'Content-Type' => 'video/mp4', :content => File.new('video.mp4') }]
674
702
  # => <Two parts with custom Content-Type header>
675
703
  # See HTTP::Message.file? for actual condition of 'a file'.
676
- # extheader:: a Hash or an Array of extra headers. e.g.
677
- # { 'Accept' => '*/*' } or
678
- # [['Accept', 'image/jpeg'], ['Accept', 'image/png']].
704
+ # header:: a Hash or an Array of extra headers. e.g.
705
+ # { 'Accept' => '*/*' } or
706
+ # [['Accept', 'image/jpeg'], ['Accept', 'image/png']].
679
707
  # &block:: Give a block to get chunked message-body of response like
680
708
  # get(uri) { |chunked_body| ... }.
681
709
  # Size of each chunk may not be the same.
@@ -687,77 +715,99 @@ class HTTPClient
687
715
  # chunked encoding (Transfer-Encoding: chunked in HTTP header). Bear in mind
688
716
  # that some server application does not support chunked request. At least
689
717
  # cgi.rb does not support it.
690
- def request(method, uri, query = nil, body = nil, extheader = {}, &block)
718
+ def request(method, uri, *args, &block)
719
+ query, body, header, follow_redirect = keyword_argument(args, :query, :body, :header, :follow_redirect)
720
+ if [:post, :put].include?(method)
721
+ body ||= ''
722
+ end
723
+ if method == :propfind
724
+ header ||= PROPFIND_DEFAULT_EXTHEADER
725
+ else
726
+ header ||= {}
727
+ end
691
728
  uri = urify(uri)
692
729
  if block
693
730
  filtered_block = proc { |res, str|
694
731
  block.call(str)
695
732
  }
696
733
  end
697
- do_request(method, uri, query, body, extheader, &filtered_block)
734
+ if follow_redirect
735
+ follow_redirect(method, uri, query, body, header, &block)
736
+ else
737
+ do_request(method, uri, query, body, header, &filtered_block)
738
+ end
698
739
  end
699
740
 
700
741
  # Sends HEAD request in async style. See request_async for arguments.
701
742
  # It immediately returns a HTTPClient::Connection instance as a result.
702
- def head_async(uri, query = nil, extheader = {})
703
- request_async(:head, uri, query, nil, extheader)
743
+ def head_async(uri, *args)
744
+ query, header = keyword_argument(args, :query, :header)
745
+ request_async(:head, uri, query, nil, header || {})
704
746
  end
705
747
 
706
748
  # Sends GET request in async style. See request_async for arguments.
707
749
  # It immediately returns a HTTPClient::Connection instance as a result.
708
- def get_async(uri, query = nil, extheader = {})
709
- request_async(:get, uri, query, nil, extheader)
750
+ def get_async(uri, *args)
751
+ query, header = keyword_argument(args, :query, :header)
752
+ request_async(:get, uri, query, nil, header || {})
710
753
  end
711
754
 
712
755
  # Sends POST request in async style. See request_async for arguments.
713
756
  # It immediately returns a HTTPClient::Connection instance as a result.
714
- def post_async(uri, body = nil, extheader = {})
715
- request_async(:post, uri, nil, body, extheader)
757
+ def post_async(uri, *args)
758
+ body, header = keyword_argument(args, :body, :header)
759
+ request_async(:post, uri, nil, body || '', header || {})
716
760
  end
717
761
 
718
762
  # Sends PUT request in async style. See request_async for arguments.
719
763
  # It immediately returns a HTTPClient::Connection instance as a result.
720
- def put_async(uri, body = nil, extheader = {})
721
- request_async(:put, uri, nil, body, extheader)
764
+ def put_async(uri, *args)
765
+ body, header = keyword_argument(args, :body, :header)
766
+ request_async(:put, uri, nil, body || '', header || {})
722
767
  end
723
768
 
724
769
  # Sends DELETE request in async style. See request_async for arguments.
725
770
  # It immediately returns a HTTPClient::Connection instance as a result.
726
- def delete_async(uri, extheader = {})
727
- request_async(:delete, uri, nil, nil, extheader)
771
+ def delete_async(uri, *args)
772
+ header = keyword_argument(args, :header)
773
+ request_async(:delete, uri, nil, nil, header || {})
728
774
  end
729
775
 
730
776
  # Sends OPTIONS request in async style. See request_async for arguments.
731
777
  # It immediately returns a HTTPClient::Connection instance as a result.
732
- def options_async(uri, extheader = {})
733
- request_async(:options, uri, nil, nil, extheader)
778
+ def options_async(uri, *args)
779
+ header = keyword_argument(args, :header)
780
+ request_async(:options, uri, nil, nil, header || {})
734
781
  end
735
782
 
736
783
  # Sends PROPFIND request in async style. See request_async for arguments.
737
784
  # It immediately returns a HTTPClient::Connection instance as a result.
738
- def propfind_async(uri, extheader = PROPFIND_DEFAULT_EXTHEADER)
739
- request_async(:propfind, uri, nil, nil, extheader)
785
+ def propfind_async(uri, *args)
786
+ header = keyword_argument(args, :header)
787
+ request_async(:propfind, uri, nil, nil, header || PROPFIND_DEFAULT_EXTHEADER)
740
788
  end
741
789
 
742
790
  # Sends PROPPATCH request in async style. See request_async for arguments.
743
791
  # It immediately returns a HTTPClient::Connection instance as a result.
744
- def proppatch_async(uri, body = nil, extheader = {})
745
- request_async(:proppatch, uri, nil, body, extheader)
792
+ def proppatch_async(uri, *args)
793
+ body, header = keyword_argument(args, :body, :header)
794
+ request_async(:proppatch, uri, nil, body, header || {})
746
795
  end
747
796
 
748
797
  # Sends TRACE request in async style. See request_async for arguments.
749
798
  # It immediately returns a HTTPClient::Connection instance as a result.
750
- def trace_async(uri, query = nil, body = nil, extheader = {})
751
- request_async(:trace, uri, query, body, extheader)
799
+ def trace_async(uri, *args)
800
+ query, body, header = keyword_argument(args, :query, :body, :header)
801
+ request_async(:trace, uri, query, body, header || {})
752
802
  end
753
803
 
754
804
  # Sends a request in async style. request method creates new Thread for
755
805
  # HTTP connection and returns a HTTPClient::Connection instance immediately.
756
806
  #
757
807
  # Arguments definition is the same as request.
758
- def request_async(method, uri, query = nil, body = nil, extheader = {})
808
+ def request_async(method, uri, query = nil, body = nil, header = {})
759
809
  uri = urify(uri)
760
- do_request_async(method, uri, query, body, extheader)
810
+ do_request_async(method, uri, query, body, header)
761
811
  end
762
812
 
763
813
  # Resets internal session for the given URL. Keep-alive connection for the
@@ -784,7 +834,7 @@ private
784
834
  end
785
835
  end
786
836
 
787
- def do_request(method, uri, query, body, extheader, &block)
837
+ def do_request(method, uri, query, body, header, &block)
788
838
  conn = Connection.new
789
839
  res = nil
790
840
  if HTTP::Message.file?(body)
@@ -794,7 +844,7 @@ private
794
844
  proxy = no_proxy?(uri) ? nil : @proxy
795
845
  while retry_count > 0
796
846
  body.pos = pos if pos
797
- req = create_request(method, uri, query, body, extheader)
847
+ req = create_request(method, uri, query, body, header)
798
848
  begin
799
849
  protect_keep_alive_disconnected do
800
850
  do_get_block(req, proxy, conn, &block)
@@ -809,7 +859,7 @@ private
809
859
  res
810
860
  end
811
861
 
812
- def do_request_async(method, uri, query, body, extheader)
862
+ def do_request_async(method, uri, query, body, header)
813
863
  conn = Connection.new
814
864
  t = Thread.new(conn) { |tconn|
815
865
  begin
@@ -820,7 +870,7 @@ private
820
870
  proxy = no_proxy?(uri) ? nil : @proxy
821
871
  while retry_count > 0
822
872
  body.pos = pos if pos
823
- req = create_request(method, uri, query, body, extheader)
873
+ req = create_request(method, uri, query, body, header)
824
874
  begin
825
875
  protect_keep_alive_disconnected do
826
876
  do_get_stream(req, proxy, tconn)
@@ -856,7 +906,7 @@ private
856
906
  ENV[name.downcase] || ENV[name.upcase]
857
907
  end
858
908
 
859
- def follow_redirect(method, uri, query, body, extheader, &block)
909
+ def follow_redirect(method, uri, query, body, header, &block)
860
910
  uri = urify(uri)
861
911
  if block
862
912
  filtered_block = proc { |r, str|
@@ -869,7 +919,7 @@ private
869
919
  retry_number = 0
870
920
  while retry_number < @follow_redirect_count
871
921
  body.pos = pos if pos
872
- res = do_request(method, uri, query, body, extheader, &filtered_block)
922
+ res = do_request(method, uri, query, body, header, &filtered_block)
873
923
  if HTTP::Status.successful?(res.status)
874
924
  return res
875
925
  elsif HTTP::Status.redirect?(res.status)
@@ -893,16 +943,16 @@ private
893
943
  end
894
944
  end
895
945
 
896
- def create_request(method, uri, query, body, extheader)
946
+ def create_request(method, uri, query, body, header)
897
947
  method = method.to_s.upcase
898
- if extheader.is_a?(Hash)
899
- extheader = extheader.to_a
948
+ if header.is_a?(Hash)
949
+ header = header.to_a
900
950
  else
901
- extheader = extheader.dup
951
+ header = header.dup
902
952
  end
903
953
  boundary = nil
904
954
  if body
905
- _, content_type = extheader.find { |key, value|
955
+ _, content_type = header.find { |key, value|
906
956
  key.downcase == 'content-type'
907
957
  }
908
958
  if content_type
@@ -912,7 +962,7 @@ private
912
962
  else
913
963
  boundary = create_boundary
914
964
  content_type = "#{content_type}; boundary=#{boundary}"
915
- extheader = override_header(extheader, 'Content-Type', content_type)
965
+ header = override_header(header, 'Content-Type', content_type)
916
966
  end
917
967
  end
918
968
  elsif method == 'POST'
@@ -922,11 +972,11 @@ private
922
972
  else
923
973
  content_type = 'application/x-www-form-urlencoded'
924
974
  end
925
- extheader << ['Content-Type', content_type]
975
+ header << ['Content-Type', content_type]
926
976
  end
927
977
  end
928
978
  req = HTTP::Message.new_request(method, uri, query, body, boundary)
929
- extheader.each do |key, value|
979
+ header.each do |key, value|
930
980
  req.header.add(key, value)
931
981
  end
932
982
  if @cookie_manager && cookie = @cookie_manager.find(uri)
@@ -944,9 +994,9 @@ private
944
994
  body.any? { |k, v| HTTP::Message.file?(v) }
945
995
  end
946
996
 
947
- def override_header(extheader, key, value)
997
+ def override_header(header, key, value)
948
998
  result = []
949
- extheader.each do |k, v|
999
+ header.each do |k, v|
950
1000
  if k.downcase == key.downcase
951
1001
  result << [key, value]
952
1002
  else
@@ -981,7 +1031,7 @@ private
981
1031
  filter.filter_request(req)
982
1032
  end
983
1033
  if str = @test_loopback_response.shift
984
- dump_dummy_request_response(req.body.dump, str) if @debug_dev
1034
+ dump_dummy_request_response(req.http_body.dump, str) if @debug_dev
985
1035
  conn.push(HTTP::Message.new_response(str))
986
1036
  return
987
1037
  end
@@ -1017,7 +1067,7 @@ private
1017
1067
  filter.filter_request(req)
1018
1068
  end
1019
1069
  if str = @test_loopback_response.shift
1020
- dump_dummy_request_response(req.body.dump, str) if @debug_dev
1070
+ dump_dummy_request_response(req.http_body.dump, str) if @debug_dev
1021
1071
  conn.push(HTTP::Message.new_response(StringIO.new(str)))
1022
1072
  return
1023
1073
  end
@@ -800,8 +800,8 @@ class HTTPClient
800
800
  params += encode_param(query)
801
801
  end
802
802
  # captures HTTP Message body only for 'application/x-www-form-urlencoded'
803
- if req.header.contenttype == 'application/x-www-form-urlencoded' and req.body.size
804
- params += encode_param(HTTP::Message.parse(req.body.content))
803
+ if req.header.contenttype == 'application/x-www-form-urlencoded' and req.http_body.size
804
+ params += encode_param(HTTP::Message.parse(req.http_body.content))
805
805
  end
806
806
  uri = req.header.request_uri
807
807
  if uri.query
@@ -378,12 +378,17 @@ module HTTP
378
378
  set('Last-Modified', @body_date.httpdate)
379
379
  end
380
380
  if self['Content-Type'].empty?
381
- set('Content-Type', "#{ @body_type || 'text/html' }; charset=#{ charset_label(@body_charset || $KCODE) }")
381
+ set('Content-Type', "#{ @body_type || 'text/html' }; charset=#{ charset_label }")
382
382
  end
383
383
  end
384
384
 
385
- def charset_label(charset)
386
- CHARSET_MAP[charset] || 'us-ascii'
385
+ def charset_label
386
+ # TODO: should handle response encoding for 1.9 correctly.
387
+ if RUBY_VERSION > "1.9"
388
+ CHARSET_MAP[@body_charset] || 'us-ascii'
389
+ else
390
+ CHARSET_MAP[@body_charset || $KCODE] || 'us-ascii'
391
+ end
387
392
  end
388
393
  end
389
394
 
@@ -640,8 +645,8 @@ module HTTP
640
645
  # uri:: an URI that need to connect. Only uri.host and uri.port are used.
641
646
  def new_connect_request(uri)
642
647
  m = new
643
- m.header.init_connect_request(uri)
644
- m.header.body_size = nil
648
+ m.http_header.init_connect_request(uri)
649
+ m.http_header.body_size = nil
645
650
  m
646
651
  end
647
652
 
@@ -660,14 +665,14 @@ module HTTP
660
665
  # a multipart/form-data using this boundary String.
661
666
  def new_request(method, uri, query = nil, body = nil, boundary = nil)
662
667
  m = new
663
- m.header.init_request(method, uri, query)
664
- m.body = Body.new
665
- m.body.init_request(body || '', boundary)
668
+ m.http_header.init_request(method, uri, query)
669
+ m.http_body = Body.new
670
+ m.http_body.init_request(body || '', boundary)
666
671
  if body
667
- m.header.body_size = m.body.size
668
- m.header.chunked = true if m.body.size.nil?
672
+ m.http_header.body_size = m.http_body.size
673
+ m.http_header.chunked = true if m.http_body.size.nil?
669
674
  else
670
- m.header.body_size = nil
675
+ m.http_header.body_size = nil
671
676
  end
672
677
  m
673
678
  end
@@ -676,10 +681,10 @@ module HTTP
676
681
  # body:: a String or an IO of response message body.
677
682
  def new_response(body)
678
683
  m = new
679
- m.header.init_response(Status::OK)
680
- m.body = Body.new
681
- m.body.init_response(body)
682
- m.header.body_size = m.body.size || 0
684
+ m.http_header.init_response(Status::OK)
685
+ m.http_body = Body.new
686
+ m.http_body.init_response(body)
687
+ m.http_header.body_size = m.http_body.size || 0
683
688
  m
684
689
  end
685
690
 
@@ -820,10 +825,10 @@ module HTTP
820
825
 
821
826
 
822
827
  # HTTP::Message::Headers:: message header.
823
- attr_accessor :header
828
+ attr_accessor :http_header
824
829
 
825
830
  # HTTP::Message::Body:: message body.
826
- attr_reader :body
831
+ attr_reader :http_body
827
832
 
828
833
  # OpenSSL::X509::Certificate:: response only. server certificate which is
829
834
  # used for retrieving the response.
@@ -833,18 +838,18 @@ module HTTP
833
838
  # Use Message.new_connect_request, Message.new_request or
834
839
  # Message.new_response instead.
835
840
  def initialize # :nodoc:
836
- @header = Headers.new
837
- @body = @peer_cert = nil
841
+ @http_header = Headers.new
842
+ @http_body = @peer_cert = nil
838
843
  end
839
844
 
840
845
  # Dumps message (header and body) to given dev.
841
846
  # dev needs to respond to <<.
842
847
  def dump(dev = '')
843
- str = header.dump + CRLF
844
- if header.chunked
845
- dev = body.dump_chunked(str, dev)
846
- elsif body
847
- dev = body.dump(str, dev)
848
+ str = @http_header.dump + CRLF
849
+ if @http_header.chunked
850
+ dev = @http_body.dump_chunked(str, dev)
851
+ elsif @http_body
852
+ dev = @http_body.dump(str, dev)
848
853
  else
849
854
  dev << str
850
855
  end
@@ -852,35 +857,35 @@ module HTTP
852
857
  end
853
858
 
854
859
  # Sets a new body. header.body_size is updated with new body.size.
855
- def body=(body)
856
- @body = body
857
- @header.body_size = @body.size if @header
860
+ def http_body=(body)
861
+ @http_body = body
862
+ @http_header.body_size = @http_body.size if @http_header
858
863
  end
859
864
 
860
865
  # Returns HTTP version in a HTTP header. String.
861
866
  def http_version
862
- @header.http_version
867
+ @http_header.http_version
863
868
  end
864
869
 
865
870
  # Sets HTTP version in a HTTP header. String.
866
871
  def http_version=(http_version)
867
- @header.http_version = http_version
872
+ @http_header.http_version = http_version
868
873
  end
869
874
 
870
875
  VERSION_WARNING = 'Message#version (Float) is deprecated. Use Message#http_version (String) instead.'
871
876
  def version
872
877
  warn(VERSION_WARNING)
873
- @header.http_version.to_f
878
+ @http_header.http_version.to_f
874
879
  end
875
880
 
876
881
  def version=(version)
877
882
  warn(VERSION_WARNING)
878
- @header.http_version = version
883
+ @http_header.http_version = version
879
884
  end
880
885
 
881
886
  # Returns HTTP status code in response. Integer.
882
887
  def status
883
- @header.status_code
888
+ @http_header.status_code
884
889
  end
885
890
 
886
891
  alias code status
@@ -889,32 +894,58 @@ module HTTP
889
894
  # Sets HTTP status code of response. Integer.
890
895
  # Reason phrase is updated, too.
891
896
  def status=(status)
892
- @header.status_code = status
897
+ @http_header.status_code = status
893
898
  end
894
899
 
895
900
  # Returns HTTP status reason phrase in response. String.
896
901
  def reason
897
- @header.reason_phrase
902
+ @http_header.reason_phrase
898
903
  end
899
904
 
900
905
  # Sets HTTP status reason phrase of response. String.
901
906
  def reason=(reason)
902
- @header.reason_phrase = reason
907
+ @http_header.reason_phrase = reason
903
908
  end
904
909
 
905
910
  # Sets 'Content-Type' header value. Overrides if already exists.
906
911
  def contenttype
907
- @header.contenttype
912
+ @http_header.contenttype
908
913
  end
909
914
 
910
915
  # Returns 'Content-Type' header value.
911
916
  def contenttype=(contenttype)
912
- @header.contenttype = contenttype
917
+ @http_header.contenttype = contenttype
913
918
  end
914
919
 
915
920
  # Returns a content of message body. A String or an IO.
916
921
  def content
917
- @body.content
922
+ @http_body.content
923
+ end
924
+
925
+ alias header http_header
926
+ alias body content
927
+
928
+ # Returns Hash of header. key and value are both String. Each key has a
929
+ # single value so you can't extract exact value when a message has multiple
930
+ # headers like 'Set-Cookie'. Use header['Set-Cookie'] for that purpose.
931
+ # (It returns an Array always)
932
+ def headers
933
+ Hash[http_header.all]
934
+ end
935
+
936
+ # Extracts cookies from 'Set-Cookie' header.
937
+ # Supports 'Set-Cookie' in response header only.
938
+ # Do we need 'Cookie' support in request header?
939
+ def cookies
940
+ set_cookies = http_header['set-cookie']
941
+ unless set_cookies.empty?
942
+ uri = http_header.request_uri
943
+ set_cookies.map { |str|
944
+ cookie = WebAgent::Cookie.new
945
+ cookie.parse(str, uri)
946
+ cookie
947
+ }
948
+ end
918
949
  end
919
950
  end
920
951
 
@@ -152,7 +152,7 @@ class HTTPClient
152
152
  end
153
153
 
154
154
  def query(req, via_proxy)
155
- req.body.chunk_size = @chunk_size
155
+ req.http_body.chunk_size = @chunk_size
156
156
  sess = open(req.header.request_uri, via_proxy)
157
157
  begin
158
158
  sess.query(req)
@@ -812,7 +812,7 @@ class HTTPClient
812
812
  close
813
813
  end
814
814
  end
815
- @next_connection = false unless @content_length
815
+ @next_connection = false if !@content_length and !@chunked
816
816
  end
817
817
 
818
818
  StatusParseRegexp = %r(\AHTTP/(\d+\.\d+)\s+(\d\d\d)\s*([^\r\n]+)?\r?\n\z)
@@ -21,7 +21,7 @@ class HTTPClient
21
21
  # == Trust Anchor Control
22
22
  #
23
23
  # SSLConfig loads 'httpclient/cacert.p7s' as a trust anchor
24
- # (trusted certificate(s)) with set_trust_ca in initialization time.
24
+ # (trusted certificate(s)) with add_trust_ca in initialization time.
25
25
  # This means that HTTPClient instance trusts some CA certificates by default,
26
26
  # like Web browsers. 'httpclient/cacert.p7s' is created by the author and
27
27
  # included in released package.
@@ -29,7 +29,7 @@ class HTTPClient
29
29
  # 'cacert.p7s' is automatically generated from JDK 1.6.
30
30
  #
31
31
  # You may want to change trust anchor by yourself. Call clear_cert_store
32
- # then set_trust_ca for that purpose.
32
+ # then add_trust_ca for that purpose.
33
33
  class SSLConfig
34
34
  include OpenSSL if SSLEnabled
35
35
 
@@ -82,7 +82,7 @@ class HTTPClient
82
82
  @timeout = nil
83
83
  @options = defined?(SSL::OP_ALL) ? SSL::OP_ALL | SSL::OP_NO_SSLv2 : nil
84
84
  @ciphers = "ALL:!ADH:!LOW:!EXP:!MD5:+SSLv2:@STRENGTH"
85
- load_cacerts
85
+ @cacerts_loaded = false
86
86
  end
87
87
 
88
88
  # Sets certificate (OpenSSL::X509::Certificate) for SSL client
@@ -122,6 +122,7 @@ class HTTPClient
122
122
  #
123
123
  # Calling this method resets all existing sessions.
124
124
  def clear_cert_store
125
+ @cacerts_loaded = true # avoid lazy override
125
126
  @cert_store = X509::Store.new
126
127
  change_notify
127
128
  end
@@ -131,6 +132,7 @@ class HTTPClient
131
132
  #
132
133
  # Calling this method resets all existing sessions.
133
134
  def cert_store=(cert_store)
135
+ @cacerts_loaded = true # avoid lazy override
134
136
  @cert_store = cert_store
135
137
  change_notify
136
138
  end
@@ -142,7 +144,8 @@ class HTTPClient
142
144
  # trusted certificate files.
143
145
  #
144
146
  # Calling this method resets all existing sessions.
145
- def set_trust_ca(trust_ca_file_or_hashed_dir)
147
+ def add_trust_ca(trust_ca_file_or_hashed_dir)
148
+ @cacerts_loaded = true # avoid lazy override
146
149
  if FileTest.directory?(trust_ca_file_or_hashed_dir)
147
150
  @cert_store.add_path(trust_ca_file_or_hashed_dir)
148
151
  else
@@ -150,13 +153,21 @@ class HTTPClient
150
153
  end
151
154
  change_notify
152
155
  end
156
+ alias set_trust_ca add_trust_ca
157
+
158
+ # Loads default trust anchors.
159
+ # Calling this method resets all existing sessions.
160
+ def load_trust_ca
161
+ load_cacerts
162
+ change_notify
163
+ end
153
164
 
154
165
  # Adds CRL for verification.
155
166
  # crl:: a OpenSSL::X509::CRL or a filename of a PEM/DER formatted
156
167
  # OpenSSL::X509::CRL.
157
168
  #
158
169
  # Calling this method resets all existing sessions.
159
- def set_crl(crl)
170
+ def add_crl(crl)
160
171
  unless crl.is_a?(X509::CRL)
161
172
  crl = X509::CRL.new(File.open(crl) { |f| f.read })
162
173
  end
@@ -164,6 +175,7 @@ class HTTPClient
164
175
  @cert_store.flags = X509::V_FLAG_CRL_CHECK | X509::V_FLAG_CRL_CHECK_ALL
165
176
  change_notify
166
177
  end
178
+ alias set_crl add_crl
167
179
 
168
180
  # Sets verify mode of OpenSSL. New value must be a combination of
169
181
  # constants OpenSSL::SSL::VERIFY_*
@@ -223,6 +235,8 @@ class HTTPClient
223
235
 
224
236
  # interfaces for SSLSocketWrap.
225
237
  def set_context(ctx) # :nodoc:
238
+ load_trust_ca unless @cacerts_loaded
239
+ @cacerts_loaded = true
226
240
  # Verification: Use Store#verify_callback instead of SSLContext#verify*?
227
241
  ctx.cert_store = @cert_store
228
242
  ctx.verify_mode = @verify_mode
@@ -350,7 +364,7 @@ class HTTPClient
350
364
  store = X509::Store.new
351
365
  store.add_cert(selfcert)
352
366
  if (p7.verify(nil, store, p7.data, 0))
353
- set_trust_ca(file)
367
+ add_trust_ca(file)
354
368
  return
355
369
  end
356
370
  end
@@ -23,6 +23,7 @@ class HTTPClient
23
23
  # timeout scheduler.
24
24
  # * Do not wakeup the scheduler thread so often. Let scheduler thread sleep
25
25
  # until the nearest period.
26
+ if !defined?(JRUBY_VERSION) and RUBY_VERSION < '1.9'
26
27
  class TimeoutScheduler
27
28
 
28
29
  # Represents timeout period.
@@ -117,6 +118,7 @@ class HTTPClient
117
118
  end
118
119
  end
119
120
  timeout_scheduler # initialize at first time.
121
+ end
120
122
 
121
123
  module Timeout
122
124
  if !defined?(JRUBY_VERSION) and RUBY_VERSION < '1.9'
@@ -43,10 +43,34 @@ class HTTPClient
43
43
  #
44
44
  def keyword_argument(args, *field)
45
45
  if args.size == 1 and args[0].is_a?(Hash)
46
- args[0].values_at(*field)
47
- else
48
- args
46
+ r = args[0].values_at(*field)
47
+ unless r.compact.empty?
48
+ return r
49
+ end
50
+ end
51
+ args
52
+ end
53
+
54
+ # Keyword argument to hash helper.
55
+ # args:: given arguments.
56
+ # *field:: a list of arguments to be extracted.
57
+ #
58
+ # Returns hash which has defined keys. When a Hash given, returns it
59
+ # including undefined keys. When an Array given, returns a Hash which only
60
+ # includes defined keys.
61
+ def argument_to_hash(args, *field)
62
+ return nil if args.empty?
63
+ if args.size == 1 and args[0].is_a?(Hash)
64
+ r = args[0].values_at(*field)
65
+ unless r.compact.empty?
66
+ return args[0]
67
+ end
68
+ end
69
+ h = {}
70
+ field.each_with_index do |e, idx|
71
+ h[e] = args[idx]
49
72
  end
73
+ h
50
74
  end
51
75
 
52
76
  # Gets an URI instance.
metadata CHANGED
@@ -2,7 +2,7 @@
2
2
  name: httpclient
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease:
5
- version: 2.1.7.2
5
+ version: 2.2.0
6
6
  platform: ruby
7
7
  authors:
8
8
  - NAKAMURA, Hiroshi
@@ -10,8 +10,7 @@ autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
12
 
13
- date: 2011-03-23 00:00:00 +09:00
14
- default_executable:
13
+ date: 2011-04-08 00:00:00 Z
15
14
  dependencies: []
16
15
 
17
16
  description:
@@ -49,7 +48,6 @@ files:
49
48
  - lib/httpclient/util.rbc
50
49
  - lib/httpclient/http.rb
51
50
  - lib/httpclient.rb
52
- has_rdoc: true
53
51
  homepage: http://github.com/nahi/httpclient
54
52
  licenses: []
55
53
 
@@ -73,7 +71,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
73
71
  requirements: []
74
72
 
75
73
  rubyforge_project:
76
- rubygems_version: 1.6.2
74
+ rubygems_version: 1.7.1
77
75
  signing_key:
78
76
  specification_version: 3
79
77
  summary: gives something like the functionality of libwww-perl (LWP) in Ruby