httpclient 2.3.0.1 → 2.8.3

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.
Files changed (41) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +85 -0
  3. data/bin/httpclient +18 -6
  4. data/bin/jsonclient +85 -0
  5. data/lib/http-access2.rb +1 -1
  6. data/lib/httpclient.rb +262 -88
  7. data/lib/httpclient/auth.rb +269 -244
  8. data/lib/httpclient/cacert.pem +3952 -0
  9. data/lib/httpclient/cacert1024.pem +3866 -0
  10. data/lib/httpclient/connection.rb +1 -1
  11. data/lib/httpclient/cookie.rb +161 -514
  12. data/lib/httpclient/http.rb +57 -21
  13. data/lib/httpclient/include_client.rb +2 -0
  14. data/lib/httpclient/jruby_ssl_socket.rb +588 -0
  15. data/lib/httpclient/session.rb +259 -317
  16. data/lib/httpclient/ssl_config.rb +141 -188
  17. data/lib/httpclient/ssl_socket.rb +150 -0
  18. data/lib/httpclient/timeout.rb +1 -1
  19. data/lib/httpclient/util.rb +62 -1
  20. data/lib/httpclient/version.rb +1 -1
  21. data/lib/httpclient/webagent-cookie.rb +459 -0
  22. data/lib/jsonclient.rb +63 -0
  23. data/lib/oauthclient.rb +2 -1
  24. data/sample/jsonclient.rb +67 -0
  25. data/sample/oauth_twitter.rb +4 -4
  26. data/test/{ca-chain.cert → ca-chain.pem} +0 -0
  27. data/test/client-pass.key +18 -0
  28. data/test/helper.rb +10 -8
  29. data/test/jruby_ssl_socket/test_pemutils.rb +32 -0
  30. data/test/test_auth.rb +175 -4
  31. data/test/test_cookie.rb +147 -243
  32. data/test/test_http-access2.rb +17 -16
  33. data/test/test_httpclient.rb +458 -77
  34. data/test/test_jsonclient.rb +80 -0
  35. data/test/test_ssl.rb +341 -17
  36. data/test/test_webagent-cookie.rb +465 -0
  37. metadata +57 -55
  38. data/README.txt +0 -721
  39. data/lib/httpclient/cacert.p7s +0 -1858
  40. data/lib/httpclient/cacert_sha1.p7s +0 -1858
  41. data/sample/oauth_salesforce_10.rb +0 -63
@@ -1,5 +1,7 @@
1
+ # -*- encoding: utf-8 -*-
1
2
  require 'http-access2'
2
3
  require File.expand_path('helper', File.dirname(__FILE__))
4
+ require 'tempfile'
3
5
 
4
6
 
5
7
  module HTTPAccess2
@@ -47,7 +49,7 @@ class TestClient < Test::Unit::TestCase
47
49
  @client.get(serverurl)
48
50
  lines = str.split(/(?:\r?\n)+/)
49
51
  assert_equal("= Request", lines[0])
50
- assert_match(/^From: from_bar/, lines[4])
52
+ assert_match(/^From: from_bar/, lines[5])
51
53
  end
52
54
 
53
55
  def test_debug_dev
@@ -81,8 +83,8 @@ class TestClient < Test::Unit::TestCase
81
83
  assert_equal("= Request", lines[0])
82
84
  assert_equal("! CONNECTION ESTABLISHED", lines[2])
83
85
  assert_equal("GET /hello HTTP/1.0", lines[3])
84
- assert_equal("Connection: close", lines[6])
85
- assert_equal("= Response", lines[7])
86
+ assert_equal("Connection: close", lines[7])
87
+ assert_equal("= Response", lines[8])
86
88
  end
87
89
 
88
90
  def test_protocol_version_http11
@@ -93,7 +95,7 @@ class TestClient < Test::Unit::TestCase
93
95
  assert_equal("= Request", lines[0])
94
96
  assert_equal("! CONNECTION ESTABLISHED", lines[2])
95
97
  assert_equal("GET / HTTP/1.1", lines[3])
96
- assert_equal("Host: localhost:#{serverport}", lines[6])
98
+ assert_equal("Host: localhost:#{serverport}", lines[7])
97
99
  @client.protocol_version = 'HTTP/1.1'
98
100
  str = ""
99
101
  @client.debug_dev = str
@@ -116,9 +118,9 @@ class TestClient < Test::Unit::TestCase
116
118
  setup_proxyserver
117
119
  escape_noproxy do
118
120
  begin
119
- @client.proxy = "http://"
120
- rescue
121
- assert_match(/InvalidURIError/, $!.class.to_s)
121
+ @client.proxy = "http://あ"
122
+ rescue => e
123
+ assert_match(/InvalidURIError/, e.class.to_s)
122
124
  end
123
125
  @client.proxy = ""
124
126
  assert_nil(@client.proxy)
@@ -243,7 +245,7 @@ class TestClient < Test::Unit::TestCase
243
245
  end
244
246
 
245
247
  def test_post
246
- assert_equal("post", @client.post(serverurl + 'servlet').content)
248
+ assert_equal("post", @client.post(serverurl + 'servlet', '').content)
247
249
  param = {'1'=>'2', '3'=>'4'}
248
250
  res = @client.get(serverurl + 'servlet', param)
249
251
  assert_equal(param, params(res.header["x-query"][0]))
@@ -345,27 +347,26 @@ class TestClient < Test::Unit::TestCase
345
347
  def test_receive_timeout
346
348
  # this test takes 2 sec
347
349
  assert_equal('hello', @client.get_content(serverurl + 'sleep?sec=2'))
350
+ @client.reset_all
348
351
  @client.receive_timeout = 1
349
352
  assert_equal('hello', @client.get_content(serverurl + 'sleep?sec=0'))
350
353
  assert_raise(HTTPClient::ReceiveTimeoutError) do
351
354
  @client.get_content(serverurl + 'sleep?sec=2')
352
355
  end
356
+ @client.reset_all
353
357
  @client.receive_timeout = 3
354
358
  assert_equal('hello', @client.get_content(serverurl + 'sleep?sec=2'))
355
359
  end
356
360
 
357
361
  def test_cookies
358
- cookiefile = File.join(File.dirname(File.expand_path(__FILE__)),
359
- 'test_cookies_file')
362
+ cookiefile = Tempfile.new('test_cookies_file')
360
363
  # from [ruby-talk:164079]
361
- File.open(cookiefile, "wb") do |f|
362
- f << "http://rubyforge.org//account/login.php session_ser LjEwMy45Ni40Ni0q%2A-fa0537de8cc31 1131676286 .rubyforge.org / 13\n"
364
+ File.open(cookiefile.path, "wb") do |f|
365
+ f << "http://rubyforge.org//account/login.php session_ser LjEwMy45Ni40Ni0q%2A-fa0537de8cc31 2131676286 .rubyforge.org / 13\n"
363
366
  end
364
- cm = WebAgent::CookieManager::new(cookiefile)
367
+ cm = WebAgent::CookieManager::new(cookiefile.path)
365
368
  cm.load_cookies
