glebtv-httpclient 3.1.1 → 3.2.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/.coveralls.yml +1 -0
  3. data/.gitignore +8 -0
  4. data/.ruby-gemset +1 -0
  5. data/.ruby-version +1 -0
  6. data/.travis.yml +6 -0
  7. data/CHANGELOG.rdoc +653 -0
  8. data/Gemfile +12 -0
  9. data/Gemfile.lock +284 -0
  10. data/README.md +7 -2
  11. data/Rakefile +22 -0
  12. data/bin/httpclient +1 -1
  13. data/dist_key/cacerts.pem +1808 -0
  14. data/dist_key/cert.pem +24 -0
  15. data/dist_key/gen_dist_cert.rb +29 -0
  16. data/httpclient.gemspec +33 -0
  17. data/lib/httpclient.rb +59 -15
  18. data/lib/httpclient/lru_cache.rb +171 -0
  19. data/lib/httpclient/lru_threadsafe.rb +29 -0
  20. data/lib/httpclient/session.rb +52 -13
  21. data/lib/httpclient/ssl_config.rb +4 -3
  22. data/lib/httpclient/version.rb +1 -1
  23. data/sample/ssl/trust_certs/.keep_me +0 -0
  24. data/spec/http_message_spec.rb +124 -0
  25. data/spec/httpclient_spec.rb +322 -0
  26. data/spec/keepalive_spec.rb +129 -0
  27. data/spec/spec_helper.rb +40 -0
  28. data/spec/support/1024x768.gif +0 -0
  29. data/spec/support/1x1.png +0 -0
  30. data/spec/support/base_server.rb +36 -0
  31. data/spec/support/file.txt +1 -0
  32. data/spec/support/ht_helpers.rb +10 -0
  33. data/spec/support/main_server.rb +155 -0
  34. data/spec/support/proxy_server.rb +14 -0
  35. data/spec/support/test_servlet.rb +73 -0
  36. data/stress-test/Gemfile +4 -0
  37. data/stress-test/Gemfile.lock +16 -0
  38. data/stress-test/client.rb +72 -0
  39. data/stress-test/config.ru +4 -0
  40. data/stress-test/unicorn.conf +2 -0
  41. data/test.rb +19 -0
  42. data/test/helper.rb +4 -3
  43. data/test/test_httpclient.rb +19 -677
  44. metadata +226 -38
  45. data/lib/httpclient/timeout.rb +0 -140
  46. data/test/runner.rb +0 -2
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+ ruby '2.0.0'
3
+
4
+ gem 'unicorn'
@@ -0,0 +1,16 @@
1
+ GEM
2
+ remote: https://rubygems.org/
3
+ specs:
4
+ kgio (2.8.1)
5
+ rack (1.5.2)
6
+ raindrops (0.12.0)
7
+ unicorn (4.7.0)
8
+ kgio (~> 2.6)
9
+ rack
10
+ raindrops (~> 0.7)
11
+
12
+ PLATFORMS
13
+ ruby
14
+
15
+ DEPENDENCIES
16
+ unicorn
@@ -0,0 +1,72 @@
1
+ # encoding: utf-8
2
+ lib = File.expand_path('../../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'httpclient'
5
+
6
+ require 'thread'
7
+
8
+ threads = []
9
+ # clnt = HTTPClient.new()
10
+
11
+ # 20.times do
12
+ # threads << Thread.new do
13
+ # loop do
14
+ # clnt.get("http://localhost:7000/#{rand(1000..10000).to_s}.html") do |str|
15
+ # puts str.length if str.length != 1300000
16
+ # end
17
+ # end
18
+ # end
19
+ # end
20
+ #
21
+ # clnt = HTTPClient.new()
22
+ # 10.times do
23
+ # threads << Thread.new do
24
+ # loop do
25
+ # begin
26
+ # clnt.get("http://#{rand(10000...200000)}.test.local/test.htm") do |str|
27
+ # puts str.length if str.length != 1300000
28
+ # end
29
+ # rescue
30
+ # end
31
+ # end
32
+ # end
33
+ # end
34
+
35
+ 20.times do
36
+ threads << Thread.new do
37
+ loop do
38
+ clnt = HTTPClient.new()
39
+ clnt.get("http://localhost:7000/#{rand(1000..10000).to_s}.html") do |str|
40
+ puts str.length if str.length != 1300000
41
+ end
42
+ end
43
+ end
44
+ end
45
+
46
+ def ostats(last_stat = nil)
47
+ stats = Hash.new(0)
48
+ ObjectSpace.each_object {|o| stats[o.class] += 1}
49
+
50
+ stats.sort {|(k1,v1),(k2,v2)| v2 <=> v1}.each do |k,v|
51
+ next if v < 25
52
+ printf "%-30s %10d", k, v
53
+ printf " | delta %10d", (v - last_stat[k]) if last_stat
54
+ puts
55
+ end
56
+
57
+ stats
58
+ end
59
+
60
+ mstat = nil
61
+
62
+ threads << Thread.new do
63
+ loop do
64
+ mstat = ostats(mstat)
65
+ puts '-' * 80
66
+ sleep 1
67
+ end
68
+ end
69
+
70
+ threads.each do |t|
71
+ t.join
72
+ end
@@ -0,0 +1,4 @@
1
+ body = ['abcdfghklmnop' * 100_000]
2
+ run Proc.new { |env|
3
+ [200, {'Content-Type' => 'text/html'}, body]
4
+ }
@@ -0,0 +1,2 @@
1
+ listen 7000
2
+ worker_processes 10
data/test.rb ADDED
@@ -0,0 +1,19 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.unshift(File.join('.', 'lib'))
4
+ require 'httpclient'
5
+
6
+ clnt = HTTPClient.new()
7
+ site = ARGV.shift
8
+ threads = []
9
+ 15.times do
10
+ threads << Thread.new do
11
+ loop do
12
+ puts "GET #{site}"
13
+ cnt = clnt.get_content site
14
+ sleep 1
15
+ end
16
+ end
17
+ end
18
+
19
+ threads.map(&:join)
data/test/helper.rb CHANGED
@@ -1,9 +1,10 @@
1
1
  # -*- encoding: utf-8 -*-
2
- require 'test/unit'
2
+ require "test/unit"
3
+
3
4
  begin
4
5
  require 'simplecov'
5
- require 'simplecov-rcov'
6
- SimpleCov.formatter = SimpleCov::Formatter::RcovFormatter
6
+ # require 'simplecov-rcov'
7
+ # SimpleCov.formatter = SimpleCov::Formatter::RcovFormatter
7
8
  SimpleCov.start
8
9
  rescue LoadError
9
10
  end
@@ -64,56 +64,6 @@ class TestHTTPClient < Test::Unit::TestCase
64
64
  assert(!str.empty?)
65
65
  end
66
66
 
67
- def test_protocol_version_http09
68
- @client.protocol_version = 'HTTP/0.9'
69
- @client.debug_dev = str = ''
70
- @client.test_loopback_http_response << "hello\nworld\n"
71
- res = @client.get(serverurl + 'hello')
72
- assert_equal('0.9', res.http_version)
73
- assert_equal(nil, res.status)
74
- assert_equal(nil, res.reason)
75
- assert_equal("hello\nworld\n", res.content)
76
- lines = str.split(/(?:\r?\n)+/)
77
- assert_equal("= Request", lines[0])
78
- assert_equal("! CONNECTION ESTABLISHED", lines[2])
79
- assert_equal("GET /hello HTTP/0.9", lines[3])
80
- assert_equal("Connection: close", lines[7])
81
- assert_equal("= Response", lines[8])
82
- assert_match(/^hello$/, lines[9])
83
- assert_match(/^world$/, lines[10])
84
- end
85
-
86
- def test_protocol_version_http10
87
- assert_equal(nil, @client.protocol_version)
88
- @client.protocol_version = 'HTTP/1.0'
89
- assert_equal('HTTP/1.0', @client.protocol_version)
90
- str = ""
91
- @client.debug_dev = str
92
- @client.get(serverurl + 'hello')
93
- lines = str.split(/(?:\r?\n)+/)
94
- assert_equal("= Request", lines[0])
95
- assert_equal("! CONNECTION ESTABLISHED", lines[2])
96
- assert_equal("GET /hello HTTP/1.0", lines[3])
97
- assert_equal("Connection: close", lines[7])
98
- assert_equal("= Response", lines[8])
99
- end
100
-
101
- def test_header_accept_by_default
102
- str = ""
103
- @client.debug_dev = str
104
- @client.get(serverurl)
105
- lines = str.split(/(?:\r?\n)+/)
106
- assert_equal("Accept: */*", lines[5])
107
- end
108
-
109
- def test_header_accept
110
- str = ""
111
- @client.debug_dev = str
112
- @client.get(serverurl, :header => {:Accept => 'text/html'})
113
- lines = str.split(/(?:\r?\n)+/)
114
- assert_equal("Accept: text/html", lines[4])
115
- end
116
-
117
67
  def test_host_given
118
68
  str = ""
119
69
  @client.debug_dev = str
@@ -143,35 +93,6 @@ class TestHTTPClient < Test::Unit::TestCase
143
93
  end
144
94
  end
145
95
 
146
- def test_protocol_version_http11
147
- assert_equal(nil, @client.protocol_version)
148
- str = ""
149
- @client.debug_dev = str
150
- @client.get(serverurl)
151
- lines = str.split(/(?:\r?\n)+/)
152
- assert_equal("= Request", lines[0])
153
- assert_equal("! CONNECTION ESTABLISHED", lines[2])
154
- assert_equal("GET / HTTP/1.1", lines[3])
155
- assert_equal("Host: localhost:#{serverport}", lines[7])
156
- @client.protocol_version = 'HTTP/1.1'
157
- assert_equal('HTTP/1.1', @client.protocol_version)
158
- str = ""
159
- @client.debug_dev = str
160
- @client.get(serverurl)
161
- lines = str.split(/(?:\r?\n)+/)
162
- assert_equal("= Request", lines[0])
163
- assert_equal("! CONNECTION ESTABLISHED", lines[2])
164
- assert_equal("GET / HTTP/1.1", lines[3])
165
- @client.protocol_version = 'HTTP/1.0'
166
- str = ""
167
- @client.debug_dev = str
168
- @client.get(serverurl)
169
- lines = str.split(/(?:\r?\n)+/)
170
- assert_equal("= Request", lines[0])
171
- assert_equal("! CONNECTION ESTABLISHED", lines[2])
172
- assert_equal("GET / HTTP/1.0", lines[3])
173
- end
174
-
175
96
  def test_proxy
176
97
  setup_proxyserver
177
98
  escape_noproxy do
@@ -526,104 +447,6 @@ EOS
526
447
  end
527
448
  end
528
449
 
529
- def test_get_content
530
- assert_equal('hello', @client.get_content(serverurl + 'hello'))
531
- assert_equal('hello', @client.get_content(serverurl + 'redirect1'))
532
- assert_equal('hello', @client.get_content(serverurl + 'redirect2'))
533
- url = serverurl.sub(/localhost/, '127.0.0.1')
534
- assert_equal('hello', @client.get_content(url + 'hello'))
535
- assert_equal('hello', @client.get_content(url + 'redirect1'))
536
- assert_equal('hello', @client.get_content(url + 'redirect2'))
537
- @client.reset(serverurl)
538
- @client.reset(url)
539
- @client.reset(serverurl)
540
- @client.reset(url)
541
- assert_raises(HTTPClient::BadResponseError) do
542
- @client.get_content(serverurl + 'notfound')
543
- end
544
- assert_raises(HTTPClient::BadResponseError) do
545
- @client.get_content(serverurl + 'redirect_self')
546
- end
547
- called = false
548
- @client.redirect_uri_callback = lambda { |uri, res|
549
- newuri = res.header['location'][0]
550
- called = true
551
- newuri
552
- }
553
- assert_equal('hello', @client.get_content(serverurl + 'relative_redirect'))
554
- assert(called)
555
- end
556
-
557
- 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
- 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)
561
- def test_get_gzipped_content
562
- @client.transparent_gzip_decompression = false
563
- content = @client.get_content(serverurl + 'compressed?enc=gzip')
564
- assert_not_equal('hello', content)
565
- assert_equal(GZIP_CONTENT, content)
566
- @client.transparent_gzip_decompression = true
567
- assert_equal('hello', @client.get_content(serverurl + 'compressed?enc=gzip'))
568
- assert_equal('hello', @client.get_content(serverurl + 'compressed?enc=deflate'))
569
- @client.transparent_gzip_decompression = false
570
- end
571
-
572
- def test_get_content_with_block
573
- @client.get_content(serverurl + 'hello') do |str|
574
- assert_equal('hello', str)
575
- end
576
- @client.get_content(serverurl + 'redirect1') do |str|
577
- assert_equal('hello', str)
578
- end
579
- @client.get_content(serverurl + 'redirect2') do |str|
580
- assert_equal('hello', str)
581
- end
582
- end
583
-
584
- def test_post_content
585
- assert_equal('hello', @client.post_content(serverurl + 'hello'))
586
- assert_equal('hello', @client.post_content(serverurl + 'redirect1'))
587
- assert_equal('hello', @client.post_content(serverurl + 'redirect2'))
588
- assert_raises(HTTPClient::BadResponseError) do
589
- @client.post_content(serverurl + 'notfound')
590
- end
591
- assert_raises(HTTPClient::BadResponseError) do
592
- @client.post_content(serverurl + 'redirect_self')
593
- end
594
- called = false
595
- @client.redirect_uri_callback = lambda { |uri, res|
596
- newuri = res.header['location'][0]
597
- called = true
598
- newuri
599
- }
600
- assert_equal('hello', @client.post_content(serverurl + 'relative_redirect'))
601
- assert(called)
602
- end
603
-
604
- def test_post_content_io
605
- post_body = StringIO.new("1234567890")
606
- assert_equal('post,1234567890', @client.post_content(serverurl + 'servlet', post_body))
607
-
608
- # all browsers use GET for 302
609
- post_body = StringIO.new("1234567890")
610
- assert_equal('1234567890', @client.post_content(serverurl + 'servlet_413', post_body))
611
-
612
- assert_equal('', @client.get_content(serverurl + 'servlet_redirect_413'))
613
- post_body = StringIO.new("1234567890")
614
- assert_equal('', @client.post_content(serverurl + 'servlet_redirect_413', post_body))
615
-
616
-
617
- post_body = StringIO.new("1234567890")
618
- assert_equal('post,1234567890', @client.post_content(serverurl + 'servlet_temporary_redirect', post_body))
619
- post_body = StringIO.new("1234567890")
620
- assert_equal('get', @client.post_content(serverurl + 'servlet_see_other', post_body))
621
- #
622
- post_body = StringIO.new("1234567890")
623
- post_body.read(5)
624
- assert_equal('post,67890', @client.post_content(serverurl + 'servlet_temporary_redirect', post_body))
625
- end
626
-
627
450
  def test_head
