httpclient 2.1.7.2 → 2.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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