366
- cookie = cm.cookies.first
367
- url = cookie.url
368
- assert(cookie.domain_match(url.host, cookie.domain))
369
+ assert_equal(1, cm.cookies.size)
369
370
  end
370
371
 
371
372
  private
@@ -1,5 +1,6 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
  require File.expand_path('helper', File.dirname(__FILE__))
3
+ require 'tempfile'
3
4
 
4
5
 
5
6
  class TestHTTPClient < Test::Unit::TestCase
@@ -44,7 +45,7 @@ class TestHTTPClient < Test::Unit::TestCase
44
45
  @client.get(serverurl)
45
46
  lines = str.split(/(?:\r?\n)+/)
46
47
  assert_equal("= Request", lines[0])
47
- assert_match(/^From: from_bar/, lines[4])
48
+ assert_match(/^From: from_bar/, lines[5])
48
49
  end
49
50
 
50
51
  def test_debug_dev
@@ -77,10 +78,10 @@ class TestHTTPClient < Test::Unit::TestCase
77
78
  assert_equal("= Request", lines[0])
78
79
  assert_equal("! CONNECTION ESTABLISHED", lines[2])
79
80
  assert_equal("GET /hello HTTP/0.9", lines[3])
80
- assert_equal("Connection: close", lines[6])
81
- assert_equal("= Response", lines[7])
82
- assert_match(/^hello$/, lines[8])
83
- assert_match(/^world$/, lines[9])
81
+ assert_equal("Connection: close", lines[7])
82
+ assert_equal("= Response", lines[8])
83
+ assert_match(/^hello$/, lines[9])
84
+ assert_match(/^world$/, lines[10])
84
85
  end
85
86
 
86
87
  def test_protocol_version_http10
@@ -94,8 +95,8 @@ class TestHTTPClient < Test::Unit::TestCase
94
95
  assert_equal("= Request", lines[0])
95
96
  assert_equal("! CONNECTION ESTABLISHED", lines[2])
96
97
  assert_equal("GET /hello HTTP/1.0", lines[3])
97
- assert_equal("Connection: close", lines[6])
98
- assert_equal("= Response", lines[7])
98
+ assert_equal("Connection: close", lines[7])
99
+ assert_equal("= Response", lines[8])
99
100
  end
100
101
 
101
102
  def test_header_accept_by_default
@@ -103,7 +104,7 @@ class TestHTTPClient < Test::Unit::TestCase
103
104
  @client.debug_dev = str
104
105
  @client.get(serverurl)
105
106
  lines = str.split(/(?:\r?\n)+/)
106
- assert_equal("Accept: */*", lines[4])
107
+ assert_equal("Accept: */*", lines[5])
107
108
  end
108
109
 
109
110
  def test_header_accept
@@ -114,6 +115,14 @@ class TestHTTPClient < Test::Unit::TestCase
114
115
  assert_equal("Accept: text/html", lines[4])
115
116
  end
116
117
 
118
+ def test_header_symbol
119
+ str = ""
120
+ @client.debug_dev = str
121
+ @client.post(serverurl + 'servlet', :header => {:'Content-Type' => 'application/json'}, :body => 'hello')
122
+ lines = str.split(/(?:\r?\n)+/).grep(/^Content-Type/)
123
+ assert_equal(2, lines.size) # 1 for both request and response
124
+ end
125
+
117
126
  def test_host_given
118
127
  str = ""
119
128
  @client.debug_dev = str
@@ -122,7 +131,7 @@ class TestHTTPClient < Test::Unit::TestCase
122
131
  assert_equal("= Request", lines[0])
123
132
  assert_equal("! CONNECTION ESTABLISHED", lines[2])
124
133
  assert_equal("GET / HTTP/1.1", lines[3])
125
- assert_equal("Host: localhost:#{serverport}", lines[6])
134
+ assert_equal("Host: localhost:#{serverport}", lines[7])
126
135
  #
127
136
  @client.reset_all
128
137
  str = ""
@@ -137,12 +146,24 @@ class TestHTTPClient < Test::Unit::TestCase
137
146
 
138
147
  def test_redirect_returns_not_modified
139
148
  assert_nothing_raised do
140
- timeout(2) do
149
+ ::Timeout.timeout(2) do
141
150
  @client.get(serverurl + 'status', {:status => 306}, {:follow_redirect => true})
142
151
  end
143
152
  end
144
153
  end
145
154
 
155
+ class LocationRemoveFilter
156
+ def filter_request(req); end
157
+ def filter_response(req, res); res.header.delete('Location'); end
158
+ end
159
+
160
+ def test_redirect_without_location_should_gracefully_fail
161
+ @client.request_filter << LocationRemoveFilter.new
162
+ assert_raises(HTTPClient::BadResponseError) do
163
+ @client.get(serverurl + 'redirect1', :follow_redirect => true)
164
+ end
165
+ end
166
+
146
167
  def test_protocol_version_http11
147
168
  assert_equal(nil, @client.protocol_version)
148
169
  str = ""
@@ -152,7 +173,7 @@ class TestHTTPClient < Test::Unit::TestCase
152
173
  assert_equal("= Request", lines[0])
153
174
  assert_equal("! CONNECTION ESTABLISHED", lines[2])
154
175
  assert_equal("GET / HTTP/1.1", lines[3])
155
- assert_equal("Host: localhost:#{serverport}", lines[6])
176
+ assert_equal("Host: localhost:#{serverport}", lines[7])
156
177
  @client.protocol_version = 'HTTP/1.1'
157
178
  assert_equal('HTTP/1.1', @client.protocol_version)
158
179
  str = ""
@@ -176,9 +197,9 @@ class TestHTTPClient < Test::Unit::TestCase
176
197
  setup_proxyserver
177
198
  escape_noproxy do
178
199
  begin
179
- @client.proxy = "http://"
180
- rescue
181
- assert_match(/InvalidURIError/, $!.class.to_s)
200
+ @client.proxy = "http://あ"
201
+ rescue => e
202
+ assert_match(/InvalidURIError/, e.class.to_s)
182
203
  end
183
204
  @client.proxy = ""
184
205
  assert_nil(@client.proxy)
@@ -518,7 +539,7 @@ EOS
518
539
 
519
540
  def test_no_content
520
541
  assert_nothing_raised do
521
- timeout(2) do
542
+ ::Timeout.timeout(2) do
522
543
  @client.get(serverurl + 'status', :status => 101)
523
544
  @client.get(serverurl + 'status', :status => 204)
524
545
  @client.get(serverurl + 'status', :status => 304)
@@ -554,19 +575,46 @@ EOS
554
575
  assert(called)
555
576
  end
556
577
 