628
451
  assert_equal("head", @client.head(serverurl + 'servlet').header["x-head"][0])
629
452
  param = {'1'=>'2', '3'=>'4'}
@@ -888,7 +711,24 @@ EOS
888
711
  assert_equal(param, params(res.header["x-query"][0]))
889
712
  end
890
713
 
891
- def test_delete
714
+ def test_patch
715
+ assert_equal("patch", @client.patch(serverurl + 'servlet').content)
716
+ param = {'1'=>'2', '3'=>'4'}
717
+ @client.debug_dev = str = ''
718
+ res = @client.patch(serverurl + 'servlet', param)
719
+ assert_equal(param, params(res.header["x-query"][0]))
720
+ assert_equal('Content-Type: application/x-www-form-urlencoded', str.split(/\r?\n/)[5])
721
+ end
722
+
723
+ def test_patch_async
724
+ param = {'1'=>'2', '3'=>'4'}
725
+ conn = @client.patch_async(serverurl + 'servlet', param)
726
+ Thread.pass while !conn.finished?
727
+ res = conn.pop
728
+ assert_equal(param, params(res.header["x-query"][0]))
729
+ end
730
+
731
+ def test_delete
892
732
  assert_equal("delete", @client.delete(serverurl + 'servlet').content)
893
733
  end
