httpclient 2.3.0.1 → 2.8.3

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