578
+ def test_get_content_with_base_url
579
+ @client = HTTPClient.new(:base_url => serverurl)
580
+ assert_equal('hello', @client.get_content('/hello'))
581
+ assert_equal('hello', @client.get_content('/redirect1'))
582
+ assert_equal('hello', @client.get_content('/redirect2'))
583
+ @client.reset('/')
584
+ assert_raises(HTTPClient::BadResponseError) do
585
+ @client.get_content('/notfound')
586
+ end
587
+ assert_raises(HTTPClient::BadResponseError) do
588
+ @client.get_content('/redirect_self')
589
+ end
590
+ called = false
591
+ @client.redirect_uri_callback = lambda { |uri, res|
592
+ newuri = res.header['location'][0]
593
+ called = true
594
+ newuri
595
+ }
596
+ assert_equal('hello', @client.get_content('/relative_redirect'))
597
+ assert(called)
598
+ end
599
+
557
600
  GZIP_CONTENT = "\x1f\x8b\x08\x00\x1a\x96\xe0\x4c\x00\x03\xcb\x48\xcd\xc9\xc9\x07\x00\x86\xa6\x10\x36\x05\x00\x00\x00"
558
601
  DEFLATE_CONTENT = "\x78\x9c\xcb\x48\xcd\xc9\xc9\x07\x00\x06\x2c\x02\x15"
559
- GZIP_CONTENT.force_encoding('BINARY') if GZIP_CONTENT.respond_to?(:force_encoding)
560
- DEFLATE_CONTENT.force_encoding('BINARY') if DEFLATE_CONTENT.respond_to?(:force_encoding)
602
+ DEFLATE_NOHEADER_CONTENT = "x\x9C\xCBH\xCD\xC9\xC9\a\x00\x06,\x02\x15"
603
+ [GZIP_CONTENT, DEFLATE_CONTENT, DEFLATE_NOHEADER_CONTENT].each do |content|
604
+ content.force_encoding('BINARY') if content.respond_to?(:force_encoding)
605
+ end
561
606
  def test_get_gzipped_content
562
607
  @client.transparent_gzip_decompression = false
563
608
  content = @client.get_content(serverurl + 'compressed?enc=gzip')
564
609
  assert_not_equal('hello', content)
565
610
  assert_equal(GZIP_CONTENT, content)
566
611
  @client.transparent_gzip_decompression = true
612
+ @client.reset_all
567
613
  assert_equal('hello', @client.get_content(serverurl + 'compressed?enc=gzip'))
568
614
  assert_equal('hello', @client.get_content(serverurl + 'compressed?enc=deflate'))
615
+ assert_equal('hello', @client.get_content(serverurl + 'compressed?enc=deflate_noheader'))
569
616
  @client.transparent_gzip_decompression = false
617
+ @client.reset_all
570
618
  end
571
619
 
572
620
  def test_get_content_with_block
@@ -640,6 +688,32 @@ EOS
640
688
  assert_nil(res.contenttype)
641
689
  end
642
690
 
691
+ def test_get_with_base_url
692
+ @client = HTTPClient.new(:base_url => serverurl)
693
+ assert_equal("get", @client.get('/servlet').content)
694
+ param = {'1'=>'2', '3'=>'4'}
695
+ res = @client.get('/servlet', param)
696
+ assert_equal(param, params(res.header["x-query"][0]))
697
+ assert_nil(res.contenttype)
698
+ #
699
+ @client.base_url = serverurl[0...-1] + '/servlet'
700
+ url = '?5=6&7=8'
701
+ res = @client.get(url, param)
702
+ assert_equal(param.merge("5"=>"6", "7"=>"8"), params(res.header["x-query"][0]))
703
+ assert_nil(res.contenttype)
704
+ end
705
+
706
+ def test_get_with_default_header
707
+ @client = HTTPClient.new(:base_url => serverurl, :default_header => {'x-header' => 'custom'})
708
+ assert_equal('custom', @client.get('/servlet').headers['X-Header'])
709
+ @client.default_header = {'x-header' => 'custom2'}
710
+ assert_equal('custom2', @client.get('/servlet').headers['X-Header'])
711
+ # passing Hash overrides
712
+ assert_equal('custom3', @client.get('/servlet', :header => {'x-header' => 'custom3'}).headers['X-Header'])
713
+ # passing Array does not override
714
+ assert_equal('custom2, custom4', @client.get('/servlet', :header => [['x-header', 'custom4']]).headers['X-Header'])
715
+ end
716
+
643
717
  def test_head_follow_redirect
644
718
  expected = urify(serverurl + 'hello')
645
719
  assert_equal(expected, @client.head(serverurl + 'hello', :follow_redirect => true).header.request_uri)
@@ -650,7 +724,17 @@ EOS
650
724
  def test_get_follow_redirect
651
725
  assert_equal('hello', @client.get(serverurl + 'hello', :follow_redirect => true).body)
652
726
  assert_equal('hello', @client.get(serverurl + 'redirect1', :follow_redirect => true).body)
653
- assert_equal('hello', @client.get(serverurl + 'redirect2', :follow_redirect => true).body)
727
+
728
+ res = @client.get(serverurl + 'redirect2', :follow_redirect => true)
729
+ assert_equal('hello', res.body)
730
+ assert_equal("http://localhost:#{@serverport}/hello", res.header.request_uri.to_s)
731
+ assert_equal("http://localhost:#{@serverport}/redirect3", res.previous.header.request_uri.to_s)
732
+ assert_equal("http://localhost:#{@serverport}/redirect2", res.previous.previous.header.request_uri.to_s)
733
+ assert_equal(nil, res.previous.previous.previous)
734
+ end
735
+
736
+ def test_get_follow_redirect_with_query
737
+ assert_equal('hello?1=2&3=4', @client.get(serverurl + 'redirect1', :query => {1 => 2, 3 => 4}, :follow_redirect => true).body)
654
738
  end
655
739
 
656
740
  def test_get_async
@@ -661,12 +745,44 @@ EOS
661
745
  assert_equal(param, params(res.header["x-query"][0]))
662
746
  end
663
747
 
748
+ def test_get_async_with_base_url
749
+ param = {'1'=>'2', '3'=>'4'}
750
+ @client = HTTPClient.new(:base_url => serverurl)
751
+
752
+ # Use preconfigured :base_url
753
+ conn = @client.get_async('servlet', param)
754
+ Thread.pass while !conn.finished?
755
+ res = conn.pop
756
+ assert_equal(param, params(res.header["x-query"][0]))
757
+ # full URL still works
758
+ conn = @client.get_async(serverurl + 'servlet', param)
759
+ Thread.pass while !conn.finished?
760
+ res = conn.pop
761
+ assert_equal(param, params(res.header["x-query"][0]))
762
+ end
763
+
664
764
  def test_get_async_for_largebody
665
765
  conn = @client.get_async(serverurl + 'largebody')
666
766
  res = conn.pop
667
767
  assert_equal(1000*1000, res.content.read.length)
668
768
  end
669
769
 
770
+ if RUBY_VERSION > "1.9"
771
+ def test_post_async_with_default_internal
772
+ original_encoding = Encoding.default_internal
773
+ Encoding.default_internal = Encoding::UTF_8
774
+ begin
775
+ post_body = StringIO.new("こんにちは")
776
+ conn = @client.post_async(serverurl + 'servlet', post_body)
777
+ Thread.pass while !conn.finished?
778
+ res = conn.pop
779
+ assert_equal 'post,こんにちは', res.content.read
780
+ ensure
781
+ Encoding.default_internal = original_encoding
782
+ end
783
+ end
784
+ end
785
+
670
786
  def test_get_with_block