894
734
 
@@ -963,6 +803,7 @@ EOS
963
803
 
964
804
  def test_chunked
965
805
  assert_equal('chunked', @client.get_content(serverurl + 'chunked', { 'msg' => 'chunked' }))
806
+ assert_equal('あいうえお', @client.get_content(serverurl + 'chunked', { 'msg' => 'あいうえお' }))
966
807
  end
967
808
 
968
809
  def test_chunked_empty
@@ -1086,14 +927,6 @@ EOS
1086
927
  assert_equal('hello', @client.post(serverurl + 'sleep', :sec => 2).content)
1087
928
  end
1088
929
 
1089
- # disable for now -- does not work
1090
- #def test_async_error
1091
- # assert_raise( SocketError ) do
1092
- # conn = @client.get_async("http://non-existing-host/")
1093
- # conn.pop
1094
- # end
1095
- #end
1096
-
1097
930
  def test_reset
1098
931
  url = serverurl + 'servlet'
1099
932
  assert_nothing_raised do
@@ -1188,14 +1021,6 @@ EOS
1188
1021
  end
1189
1022
  end
1190
1023
 
1191
- def test_urify
1192
- extend HTTPClient::Util
1193
- assert_nil(urify(nil))
1194
- uri = 'http://foo'
1195
- assert_equal(urify(uri), urify(uri))
1196
- assert_equal(urify(uri), urify(urify(uri)))
1197
- end
1198
-
1199
1024
  def test_connection
