glebtv-httpclient 3.1.1 → 3.2.0

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