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.
- checksums.yaml +7 -0
- data/README.md +85 -0
- data/bin/httpclient +18 -6
- data/bin/jsonclient +85 -0
- data/lib/http-access2.rb +1 -1
- data/lib/httpclient.rb +262 -88
- data/lib/httpclient/auth.rb +269 -244
- data/lib/httpclient/cacert.pem +3952 -0
- data/lib/httpclient/cacert1024.pem +3866 -0
- data/lib/httpclient/connection.rb +1 -1
- data/lib/httpclient/cookie.rb +161 -514
- data/lib/httpclient/http.rb +57 -21
- data/lib/httpclient/include_client.rb +2 -0
- data/lib/httpclient/jruby_ssl_socket.rb +588 -0
- data/lib/httpclient/session.rb +259 -317
- data/lib/httpclient/ssl_config.rb +141 -188
- data/lib/httpclient/ssl_socket.rb +150 -0
- data/lib/httpclient/timeout.rb +1 -1
- data/lib/httpclient/util.rb +62 -1
- data/lib/httpclient/version.rb +1 -1
- data/lib/httpclient/webagent-cookie.rb +459 -0
- data/lib/jsonclient.rb +63 -0
- data/lib/oauthclient.rb +2 -1
- data/sample/jsonclient.rb +67 -0
- data/sample/oauth_twitter.rb +4 -4
- data/test/{ca-chain.cert → ca-chain.pem} +0 -0
- data/test/client-pass.key +18 -0
- data/test/helper.rb +10 -8
- data/test/jruby_ssl_socket/test_pemutils.rb +32 -0
- data/test/test_auth.rb +175 -4
- data/test/test_cookie.rb +147 -243
- data/test/test_http-access2.rb +17 -16
- data/test/test_httpclient.rb +458 -77
- data/test/test_jsonclient.rb +80 -0
- data/test/test_ssl.rb +341 -17
- data/test/test_webagent-cookie.rb +465 -0
- metadata +57 -55
- data/README.txt +0 -721
- data/lib/httpclient/cacert.p7s +0 -1858
- data/lib/httpclient/cacert_sha1.p7s +0 -1858
- data/sample/oauth_salesforce_10.rb +0 -63
data/test/test_http-access2.rb
CHANGED
@@ -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[
|
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[
|
85
|
-
assert_equal("= Response", lines[
|
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[
|
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/,
|
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 =
|
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
|
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
|
-
|
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
|
data/test/test_httpclient.rb
CHANGED
@@ -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[
|
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[
|
81
|
-
assert_equal("= Response", lines[
|
82
|
-
assert_match(/^hello$/, lines[
|
83
|
-
assert_match(/^world$/, lines[
|
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[
|
98
|
-
assert_equal("= Response", lines[
|
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[
|
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[
|
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[
|
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/,
|
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
|
-
|
560
|
-
DEFLATE_CONTENT.
|
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
|
-
|
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
|
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
|
-
|
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
|
-
|
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(
|
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
|
-
|
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
|
-
|
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
|
-
|
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 =
|
1105
|
-
File.open(cookiefile, "wb") do |f|
|
1106
|
-
f << "http://rubyforge.org/account/login.php\tsession_ser\tLjEwMy45Ni40Ni0q%2A-fa0537de8cc31\t2000000000\
|
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:
|
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\
|
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
|
-
|
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
|
-
|
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,
|
1458
|
-
#
|
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
|
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
|
1598
|
-
|
1599
|
-
|
1600
|
-
|
1601
|
-
|
1602
|
-
|
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)
|