1200
1025
  c = HTTPClient::Connection.new
1201
1026
  assert(c.finished?)
@@ -1249,156 +1074,6 @@ EOS
1249
1074
  assert_equal([['foo', 'bar'], ['foo', 'bar2']], res.header.get('foo'))
1250
1075
  end
1251
1076
 
1252
- def test_mime_type
1253
- assert_equal('text/plain', HTTP::Message.mime_type('foo.txt'))
1254
- assert_equal('text/html', HTTP::Message.mime_type('foo.html'))
1255
- assert_equal('text/html', HTTP::Message.mime_type('foo.htm'))
1256
- assert_equal('application/msword', HTTP::Message.mime_type('foo.doc'))
1257
- assert_equal('image/png', HTTP::Message.mime_type('foo.png'))
1258
- assert_equal('image/gif', HTTP::Message.mime_type('foo.gif'))
1259
- assert_equal('image/jpeg', HTTP::Message.mime_type('foo.jpg'))
1260
- assert_equal('image/jpeg', HTTP::Message.mime_type('foo.jpeg'))
1261
- assert_equal('application/octet-stream', HTTP::Message.mime_type('foo.unknown'))
1262
- #
1263
- handler = lambda { |path| 'hello/world' }
1264
- assert_nil(HTTP::Message.mime_type_handler)
1265
- assert_nil(HTTP::Message.get_mime_type_func)
1266
- HTTP::Message.mime_type_handler = handler
1267
- assert_not_nil(HTTP::Message.mime_type_handler)
1268
- assert_not_nil(HTTP::Message.get_mime_type_func)
1269
- assert_equal('hello/world', HTTP::Message.mime_type('foo.txt'))
1270
- HTTP::Message.mime_type_handler = nil
1271
- assert_equal('text/plain', HTTP::Message.mime_type('foo.txt'))
1272
- HTTP::Message.set_mime_type_func(nil)
1273
- assert_equal('text/plain', HTTP::Message.mime_type('foo.txt'))
1274
- #
1275
- handler = lambda { |path| nil }
1276
- HTTP::Message.mime_type_handler = handler
1277
- assert_equal('application/octet-stream', HTTP::Message.mime_type('foo.txt'))
1278
- end
1279
-
1280
- def test_connect_request
1281
- req = HTTP::Message.new_connect_request(urify('https://foo/bar'))
1282
- assert_equal("CONNECT foo:443 HTTP/1.0\r\n\r\n", req.dump)
1283
- req = HTTP::Message.new_connect_request(urify('https://example.com/'))
1284
- assert_equal("CONNECT example.com:443 HTTP/1.0\r\n\r\n", req.dump)
1285
- end
1286
-
1287
- def test_response
1288
- res = HTTP::Message.new_response('response')
1289
- res.contenttype = 'text/plain'
1290
- res.header.body_date = Time.at(946652400)
1291
- assert_equal(
1292
- [
1293
- "",
1294
- "Content-Length: 8",
1295
- "Content-Type: text/plain",
1296
- "Last-Modified: Fri, 31 Dec 1999 15:00:00 GMT",
1297
- "Status: 200 OK",
1298
- "response"
1299
- ],
1300
- res.dump.split(/\r\n/).sort
1301
- )
1302
- assert_equal(['8'], res.header['Content-Length'])
1303
- assert_equal('8', res.headers['Content-Length'])
1304
- res.header.set('foo', 'bar')
1305
- assert_equal(
1306
- [
1307
- "",
1308
- "Content-Length: 8",
1309
- "Content-Type: text/plain",
1310
- "Last-Modified: Fri, 31 Dec 1999 15:00:00 GMT",
1311
- "Status: 200 OK",
1312
- "foo: bar",
1313
- "response"
1314
- ],
1315
- res.dump.split(/\r\n/).sort
1316
- )
1317
- # nil body
1318
- res = HTTP::Message.new_response(nil)
1319
- assert_equal(
1320
- [
1321
- "Content-Length: 0",
1322
- "Content-Type: text/html; charset=us-ascii",
1323
- "Status: 200 OK"
1324
- ],
1325
- res.dump.split(/\r\n/).sort
1326
- )
1327
- # for mod_ruby env
1328
- Object.const_set('Apache', nil)
1329
- begin
1330
- res = HTTP::Message.new_response('response')
1331
- assert(res.dump.split(/\r\n/).any? { |line| /^Date/ =~ line })
1332
- #
1333
- res = HTTP::Message.new_response('response')
1334
- res.contenttype = 'text/plain'
1335
- res.header.body_date = Time.at(946652400)
1336
- res.header['Date'] = Time.at(946652400).httpdate
1337
- assert_equal(
1338
- [
1339
- "",
1340
- "Content-Length: 8",
1341
- "Content-Type: text/plain",
1342
- "Date: Fri, 31 Dec 1999 15:00:00 GMT",
1343
- "HTTP/1.1 200 OK",
1344
- "Last-Modified: Fri, 31 Dec 1999 15:00:00 GMT",
1345
- "response"
1346
- ],
1347
- res.dump.split(/\r\n/).sort
1348
- )
1349
- ensure
1350
- Object.instance_eval { remove_const('Apache') }
1351
- end
1352
- end
1353
-
1354
- def test_response_cookies
1355
- res = HTTP::Message.new_response('response')
1356
- res.contenttype = 'text/plain'
1357
- res.header.body_date = Time.at(946652400)
1358
- assert_nil(res.cookies)
1359
- #
1360
- res.header['Set-Cookie'] = [
1361
- 'CUSTOMER=WILE_E_COYOTE; path=/; expires=Wednesday, 09-Nov-99 23:12:40 GMT',
1362
- 'PART_NUMBER=ROCKET_LAUNCHER_0001; path=/'
1363
- ]
1364
- assert_equal(
1365
- [
1366
- "",
1367
- "Content-Length: 8",
1368
- "Content-Type: text/plain",
1369
- "Last-Modified: Fri, 31 Dec 1999 15:00:00 GMT",
1370
- "Set-Cookie: CUSTOMER=WILE_E_COYOTE; path=/; expires=Wednesday, 09-Nov-99 23:12:40 GMT",
1371
- "Set-Cookie: PART_NUMBER=ROCKET_LAUNCHER_0001; path=/",
1372
- "Status: 200 OK",
1373
- "response"
1374
- ],
1375
- res.dump.split(/\r\n/).sort
1376
- )
1377
- assert_equal(2, res.cookies.size)
1378
- assert_equal('CUSTOMER', res.cookies[0].name)
1379
- assert_equal('PART_NUMBER', res.cookies[1].name)
1380
- end
1381
-
1382
- def test_ok_response_success
1383
- res = HTTP::Message.new_response('response')
1384
- assert_equal(true, res.ok?)
1385
- res.status = 404
1386
- assert_equal(false, res.ok?)
1387
- res.status = 500
1388
- assert_equal(false, res.ok?)
1389
- res.status = 302
1390
- assert_equal(false, res.ok?)
1391
- end
1392
-
1393
- if !defined?(JRUBY_VERSION) and RUBY_VERSION < '1.9'
1394
- def test_timeout_scheduler
1395
- assert_equal('hello', @client.get_content(serverurl + 'hello'))
1396
- status = HTTPClient.timeout_scheduler.instance_eval { @thread.kill; @thread.join; @thread.status }
1397
- assert(!status) # dead
1398
- assert_equal('hello', @client.get_content(serverurl + 'hello'))
1399
- end
1400
- end
1401
-
1402
1077
  def test_session_manager