671
787
  called = false
672
788
  res = @client.get(serverurl + 'servlet') { |str|
@@ -678,23 +794,101 @@ EOS
678
794
  assert_nil(res.content)
679
795
  end
680
796
 
681
- def test_get_with_block_chunk_string_recycle
797
+ def test_get_with_block_arity_2
798
+ called = false
799
+ res = @client.get(serverurl + 'servlet') { |blk_res, str|
800
+ assert_equal(200, blk_res.status)
801
+ assert_equal('get', str)
802
+ called = true
803
+ }
804
+ assert(called)
805
+ # res does not have a content
806
+ assert_nil(res.content)
807
+ end
808
+
809
+ def test_get_with_block_and_redirects
810
+ called = false
811
+ res = @client.get(serverurl + 'servlet', :follow_redirect => true) { |str|
812
+ assert_equal('get', str)
813
+ called = true
814
+ }
815
+ assert(called)
816
+ # res does not have a content
817
+ assert_nil(res.content)
818
+ end
819
+
820
+ def test_get_with_block_arity_2_and_redirects
821
+ called = false
822
+ res = @client.get(serverurl + 'servlet', :follow_redirect => true) { |blk_res, str|
823
+ assert_equal(200, blk_res.status)
824
+ assert_equal('get', str)
825
+ called = true
826
+ }
827
+ assert(called)
828
+ # res does not have a content
829
+ assert_nil(res.content)
830
+ end
831
+
832
+ def test_get_with_block_string_recycle
682
833
  @client.read_block_size = 2
683
834
  body = []
684
- res = @client.get(serverurl + 'servlet') { |str|
835
+ _res = @client.get(serverurl + 'servlet') { |str|
685
836
  body << str
686
837
  }
687
838
  assert_equal(2, body.size)
688
839
  assert_equal("get", body.join) # Was "tt" by String object recycle...
689
840
  end
690
841
 
842
+ def test_get_with_block_chunked_string_recycle
843
+ server = TCPServer.open('localhost', 0)
844
+ server_thread = Thread.new {
845
+ Thread.abort_on_exception = true
846
+ sock = server.accept
847
+ create_keepalive_thread(1, sock)
848
+ }
849
+ url = "http://localhost:#{server.addr[1]}/"
850
+ body = []
851
+ begin
852
+ _res = @client.get(url + 'chunked') { |str|
853
+ body << str
854
+ }
855
+ ensure
856
+ server.close
857
+ server_thread.join
858
+ end
859
+ assert_equal('abcdefghijklmnopqrstuvwxyz1234567890abcdef', body.join)
860
+ end
861
+
691
862
  def test_post
692
- assert_equal("post", @client.post(serverurl + 'servlet').content[0, 4])
863
+ assert_equal("post", @client.post(serverurl + 'servlet', '').content[0, 4])
693
864
  param = {'1'=>'2', '3'=>'4'}
694
865
  res = @client.post(serverurl + 'servlet', param)
695
866
  assert_equal(param, params(res.header["x-query"][0]))
696
867
  end
697
868
 
869
+ def test_post_empty
870
+ @client.debug_dev = str = ''
871
+ # nil body means 'no content' that is allowed but WEBrick cannot handle it.
872
+ @client.post(serverurl + 'servlet', :body => nil)
873
+ # request does not have 'Content-Type'
874
+ assert_equal(1, str.scan(/content-type/i).size)
875
+ end
876
+
877
+ def test_post_with_query
878
+ # this {:query => 'query'} recognized as body
879
+ res = @client.post(serverurl + 'servlet', :query => 'query')
880
+ assert_equal("post", res.content[0, 4])
881
+ assert_equal("query=query", res.headers["X-Query"])
882
+ assert_equal("", res.headers["X-Request-Query"])
883
+ end
884
+
885
+ def test_post_with_query_and_body
886
+ res = @client.post(serverurl + 'servlet', :query => {:query => 'query'}, :body => {:body => 'body'})
887
+ assert_equal("post", res.content[0, 4])
888
+ assert_equal("body=body", res.headers["X-Query"])
889
+ assert_equal("query=query", res.headers["X-Request-Query"])
890
+ end
891
+
698
892
  def test_post_follow_redirect
699
893
  assert_equal('hello', @client.post(serverurl + 'hello', :follow_redirect => true).body)
700
894
  assert_equal('hello', @client.post(serverurl + 'redirect1', :follow_redirect => true).body)
@@ -704,18 +898,18 @@ EOS
704
898
  def test_post_with_content_type
705
899
  param = [['1', '2'], ['3', '4']]
706
900
  ext = {'content-type' => 'application/x-www-form-urlencoded', 'hello' => 'world'}
707
- assert_equal("post", @client.post(serverurl + 'servlet').content[0, 4], ext)
901
+ assert_equal("post", @client.post(serverurl + 'servlet', '').content[0, 4], ext)
708
902
  res = @client.post(serverurl + 'servlet', param, ext)
709
903
  assert_equal(Hash[param], params(res.header["x-query"][0]))
710
904
  #
711
905
  ext = [['content-type', 'multipart/form-data'], ['hello', 'world']]
712
- assert_equal("post", @client.post(serverurl + 'servlet').content[0, 4], ext)
906
+ assert_equal("post", @client.post(serverurl + 'servlet', '').content[0, 4], ext)
713
907
  res = @client.post(serverurl + 'servlet', param, ext)
714
908
  assert_match(/Content-Disposition: form-data; name="1"/, res.content)
715
909
  assert_match(/Content-Disposition: form-data; name="3"/, res.content)
716
910
  #
717
911
  ext = {'content-type' => 'multipart/form-data; boundary=hello'}
718
- assert_equal("post", @client.post(serverurl + 'servlet').content[0, 4], ext)
912
+ assert_equal("post", @client.post(serverurl + 'servlet', '').content[0, 4], ext)
719
913
  res = @client.post(serverurl + 'servlet', param, ext)
720
914
  assert_match(/Content-Disposition: form-data; name="1"/, res.content)
721
915
  assert_match(/Content-Disposition: form-data; name="3"/, res.content)
@@ -725,7 +919,7 @@ EOS
725
919
  def test_post_with_custom_multipart_and_boolean_params
726
920
  param = [['boolean_true', true]]
727
921
  ext = { 'content-type' => 'multipart/form-data' }
728
- assert_equal("post", @client.post(serverurl + 'servlet').content[0, 4], ext)
922
+ assert_equal("post", @client.post(serverurl + 'servlet', '').content[0, 4], ext)
729
923
  res = @client.post(serverurl + 'servlet', param, ext)
730
924
  assert_match(/Content-Disposition: form-data; name="boolean_true"\r\n\r\ntrue\r\n/, res.content)
731
925
  #
@@ -777,7 +971,8 @@ EOS
777
971
  assert_match(/\r\n2\r\n/m, res.content)
778
972
  assert_match(/\r\nContent-Disposition: form-data; name="3"; filename=""\r\n/m, res.content)
779
973
  assert_match(/\r\nContent-Length:/m, str.string)
780
- assert_equal(3, myio.called)
974
+ # HTTPClient reads from head to 'size'; CHUNK_SIZE bytes then 1 byte, that's all.
975
+ assert_equal(2, myio.called)
781
976
  end
782
977
 
783
978
  def test_post_with_io_nosize # streaming + chunked post
@@ -794,6 +989,42 @@ EOS
794
989
  assert_match(/\r\nTransfer-Encoding: chunked\r\n/m, str.string)
795
990
  end
796
991
 
992
+ def test_post_with_sized_io
993
+ myio = StringIO.new("45")
994
+ def myio.size
995
+ 1
996
+ end
997
+ res = @client.post(serverurl + 'servlet', myio)
998
+ assert_equal('post,4', res.content)
999
+ end
1000
+
1001
+ def test_post_with_sized_io_part
1002
+ myio = StringIO.new("45")
1003
+ def myio.size
1004
+ 1
1005
+ end
1006
+ @client.debug_dev = str = StringIO.new
1007
+ _res = @client.post(serverurl + 'servlet', { :file => myio })
1008
+ assert_match(/\r\n4\r\n/, str.string, 'should send "4" not "45"')
1009
+ end
1010
+
1011
+ def test_post_with_unknown_sized_io_part
1012
+ myio1 = StringIO.new("123")
1013
+ myio2 = StringIO.new("45")
1014
+ class << myio1
1015
+ undef :size
1016
+ end
1017
+ class << myio2
1018
+ # This does not work because other file is 'unknown sized'
1019
+ def size
1020
+ 1
1021
+ end
1022
+ end
1023
+ @client.debug_dev = str = StringIO.new
1024
+ _res = @client.post(serverurl + 'servlet', { :file1 => myio1, :file2 => myio2 })
1025
+ assert_match(/\r\n45\r\n/, str.string)
1026
+ end
1027
+
797
1028
  def test_post_async
798
1029
  param = {'1'=>'2', '3'=>'4'}
799
1030
  conn = @client.post_async(serverurl + 'servlet', param)
@@ -804,7 +1035,7 @@ EOS
804
1035
 
805
1036
  def test_post_with_block
806
1037
  called = false
807
- res = @client.post(serverurl + 'servlet') { |str|
1038
+ res = @client.post(serverurl + 'servlet', '') { |str|
808
1039
  assert_equal('post,', str)
809
1040
  called = true
810
1041
  }
@@ -824,7 +1055,7 @@ EOS
824
1055
 
825
1056
  def test_post_with_custom_multipart
826
1057
  ext = {'content-type' => 'multipart/form-data'}
827
- assert_equal("post", @client.post(serverurl + 'servlet').content[0, 4], ext)
1058
+ assert_equal("post", @client.post(serverurl + 'servlet', '').content[0, 4], ext)
828
1059
  body = [{ 'Content-Disposition' => 'form-data; name="1"', :content => "2"},
829
1060
  { 'Content-Disposition' => 'form-data; name="3"', :content => "4"}]
830
1061
  res = @client.post(serverurl + 'servlet', body, ext)
@@ -832,7 +1063,7 @@ EOS
832
1063
  assert_match(/Content-Disposition: form-data; name="3"/, res.content)
833
1064
  #
834
1065
  ext = {'content-type' => 'multipart/form-data; boundary=hello'}
835
- assert_equal("post", @client.post(serverurl + 'servlet').content[0, 4], ext)
1066
+ assert_equal("post", @client.post(serverurl + 'servlet', '').content[0, 4], ext)
836
1067
  res = @client.post(serverurl + 'servlet', body, ext)
837
1068
  assert_match(/Content-Disposition: form-data; name="1"/, res.content)
838
1069
  assert_match(/Content-Disposition: form-data; name="3"/, res.content)
@@ -842,6 +1073,10 @@ EOS
842
1073
  def test_post_with_custom_multipart_and_file
843
1074
  STDOUT.sync = true
844
1075
  File.open(__FILE__) do |file|
1076
+ def file.original_filename
1077
+ 'file.txt'
1078
+ end
1079
+
845
1080
  ext = { 'Content-Type' => 'multipart/alternative' }
846
1081
  body = [{ 'Content-Type' => 'text/plain', :content => "this is only a test" },
847
1082
  { 'Content-Type' => 'application/x-ruby', :content => file }]
@@ -849,12 +1084,43 @@ EOS
849
1084
  assert_match(/^Content-Type: text\/plain\r\n/m, res.content)
850
1085
  assert_match(/^this is only a test\r\n/m, res.content)
851
1086
  assert_match(/^Content-Type: application\/x-ruby\r\n/m, res.content)
1087
+ assert_match(/Content-Disposition: form-data; name="3"; filename="file.txt"/, res.content)
852
1088
  assert_match(/FIND_TAG_IN_THIS_FILE/, res.content)
853
1089
  end
854
1090
  end
855
1091
 
1092
+ def test_patch
1093
+ assert_equal("patch", @client.patch(serverurl + 'servlet', '').content)
1094
+ param = {'1'=>'2', '3'=>'4'}
1095
+ @client.debug_dev = str = ''
1096
+ res = @client.patch(serverurl + 'servlet', param)
1097
+ assert_equal(param, params(res.header["x-query"][0]))
1098
+ assert_equal('Content-Type: application/x-www-form-urlencoded', str.split(/\r?\n/)[5])
1099
+ end
1100
+
1101
+ def test_patch_with_query_and_body
1102
+ res = @client.patch(serverurl + 'servlet', :query => {:query => 'query'}, :body => {:body => 'body'})
1103
+ assert_equal("patch", res.content)
1104
+ assert_equal("body=body", res.headers["X-Query"])
1105
+ assert_equal("query=query", res.headers["X-Request-Query"])
1106
+ end
1107
+
1108
+ def test_patch_bytesize
1109
+ res = @client.patch(serverurl + 'servlet', 'txt' => 'あいうえお')
1110
+ assert_equal('txt=%E3%81%82%E3%81%84%E3%81%86%E3%81%88%E3%81%8A', res.header["x-query"][0])
1111
+ assert_equal('15', res.header["x-size"][0])
1112
+ end
1113
+
1114
+ def test_patch_async
1115
+ param = {'1'=>'2', '3'=>'4'}
1116
+ conn = @client.patch_async(serverurl + 'servlet', param)
1117
+ Thread.pass while !conn.finished?
1118
+ res = conn.pop
1119
+ assert_equal(param, params(res.header["x-query"][0]))
1120
+ end
1121
+
856
1122
  def test_put
857
- assert_equal("put", @client.put(serverurl + 'servlet').content)
1123
+ assert_equal("put", @client.put(serverurl + 'servlet', '').content)
858
1124
  param = {'1'=>'2', '3'=>'4'}
859
1125
  @client.debug_dev = str = ''
860
1126
  res = @client.put(serverurl + 'servlet', param)
@@ -862,6 +1128,13 @@ EOS
862
1128
  assert_equal('Content-Type: application/x-www-form-urlencoded', str.split(/\r?\n/)[5])
863
1129
  end
864
1130
 
1131
+ def test_put_with_query_and_body
1132
+ res = @client.put(serverurl + 'servlet', :query => {:query => 'query'}, :body => {:body => 'body'})
1133
+ assert_equal("put", res.content)
1134
+ assert_equal("body=body", res.headers["X-Query"])
1135
+ assert_equal("query=query", res.headers["X-Request-Query"])
1136
+ end
1137
+
865
1138
  def test_put_bytesize
866
1139
  res = @client.put(serverurl + 'servlet', 'txt' => 'あいうえお')
867
1140
  assert_equal('txt=%E3%81%82%E3%81%84%E3%81%86%E3%81%88%E3%81%8A', res.header["x-query"][0])
@@ -880,6 +1153,19 @@ EOS
880
1153
  assert_equal("delete", @client.delete(serverurl + 'servlet').content)
881
1154
  end
882
1155
 
1156
+ def test_delete_with_query
1157
+ res = @client.delete(serverurl + 'servlet', :query => {:query => 'query'})
1158
+ assert_equal("delete", res.content)
1159
+ assert_equal('query=query', res.headers['X-Request-Query'])
1160
+ end
1161
+
1162
+ def test_delete_with_query_and_body
1163
+ res = @client.delete(serverurl + 'servlet', :query => {:query => 'query'}, :body => {:body => 'body'})
1164
+ assert_equal("delete", res.content)
1165
+ assert_equal('query=query', res.headers['X-Request-Query'])
1166
+ assert_equal('body=body', res.headers['X-Query'])
1167
+ end
1168
+
883
1169
  # Not prohibited by spec, but normally it's ignored
884
1170
  def test_delete_with_body
885
1171
  param = {'1'=>'2', '3'=>'4'}
@@ -896,7 +1182,23 @@ EOS
896
1182
  end
897
1183
 
898
1184
  def test_options
899
- assert_equal("options", @client.options(serverurl + 'servlet').content)
1185
+ assert_equal('options', @client.options(serverurl + 'servlet').content)
1186
+ end
1187
+
1188
+ def test_options_with_header
1189
+ res = @client.options(serverurl + 'servlet', {'x-header' => 'header'})
1190
+ assert_equal('header', res.headers['X-Header'])
1191
+ end
1192
+
1193
+ def test_options_with_body
1194
+ res = @client.options(serverurl + 'servlet', :body => 'body')
1195
+ assert_equal('body', res.headers['X-Body'])
1196
+ end
1197
+
1198
+ def test_options_with_body_and_header
1199
+ res = @client.options(serverurl + 'servlet', :body => 'body', :header => {'x-header' => 'header'})
1200
+ assert_equal('header', res.headers['X-Header'])
1201
+ assert_equal('body', res.headers['X-Body'])
900
1202
  end
901
1203
 
902
1204
  def test_options_async
@@ -951,6 +1253,7 @@ EOS
951
1253
 
952
1254
  def test_chunked
953
1255
  assert_equal('chunked', @client.get_content(serverurl + 'chunked', { 'msg' => 'chunked' }))
1256
+ assert_equal('あいうえお', @client.get_content(serverurl + 'chunked', { 'msg' => 'あいうえお' }))
954
1257
  end
955
1258
 
956
1259
  def test_chunked_empty
@@ -1024,7 +1327,7 @@ EOS
1024
1327
 
1025
1328
  def test_http_custom_date_header
1026
1329
  @client.debug_dev = (str = "")
1027
- res = @client.get(serverurl + 'hello', :header => {'Date' => 'foo'})
1330
+ _res = @client.get(serverurl + 'hello', :header => {'Date' => 'foo'})
1028
1331
  lines = str.split(/(?:\r?\n)+/)
1029
1332
  assert_equal('Date: foo', lines[4])
1030
1333
  end
@@ -1052,35 +1355,32 @@ EOS
1052
1355
 
1053
1356
  def test_receive_timeout
1054
1357
  # this test takes 2 sec
1055
- assert_equal('hello', @client.get_content(serverurl + 'sleep?sec=2'))
1358
+ assert_equal('hello?sec=2', @client.get_content(serverurl + 'sleep?sec=2'))
1056
1359
  @client.receive_timeout = 1
1057
- assert_equal('hello', @client.get_content(serverurl + 'sleep?sec=0'))
1360
+ @client.reset_all
1361
+ assert_equal('hello?sec=0', @client.get_content(serverurl + 'sleep?sec=0'))
1058
1362
  assert_raise(HTTPClient::ReceiveTimeoutError) do
1059
1363
  @client.get_content(serverurl + 'sleep?sec=2')
1060
1364
  end
1061
1365
  @client.receive_timeout = 3
1062
- assert_equal('hello', @client.get_content(serverurl + 'sleep?sec=2'))
1366
+ @client.reset_all
1367
+ assert_equal('hello?sec=2', @client.get_content(serverurl + 'sleep?sec=2'))
1063
1368
  end
1064
1369
 
1065
1370
  def test_receive_timeout_post
1066
1371
  # this test takes 2 sec
1067
1372
  assert_equal('hello', @client.post(serverurl + 'sleep', :sec => 2).content)
1068
1373
  @client.receive_timeout = 1
1374
+ @client.reset_all
1069
1375
  assert_equal('hello', @client.post(serverurl + 'sleep', :sec => 0).content)
1070
1376
  assert_raise(HTTPClient::ReceiveTimeoutError) do
1071
1377
  @client.post(serverurl + 'sleep', :sec => 2)
1072
1378
  end
1073
1379
  @client.receive_timeout = 3
1380
+ @client.reset_all
1074
1381
  assert_equal('hello', @client.post(serverurl + 'sleep', :sec => 2).content)
1075
1382
  end
1076
1383
 
1077
- def test_async_error
1078
- assert_raise( SocketError ) do
1079
- conn = @client.get_async("http://non-existing-host/")
1080
- conn.pop
1081
- end
1082
- end
1083
-
1084
1384
  def test_reset
1085
1385
  url = serverurl + 'servlet'
1086
1386
  assert_nothing_raised do
@@ -1101,22 +1401,18 @@ EOS
1101
1401
  end
1102
1402
 
1103
1403
  def test_cookies
1104
- cookiefile = File.join(File.dirname(File.expand_path(__FILE__)), 'test_cookies_file')
1105
- File.open(cookiefile, "wb") do |f|
1106
- f << "http://rubyforge.org/account/login.php\tsession_ser\tLjEwMy45Ni40Ni0q%2A-fa0537de8cc31\t2000000000\t.rubyforge.org\t/\t13\n"
1107
- end
1108
- @client.set_cookie_store(cookiefile)
1109
- cookie = @client.cookie_manager.cookies.first
1110
- url = cookie.url
1111
- assert(cookie.domain_match(url.host, cookie.domain))
1404
+ cookiefile = Tempfile.new('test_cookies_file')
1405
+ File.open(cookiefile.path, "wb") do |f|
1406
+ f << "http://rubyforge.org/account/login.php\tsession_ser\tLjEwMy45Ni40Ni0q%2A-fa0537de8cc31\t2000000000\trubyforge.org\t/account/\t9\n"
1407
+ end
1408
+ @client.set_cookie_store(cookiefile.path)
1112
1409
  #
1113
1410
  @client.reset_all
1114
- @client.test_loopback_http_response << "HTTP/1.0 200 OK\nSet-Cookie: foo=bar; expires=#{Time.at(1924873200).gmtime.httpdate}\n\nOK"
1411
+ @client.test_loopback_http_response << "HTTP/1.0 200 OK\nSet-Cookie: session_ser=bar; expires=#{Time.at(1924873200).gmtime.httpdate}\n\nOK"
1115
1412
  @client.get_content('http://rubyforge.org/account/login.php')
1116
1413
  @client.save_cookie_store
1117
- str = File.read(cookiefile)
1118
- assert_match(%r(http://rubyforge.org/account/login.php\tfoo\tbar\t1924873200\trubyforge.org\t/account\t1), str)
1119
- File.unlink(cookiefile)
1414
+ str = File.read(cookiefile.path)
1415
+ assert_match(%r(http://rubyforge.org/account/login.php\tsession_ser\tbar\t1924873200\trubyforge.org\t/account/\t9), str)
1120
1416
  end
1121
1417
 
1122
1418
  def test_eof_error_length
@@ -1240,6 +1536,7 @@ EOS
1240
1536
  assert_equal('text/plain', HTTP::Message.mime_type('foo.txt'))
1241
1537
  assert_equal('text/html', HTTP::Message.mime_type('foo.html'))
1242
1538
  assert_equal('text/html', HTTP::Message.mime_type('foo.htm'))
1539
+ assert_equal('text/xml', HTTP::Message.mime_type('foo.xml'))
1243
1540
  assert_equal('application/msword', HTTP::Message.mime_type('foo.doc'))
1244
1541
  assert_equal('image/png', HTTP::Message.mime_type('foo.png'))
1245
1542
  assert_equal('image/gif', HTTP::Message.mime_type('foo.gif'))
@@ -1342,6 +1639,7 @@ EOS
1342
1639
  res = HTTP::Message.new_response('response')
1343
1640
  res.contenttype = 'text/plain'
1344
1641
  res.header.body_date = Time.at(946652400)
1642
+ res.header.request_uri = 'http://www.example.com/'
1345
1643
  assert_nil(res.cookies)
1346
1644
  #
1347
1645
  res.header['Set-Cookie'] = [
@@ -1418,8 +1716,11 @@ EOS
1418
1716
  server = TCPServer.open('127.0.0.1', 0)
1419
1717
  server.listen(30) # set enough backlogs
1420
1718
  endpoint = "http://127.0.0.1:#{server.addr[1]}/"
1421
- Thread.new {
1719
+ queue = Queue.new
1720
+ Thread.new(queue) { |qs|
1422
1721
  Thread.abort_on_exception = true
1722
+ # want 5 requests issued
1723
+ 5.times { qs.pop }
1423
1724
  # emulate 10 keep-alive connections
1424
1725
  10.times do |idx|
1425
1726
  sock = server.accept
@@ -1448,22 +1749,29 @@ EOS
1448
1749
  sock.close
1449
1750
  end
1450
1751
  }
1451
- # allocate 10 keep-alive connections
1752
+ # try to allocate 10 keep-alive connections; it's a race so some
1753
+ # threads can reuse the connection so actual number of keep-alive
1754
+ # connections should be smaller than 10.
1452
1755
  (0...10).to_a.map {
1453
- Thread.new {
1454
- assert_equal("12345", client.get(endpoint).content)
1756
+ Thread.new(queue) { |qc|
1757
+ Thread.abort_on_exception = true
1758
+ conn = client.get_async(endpoint)
1759
+ qc.push(true)
1760
+ assert_equal("12345", conn.pop.content.read)
1455
1761
  }
1456
1762
  }.each { |th| th.join }
1457
- # send 5 requests, which should get KeepAliveDesconnected.
1458
- # doing these requests, rest keep-alive connections are invalidated.
1763
+ # send 5 requests, some of these should get KeepAliveDesconnected
1764
+ # but should retry with new connection.
1459
1765
  (0...5).to_a.map {
1460
1766
  Thread.new {
1767
+ Thread.abort_on_exception = true
1461
1768
  assert_equal("23456", client.get(endpoint).content)
1462
1769
  }
1463
1770
  }.each { |th| th.join }
1464
- # rest requests won't get KeepAliveDisconnected; how can I check this?
1771
+ # rest requests won't get KeepAliveDisconnected
1465
1772
  (0...10).to_a.map {
1466
1773
  Thread.new {
1774
+ Thread.abort_on_exception = true
1467
1775
  assert_equal("34567", client.get(endpoint).content)
1468
1776
  }
1469
1777
  }.each { |th| th.join }
@@ -1522,6 +1830,19 @@ EOS
1522
1830
  end
1523
1831
  end
1524
1832
 
1833
+ def test_strict_response_size_check
1834
+ @client.strict_response_size_check = false
1835
+ @client.test_loopback_http_response << "HTTP/1.0 200 OK\r\nContent-Length: 12345\r\n\r\nhello world"
1836
+ assert_equal('hello world', @client.get_content('http://dummy'))
1837
+
1838
+ @client.reset_all
1839
+ @client.strict_response_size_check = true
1840
+ @client.test_loopback_http_response << "HTTP/1.0 200 OK\r\nContent-Length: 12345\r\n\r\nhello world"
1841
+ assert_raise(HTTPClient::BadResponseError) do
1842
+ @client.get_content('http://dummy')
1843
+ end
1844
+ end
1845
+
1525
1846
  def test_socket_local
1526
1847
  @client.socket_local.host = '127.0.0.1'
1527
1848
  assert_equal('hello', @client.get_content(serverurl + 'hello'))
@@ -1557,6 +1878,48 @@ EOS
1557
1878
  end
1558
1879
  end
1559
1880
 
1881
+ def test_ipv6literaladdress_in_uri
1882
+ server = TCPServer.open('::1', 0) rescue return # Skip if IPv6 is unavailable.
1883
+ server_thread = Thread.new {
1884
+ Thread.abort_on_exception = true
1885
+ sock = server.accept
1886
+ while line = sock.gets
1887
+ break if line.chomp.empty?
1888
+ end
1889
+ sock.write("HTTP/1.1 200 OK\r\n")
1890
+ sock.write("Content-Length: 5\r\n")
1891
+ sock.write("\r\n")
1892
+ sock.write("12345")
1893
+ sock.close
1894
+ }
1895
+ uri = "http://[::1]:#{server.addr[1]}/"
1896
+ begin
1897
+ assert_equal('12345', @client.get(uri).body)
1898
+ ensure
1899
+ server.close
1900
+ server_thread.kill
1901
+ server_thread.join
1902
+ end
1903
+ end
1904
+
1905
+ def test_uri_no_schema
1906
+ assert_raise(ArgumentError) do
1907
+ @client.get_content("www.example.com")
1908
+ end
1909
+ end
1910
+
1911
+ def test_tcp_keepalive
1912
+ @client.tcp_keepalive = true
1913
+ @client.get(serverurl)
1914
+
1915
+ # expecting HTTP keepalive caches the socket
1916
+ session = @client.instance_variable_get(:@session_manager).send(:get_cached_session, HTTPClient::Site.new(URI.parse(serverurl)))
1917
+ socket = session.instance_variable_get(:@socket)
1918
+
1919
+ assert_true(session.tcp_keepalive)
1920
+ assert_equal(Socket::SO_KEEPALIVE, socket.getsockopt(Socket::SOL_SOCKET, Socket::SO_KEEPALIVE).optname)
1921
+ end
1922
+
1560
1923
  private
1561
1924
 
1562
1925
  def check_query_get(query)
@@ -1594,53 +1957,53 @@ private
1594
1957
  @server_thread = start_server_thread(@server)
1595
1958
  end
1596
1959
 
1597
- def escape_noproxy
1598
- backup = HTTPClient::NO_PROXY_HOSTS.dup
1599
- HTTPClient::NO_PROXY_HOSTS.clear
1600
- yield
1601
- ensure
1602
- HTTPClient::NO_PROXY_HOSTS.replace(backup)
1960
+ def add_query_string(req)
1961
+ if req.query_string
1962
+ '?' + req.query_string
1963
+ else
1964
+ ''
1965
+ end
1603
1966
  end
1604
1967
 
1605
1968
  def do_hello(req, res)
1606
1969
  res['content-type'] = 'text/html'
1607
- res.body = "hello"
1970
+ res.body = "hello" + add_query_string(req)
1608
1971
  end
1609
1972
 
1610
1973
  def do_sleep(req, res)
1611
1974
  sec = req.query['sec'].to_i
1612
1975
  sleep sec
1613
1976
  res['content-type'] = 'text/html'
1614
- res.body = "hello"
1977
+ res.body = "hello" + add_query_string(req)
1615
1978
  end
1616
1979
 
1617
1980
  def do_servlet_redirect(req, res)
1618
- res.set_redirect(WEBrick::HTTPStatus::Found, serverurl + "servlet")
1981
+ res.set_redirect(WEBrick::HTTPStatus::Found, serverurl + "servlet" + add_query_string(req))
1619
1982
  end
1620
1983
 
1621
1984
  def do_redirect1(req, res)
1622
- res.set_redirect(WEBrick::HTTPStatus::MovedPermanently, serverurl + "hello")
1985
+ res.set_redirect(WEBrick::HTTPStatus::MovedPermanently, serverurl + "hello" + add_query_string(req))
1623
1986
  end
1624
1987
 
1625
1988
  def do_redirect2(req, res)
1626
- res.set_redirect(WEBrick::HTTPStatus::TemporaryRedirect, serverurl + "redirect3")
1989
+ res.set_redirect(WEBrick::HTTPStatus::TemporaryRedirect, serverurl + "redirect3" + add_query_string(req))
1627
1990
  end
1628
1991
 
1629
1992
  def do_redirect3(req, res)
1630
- res.set_redirect(WEBrick::HTTPStatus::Found, serverurl + "hello")
1993
+ res.set_redirect(WEBrick::HTTPStatus::Found, serverurl + "hello" + add_query_string(req))
1631
1994
  end
1632
1995
 
1633
1996
  def do_redirect_self(req, res)
1634
- res.set_redirect(WEBrick::HTTPStatus::Found, serverurl + "redirect_self")
1997
+ res.set_redirect(WEBrick::HTTPStatus::Found, serverurl + "redirect_self" + add_query_string(req))
1635
1998
  end
1636
1999
 
1637
2000
  def do_relative_redirect(req, res)
1638
- res.set_redirect(WEBrick::HTTPStatus::Found, "hello")
2001
+ res.set_redirect(WEBrick::HTTPStatus::Found, "hello" + add_query_string(req))
1639
2002
  end
1640
2003
 
1641
2004
  def do_redirect_see_other(req, res)
1642
2005
  if req.request_method == 'POST'
1643
- res.set_redirect(WEBrick::HTTPStatus::SeeOther, serverurl + "redirect_see_other") # self
2006
+ res.set_redirect(WEBrick::HTTPStatus::SeeOther, serverurl + "redirect_see_other" + add_query_string(req)) # self
1644
2007
  else
1645
2008
  res.body = 'hello'
1646
2009
  end
@@ -1648,6 +2011,7 @@ private
1648
2011
 
1649
2012
  def do_chunked(req, res)
1650
2013
  res.chunked = true
2014
+ res['content-type'] = 'text/plain; charset=UTF-8'
1651
2015
  piper, pipew = IO.pipe
1652
2016
  res.body = piper
1653
2017
  pipew << req.query['msg']
@@ -1667,6 +2031,9 @@ private
1667
2031
  elsif req.query['enc'] == 'deflate'
1668
2032
  res['content-encoding'] = 'deflate'
1669
2033
  res.body = DEFLATE_CONTENT
2034
+ elsif req.query['enc'] == 'deflate_noheader'
2035
+ res['content-encoding'] = 'deflate'
2036
+ res.body = DEFLATE_NOHEADER_CONTENT
1670
2037
  end
1671
2038
  end
1672
2039
 
@@ -1700,6 +2067,7 @@ private
1700
2067
 
1701
2068
  def do_GET(req, res)
1702
2069
  res.body = 'get'
2070
+ res['x-header'] = req['X-Header']
1703
2071
  res["x-query"] = query_response(req)
1704
2072
  end
1705
2073
 
@@ -1707,6 +2075,15 @@ private
1707
2075
  res["content-type"] = "text/plain" # iso-8859-1, not US-ASCII
1708
2076
  res.body = 'post,' + req.body.to_s
1709
2077
  res["x-query"] = body_response(req)
2078
+ res["x-request-query"] = req.query_string
2079
+ end
2080
+
2081
+ def do_PATCH(req, res)
2082
+ res["x-query"] = body_response(req)
2083
+ param = WEBrick::HTTPUtils.parse_query(req.body) || {}
2084
+ res["x-size"] = (param['txt'] || '').size
2085
+ res.body = param['txt'] || 'patch'
2086
+ res["x-request-query"] = req.query_string
1710
2087
  end
1711
2088
 
1712
2089
  def do_PUT(req, res)
@@ -1714,15 +2091,19 @@ private
1714
2091
  param = WEBrick::HTTPUtils.parse_query(req.body) || {}
1715
2092
  res["x-size"] = (param['txt'] || '').size
1716
2093
  res.body = param['txt'] || 'put'
2094
+ res["x-request-query"] = req.query_string
1717
2095
  end
1718
2096
 
1719
2097
  def do_DELETE(req, res)
1720
2098
  res.body = 'delete'
2099
+ res["x-query"] = body_response(req)
2100
+ res["x-request-query"] = req.query_string
1721
2101
  end
1722
2102
 
1723
2103
  def do_OPTIONS(req, res)
1724
- # check RFC for legal response.
1725
2104
  res.body = 'options'
2105
+ res['x-header'] = req['X-Header']
2106
+ res['x-body'] = req.body
1726
2107
  end
1727
2108
 
1728
2109
  def do_PROPFIND(req, res)