1403
1078
  mgr = HTTPClient::SessionManager.new(@client)
1404
1079
  assert_nil(mgr.instance_eval { @proxy })
@@ -1410,131 +1085,6 @@ EOS
1410
1085
  assert_equal(@client.debug_dev, mgr.debug_dev)
1411
1086
  end
1412
1087
 
1413
- def create_keepalive_disconnected_thread(idx, sock)
1414
- Thread.new {
1415
- # return "12345" for the first connection
1416
- sock.gets
1417
- sock.gets
1418
- sock.write("HTTP/1.1 200 OK\r\n")
1419
- sock.write("Content-Length: 5\r\n")
1420
- sock.write("\r\n")
1421
- sock.write("12345")
1422
- # for the next connection, close while reading the request for emulating
1423
- # KeepAliveDisconnected
1424
- sock.gets
1425
- sock.close
1426
- }
1427
- end
1428
-
1429
- def test_keepalive_disconnected
1430
- client = HTTPClient.new
1431
- server = TCPServer.open('127.0.0.1', 0)
1432
- server.listen(30) # set enough backlogs
1433
- endpoint = "http://127.0.0.1:#{server.addr[1]}/"
1434
- Thread.new {
1435
- Thread.abort_on_exception = true
1436
- # emulate 10 keep-alive connections
1437
- 10.times do |idx|
1438
- sock = server.accept
1439
- create_keepalive_disconnected_thread(idx, sock)
1440
- end
1441
- # return "23456" for the request which gets KeepAliveDisconnected
1442
- 5.times do
1443
- sock = server.accept
1444
- sock.gets
1445
- sock.gets
1446
- sock.write("HTTP/1.1 200 OK\r\n")
1447
- sock.write("\r\n")
1448
- sock.write("23456")
1449
- sock.close
1450
- end
1451
- # return "34567" for the rest requests
1452
- while true
1453
- sock = server.accept
1454
- sock.gets
1455
- sock.gets
1456
- sock.write("HTTP/1.1 200 OK\r\n")
1457
- sock.write("Connection: close\r\n")
1458
- sock.write("Content-Length: 5\r\n")
1459
- sock.write("\r\n")
1460
- sock.write("34567")
1461
- sock.close
1462
- end
1463
- }
1464
- # allocate 10 keep-alive connections
1465
- (0...10).to_a.map {
1466
- Thread.new {
1467
- assert_equal("12345", client.get(endpoint).content)
1468
- }
1469
- }.each { |th| th.join }
1470
- # send 5 requests, which should get KeepAliveDesconnected.
1471
- # doing these requests, rest keep-alive connections are invalidated.
1472
- (0...5).to_a.map {
1473
- Thread.new {
1474
- assert_equal("23456", client.get(endpoint).content)
1475
- }
1476
- }.each { |th| th.join }
1477
- # rest requests won't get KeepAliveDisconnected; how can I check this?
1478
- (0...10).to_a.map {
1479
- Thread.new {
1480
- assert_equal("34567", client.get(endpoint).content)
1481
- }
1482
- }.each { |th| th.join }
1483
- end
1484
-
1485
- def create_keepalive_thread(count, sock)
1486
- Thread.new {
1487
- Thread.abort_on_exception = true
1488
- count.times do
1489
- req = sock.gets
1490
- while line = sock.gets
1491
- break if line.chomp.empty?
1492
- end
1493
- case req
1494
- when /chunked/
1495
- sock.write("HTTP/1.1 200 OK\r\n")
1496
- sock.write("Transfer-Encoding: chunked\r\n")
1497
- sock.write("\r\n")
1498
- sock.write("1a\r\n")
1499
- sock.write("abcdefghijklmnopqrstuvwxyz\r\n")
1500
- sock.write("10\r\n")
1501
- sock.write("1234567890abcdef\r\n")
1502
- sock.write("0\r\n")
1503
- sock.write("\r\n")
1504
- else
1505
- sock.write("HTTP/1.1 200 OK\r\n")
1506
- sock.write("Content-Length: 5\r\n")
1507
- sock.write("\r\n")
1508
- sock.write("12345")
1509
- end
1510
- end
1511
- sock.close
1512
- }
1513
- end
1514
-
1515
- def test_keepalive
1516
- server = TCPServer.open('localhost', 0)
1517
- server_thread = Thread.new {
1518
- Thread.abort_on_exception = true
1519
- sock = server.accept
1520
- create_keepalive_thread(10, sock)
1521
- }
1522
- url = "http://localhost:#{server.addr[1]}/"
1523
- begin
1524
- # content-length
1525
- 5.times do
1526
- assert_equal('12345', @client.get(url).body)
1527
- end
1528
- # chunked
1529
- 5.times do
1530
- assert_equal('abcdefghijklmnopqrstuvwxyz1234567890abcdef', @client.get(url + 'chunked').body)
1531
- end
1532
- ensure
1533
- server.close
1534
- server_thread.join
1535
- end
1536
- end
1537
-
1538
1088
  def test_socket_local
1539
1089
  @client.socket_local.host = '127.0.0.1'
1540
1090
  assert_equal('hello', @client.get_content(serverurl + 'hello'))
@@ -1608,212 +1158,4 @@ private
1608
1158
  )
1609
1159
  end
1610
1160
 
1611
- def setup_server
1612
- @server = WEBrick::HTTPServer.new(
1613
- :BindAddress => "localhost",
1614
- :Logger => @logger,
1615
- :Port => 0,
1616
- :AccessLog => [],
1617
- :DocumentRoot => File.dirname(File.expand_path(__FILE__))
1618
- )
1619
- @serverport = @server.config[:Port]
1620
- [
1621
- :hello, :sleep, :servlet_redirect, :servlet_temporary_redirect, :servlet_see_other,
1622
- :redirect1, :redirect2, :redirect3,
1623
- :redirect_self, :relative_redirect, :redirect_see_other, :chunked,
1624
- :largebody, :status, :compressed, :charset, :continue,
1625
- :servlet_redirect_413, :servlet_413
1626
- ].each do |sym|
1627
- @server.mount(
1628
- "/#{sym}",
1629
- WEBrick::HTTPServlet::ProcHandler.new(method("do_#{sym}").to_proc)
1630
- )
1631
- end
1632
- @server.mount('/servlet', TestServlet.new(@server))
1633
- @server_thread = start_server_thread(@server)
1634
- end
1635
-
1636
- def escape_noproxy
1637
- backup = HTTPClient::NO_PROXY_HOSTS.dup
1638
- HTTPClient::NO_PROXY_HOSTS.clear
1639
- yield
1640
- ensure
1641
- HTTPClient::NO_PROXY_HOSTS.replace(backup)
1642
- end
1643
-
1644
- def do_hello(req, res)
1645
- res['content-type'] = 'text/html'
1646
- res.body = "hello"
1647
- end
1648
-
1649
- def do_sleep(req, res)
1650
- sec = req.query['sec'].to_i
1651
- sleep sec
1652
- res['content-type'] = 'text/html'
1653
- res.body = "hello"
1654
- end
1655
-
1656
- def do_servlet_redirect(req, res)
1657
- res.set_redirect(WEBrick::HTTPStatus::Found, serverurl + "servlet")
1658
- end
1659
-
1660
- def do_servlet_redirect_413(req, res)
1661
- res.set_redirect(WEBrick::HTTPStatus::Found, serverurl + "servlet_413")
1662
- end
1663
-
1664
- def do_servlet_413(req, res)
1665
- res.body = req.body.to_s
1666
- end
1667
-
1668
- def do_servlet_temporary_redirect(req, res)
1669
- res.set_redirect(WEBrick::HTTPStatus::TemporaryRedirect, serverurl + "servlet")
1670
- end
1671
-
1672
- def do_servlet_see_other(req, res)
1673
- res.set_redirect(WEBrick::HTTPStatus::SeeOther, serverurl + "servlet")
1674
- end
1675
-
1676
- def do_redirect1(req, res)
1677
- res.set_redirect(WEBrick::HTTPStatus::MovedPermanently, serverurl + "hello")
1678
- end
1679
-
1680
- def do_redirect2(req, res)
1681
- res.set_redirect(WEBrick::HTTPStatus::TemporaryRedirect, serverurl + "redirect3")
1682
- end
1683
-
1684
- def do_redirect3(req, res)
1685
- res.set_redirect(WEBrick::HTTPStatus::Found, serverurl + "hello")
1686
- end
1687
-
1688
- def do_redirect_self(req, res)
1689
- res.set_redirect(WEBrick::HTTPStatus::Found, serverurl + "redirect_self")
1690
- end
1691
-
1692
- def do_relative_redirect(req, res)
1693
- res.set_redirect(WEBrick::HTTPStatus::Found, "hello")
1694
- end
1695
-
1696
- def do_redirect_see_other(req, res)
1697
- if req.request_method == 'POST'
1698
- res.set_redirect(WEBrick::HTTPStatus::SeeOther, serverurl + "redirect_see_other") # self
1699
- else
1700
- res.body = 'hello'
1701
- end
1702
- end
1703
-
1704
- def do_chunked(req, res)
1705
- res.chunked = true
1706
- piper, pipew = IO.pipe
1707
- res.body = piper
1708
- pipew << req.query['msg']
1709
- pipew.close
1710
- end
1711
-
1712
- def do_largebody(req, res)
1713
- res['content-type'] = 'text/html'
1714
- res.body = "a" * 1000 * 1000
1715
- end
1716
-
1717
- def do_compressed(req, res)
1718
- res['content-type'] = 'application/octet-stream'
1719
- if req.query['enc'] == 'gzip'
1720
- res['content-encoding'] = 'gzip'
1721
- res.body = GZIP_CONTENT
1722
- elsif req.query['enc'] == 'deflate'
1723
- res['content-encoding'] = 'deflate'
1724
- res.body = DEFLATE_CONTENT
1725
- end
1726
- end
1727
-
1728
- def do_charset(req, res)
1729
- if RUBY_VERSION > "1.9"
1730
- res.body = 'あいうえお'.encode("euc-jp")
1731
- res['Content-Type'] = 'text/plain; charset=euc-jp'
1732
- else
1733
- res.body = 'this endpoint is for 1.9 or later'
1734
- end
1735
- end
1736
-
1737
- def do_status(req, res)
1738
- res.status = req.query['status'].to_i
1739
- end
1740
-
1741
- def do_continue(req, res)
1742
- req.continue
1743
- res.body = 'done!'
1744
- end
1745
-
1746
- class TestServlet < WEBrick::HTTPServlet::AbstractServlet
1747
- def get_instance(*arg)
1748
- self
1749
- end
1750
-
1751
- def do_HEAD(req, res)
1752
- res["x-head"] = 'head' # use this for test purpose only.
1753
- res["x-query"] = query_response(req)
1754
- end
1755
-
1756
- def do_GET(req, res)
1757
- res.body = 'get'
1758
- res["x-query"] = query_response(req)
1759
- end
1760
-
1761
- def do_POST(req, res)
1762
- res["content-type"] = "text/plain" # iso-8859-1, not US-ASCII
1763
- res.body = 'post,' + req.body.to_s
1764
- res["x-query"] = body_response(req)
1765
- end
1766
-
1767
- def do_PUT(req, res)
1768
- res["x-query"] = body_response(req)
1769
- param = WEBrick::HTTPUtils.parse_query(req.body) || {}
1770
- res["x-size"] = (param['txt'] || '').size
1771
- res.body = param['txt'] || 'put'
1772
- end
1773
-
1774
- def do_DELETE(req, res)
1775
- res.body = 'delete'
1776
- end
1777
-
1778
- def do_OPTIONS(req, res)
1779
- # check RFC for legal response.
1780
- res.body = 'options'
1781
- end
1782
-
1783
- def do_PROPFIND(req, res)
1784
- res.body = 'propfind'
1785
- end
1786
-
1787
- def do_PROPPATCH(req, res)
1788
- res.body = 'proppatch'
1789
- res["x-query"] = body_response(req)
1790
- end
1791
-
1792
- def do_TRACE(req, res)
1793
- # client SHOULD reflect the message received back to the client as the
1794
- # entity-body of a 200 (OK) response. [RFC2616]
1795
- res.body = 'trace'
1796
- res["x-query"] = query_response(req)
1797
- end
1798
-
1799
- private
1800
-
1801
- def query_response(req)
1802
- query_escape(WEBrick::HTTPUtils.parse_query(req.query_string))
1803
- end
1804
-
1805
- def body_response(req)
1806
- query_escape(WEBrick::HTTPUtils.parse_query(req.body))
1807
- end
1808
-
1809
- def query_escape(query)
1810
- escaped = []
1811
- query.sort_by { |k, v| k }.collect do |k, v|
1812
- v.to_ary.each do |ve|
1813
- escaped << CGI.escape(k) + '=' + CGI.escape(ve)
1814
- end
1815
- end
1816
- escaped.join('&')
1817
- end
1818
- end
1819
1161
  end