http_spew 0.1.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.
- data/.document +6 -0
- data/.gitignore +8 -0
- data/.manifest +33 -0
- data/.wrongdoc.yml +4 -0
- data/COPYING +674 -0
- data/ChangeLog +170 -0
- data/GIT-VERSION-FILE +1 -0
- data/GIT-VERSION-GEN +40 -0
- data/GNUmakefile +5 -0
- data/LATEST +4 -0
- data/LICENSE +17 -0
- data/NEWS +4 -0
- data/README +61 -0
- data/http_spew.gemspec +24 -0
- data/lib/http_spew/chunky_pipe.rb +12 -0
- data/lib/http_spew/content_md5.rb +55 -0
- data/lib/http_spew/headers.rb +43 -0
- data/lib/http_spew/hit_n_run.rb +19 -0
- data/lib/http_spew/input_spray.rb +53 -0
- data/lib/http_spew/request.rb +77 -0
- data/lib/http_spew.rb +97 -0
- data/pkg.mk +171 -0
- data/setup.rb +1585 -0
- data/test/content-md5.ru +21 -0
- data/test/helper.rb +41 -0
- data/test/mirror.ru +22 -0
- data/test/sha1.ru +18 -0
- data/test/test_content_md5.rb +85 -0
- data/test/test_hit_n_run.rb +47 -0
- data/test/test_input_spray.rb +101 -0
- data/test/test_mirror.rb +60 -0
- data/test/test_request.rb +54 -0
- data/test/test_upload.rb +127 -0
- metadata +166 -0
data/test/content-md5.ru
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# SHA1 checksum generator
|
2
|
+
bs = ENV['bs'] ? ENV['bs'].to_i : 4096
|
3
|
+
require 'digest/md5'
|
4
|
+
use Rack::ContentLength
|
5
|
+
app = lambda do |env|
|
6
|
+
digest = Digest::MD5.new
|
7
|
+
input = env['rack.input']
|
8
|
+
if buf = input.read(bs)
|
9
|
+
begin
|
10
|
+
digest.update(buf)
|
11
|
+
end while input.read(bs, buf)
|
12
|
+
end
|
13
|
+
|
14
|
+
expect = env['HTTP_CONTENT_MD5']
|
15
|
+
readed = [ digest.digest ].pack('m').strip
|
16
|
+
body = "expect=#{expect}\nreaded=#{readed}\n"
|
17
|
+
status = expect == readed ? 200 : 500
|
18
|
+
|
19
|
+
[ status, {'Content-Type' => 'text/plain'}, [ body ] ]
|
20
|
+
end
|
21
|
+
run app
|
data/test/helper.rb
ADDED
@@ -0,0 +1,41 @@
|
|
1
|
+
# -*- encoding: binary -*-
|
2
|
+
$stderr.sync = $stdout.sync = true
|
3
|
+
require "test/unit"
|
4
|
+
require "digest/sha1"
|
5
|
+
require "stringio"
|
6
|
+
require "tmpdir"
|
7
|
+
require "socket"
|
8
|
+
require "rack"
|
9
|
+
require "tempfile"
|
10
|
+
$-w = true
|
11
|
+
require "http_spew"
|
12
|
+
|
13
|
+
def start_server(config, worker_processes = 4)
|
14
|
+
addr = ENV["TEST_HOST"] || "127.0.0.1"
|
15
|
+
sock = TCPServer.new(addr, 0)
|
16
|
+
port = sock.addr[1]
|
17
|
+
fifo = Tempfile.new("fifo")
|
18
|
+
fifo_path = fifo.path
|
19
|
+
fifo.close!
|
20
|
+
system("mkfifo", fifo_path) or abort "mkfifo: #$?"
|
21
|
+
cfg = Tempfile.new("unicorn.config")
|
22
|
+
cfg.puts "worker_processes #{worker_processes}"
|
23
|
+
cfg.puts "preload_app true"
|
24
|
+
cfg.puts <<EOF
|
25
|
+
after_fork do |s,w|
|
26
|
+
w.nr == (s.worker_processes - 1) and File.open("#{fifo_path}", "w").close
|
27
|
+
end
|
28
|
+
EOF
|
29
|
+
cfg.flush
|
30
|
+
pid = fork do
|
31
|
+
ENV["UNICORN_FD"] = sock.fileno.to_s
|
32
|
+
exec "unicorn", "-l#{addr}:#{port}", "-c#{cfg.path}", config
|
33
|
+
end
|
34
|
+
File.open(fifo_path).close
|
35
|
+
File.unlink fifo_path
|
36
|
+
[ addr, port, pid ]
|
37
|
+
end
|
38
|
+
|
39
|
+
def rand_data(nr)
|
40
|
+
File.open("/dev/urandom", "rb") { |fp| fp.read(nr) }
|
41
|
+
end
|
data/test/mirror.ru
ADDED
@@ -0,0 +1,22 @@
|
|
1
|
+
# SHA1 checksum generator
|
2
|
+
bs = ENV['bs'] ? ENV['bs'].to_i : 16384
|
3
|
+
require 'digest/sha1'
|
4
|
+
require 'unicorn/preread_input'
|
5
|
+
use Unicorn::PrereadInput
|
6
|
+
class InputWrap < Struct.new(:input)
|
7
|
+
def each
|
8
|
+
buf = ""
|
9
|
+
while buf = input.read(0x4000, buf)
|
10
|
+
yield buf
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
app = lambda do |env|
|
16
|
+
headers = {
|
17
|
+
"Content-Type" => "application/octet-stream",
|
18
|
+
"Content-Length" => env["CONTENT_LENGTH"].to_s,
|
19
|
+
}
|
20
|
+
[ 200, headers, InputWrap.new(env["rack.input"]) ]
|
21
|
+
end
|
22
|
+
run app
|
data/test/sha1.ru
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
# SHA1 checksum generator
|
2
|
+
bs = ENV['bs'] ? ENV['bs'].to_i : 16384
|
3
|
+
require 'digest/sha1'
|
4
|
+
use Rack::ContentLength
|
5
|
+
app = lambda do |env|
|
6
|
+
/\A100-continue\z/i =~ env['HTTP_EXPECT'] and
|
7
|
+
return [ 100, {}, [] ]
|
8
|
+
digest = Digest::SHA1.new
|
9
|
+
input = env['rack.input']
|
10
|
+
if buf = input.read(bs)
|
11
|
+
begin
|
12
|
+
digest.update(buf)
|
13
|
+
end while input.read(bs, buf)
|
14
|
+
end
|
15
|
+
|
16
|
+
[ 200, {'Content-Type' => 'text/plain'}, [ digest.hexdigest << "\n" ] ]
|
17
|
+
end
|
18
|
+
run app
|
@@ -0,0 +1,85 @@
|
|
1
|
+
# -*- encoding: binary -*-
|
2
|
+
require "./test/helper"
|
3
|
+
|
4
|
+
class TestContentMD5 < Test::Unit::TestCase
|
5
|
+
def setup
|
6
|
+
ENV["RACK_ENV"] = "deployment" # quiet Rack 1.2.1 bug
|
7
|
+
@addr, @port, @srv = start_server("./test/content-md5.ru", 1)
|
8
|
+
@sockaddr = Socket.pack_sockaddr_in(@port, @addr)
|
9
|
+
@env = {
|
10
|
+
"REQUEST_METHOD" => "PUT",
|
11
|
+
"REQUEST_URI" => "/",
|
12
|
+
"HTTP_HOST" => "example.com",
|
13
|
+
}
|
14
|
+
@tmpfiles = []
|
15
|
+
end
|
16
|
+
|
17
|
+
def teardown
|
18
|
+
Process.kill(:QUIT, @srv)
|
19
|
+
Process.waitpid2(@srv)
|
20
|
+
@tmpfiles.each { |tmp| tmp.closed? or tmp.close! }
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_upload_with_md5
|
24
|
+
str = rand_data(123) * (8 * 1021 * 13)
|
25
|
+
expect = [Digest::MD5.digest(str)].pack("m").strip!
|
26
|
+
expect = "expect=#{expect}\nreaded=#{expect}\n"
|
27
|
+
@env["CONTENT_LENGTH"] = str.size.to_s
|
28
|
+
@env["rack.input"] = StringIO.new(str)
|
29
|
+
input = HTTP_Spew::ContentMD5.input(@env)
|
30
|
+
assert_nil @env["CONTENT_LENGTH"]
|
31
|
+
assert_equal "chunked", @env["HTTP_TRANSFER_ENCODING"]
|
32
|
+
req = HTTP_Spew::Request.new(@env, input, @sockaddr)
|
33
|
+
rv = HTTP_Spew.wait 1, [req], 666000
|
34
|
+
assert_equal 200, rv[0].response[0].to_i
|
35
|
+
body = ""
|
36
|
+
req.each { |buf| body << buf }
|
37
|
+
assert_equal body, expect
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_upload_with_corrupt_md5
|
41
|
+
str = rand_data(123) * (8 * 1021 * 13)
|
42
|
+
expect = [Digest::MD5.digest(str)].pack("m").strip!
|
43
|
+
@env["HTTP_CONTENT_MD5"] = expect
|
44
|
+
str = rand_data(123) * (8 * 1021 * 13)
|
45
|
+
@env["CONTENT_LENGTH"] = str.size.to_s
|
46
|
+
@env["rack.input"] = StringIO.new(str)
|
47
|
+
input = HTTP_Spew::ContentMD5.input(@env)
|
48
|
+
assert_nil @env["CONTENT_LENGTH"]
|
49
|
+
assert_equal "chunked", @env["HTTP_TRANSFER_ENCODING"]
|
50
|
+
req = HTTP_Spew::Request.new(@env, input, @sockaddr)
|
51
|
+
rv = HTTP_Spew.wait 1, [req], 3600_000
|
52
|
+
assert_kind_of HTTP_Spew::ContentMD5::MismatchError, rv[0].error
|
53
|
+
end
|
54
|
+
|
55
|
+
def test_upload_with_corrupt_length
|
56
|
+
str = rand_data(123) * (8 * 1021 * 13)
|
57
|
+
expect = [Digest::MD5.digest(str)].pack("m").strip!
|
58
|
+
@env["HTTP_CONTENT_MD5"] = expect
|
59
|
+
str = rand_data(123) * (8 * 1021 * 13)
|
60
|
+
@env["CONTENT_LENGTH"] = (str.size + 1).to_s
|
61
|
+
@env["rack.input"] = StringIO.new(str)
|
62
|
+
input = HTTP_Spew::ContentMD5.input(@env)
|
63
|
+
assert_nil @env["CONTENT_LENGTH"]
|
64
|
+
assert_equal "chunked", @env["HTTP_TRANSFER_ENCODING"]
|
65
|
+
req = HTTP_Spew::Request.new(@env, input, @sockaddr)
|
66
|
+
rv = HTTP_Spew.wait 1, [req], 3600_000
|
67
|
+
assert_kind_of HTTP_Spew::ContentMD5::LengthError, rv[0].error
|
68
|
+
end
|
69
|
+
|
70
|
+
def test_upload_with_valid_md5
|
71
|
+
str = rand_data(123) * (8 * 1021 * 13)
|
72
|
+
expect = [Digest::MD5.digest(str)].pack("m").strip!
|
73
|
+
@env["HTTP_CONTENT_MD5"] = expect
|
74
|
+
@env["CONTENT_LENGTH"] = str.size.to_s
|
75
|
+
@env["rack.input"] = StringIO.new(str)
|
76
|
+
input = HTTP_Spew::ContentMD5.input(@env)
|
77
|
+
assert_nil @env["CONTENT_LENGTH"]
|
78
|
+
assert_equal "chunked", @env["HTTP_TRANSFER_ENCODING"]
|
79
|
+
req = HTTP_Spew::Request.new(@env, input, @sockaddr)
|
80
|
+
rv = HTTP_Spew.wait 1, [req], 3600_000
|
81
|
+
assert_equal 200, rv[0].response[0].to_i
|
82
|
+
body = ""
|
83
|
+
req.each { |buf| body << buf }
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,47 @@
|
|
1
|
+
require "./test/helper"
|
2
|
+
|
3
|
+
class TestHitNRun < Test::Unit::TestCase
|
4
|
+
def setup
|
5
|
+
@addr, @port, @srv = start_server("./test/sha1.ru", 1)
|
6
|
+
@sockaddr = Socket.pack_sockaddr_in(@port, @addr)
|
7
|
+
@env = {
|
8
|
+
"REQUEST_METHOD" => "PUT",
|
9
|
+
"REQUEST_URI" => "/",
|
10
|
+
"HTTP_HOST" => "example.com",
|
11
|
+
}
|
12
|
+
@tmpfiles = []
|
13
|
+
end
|
14
|
+
|
15
|
+
def teardown
|
16
|
+
Process.kill(:QUIT, @srv)
|
17
|
+
Process.waitpid2(@srv)
|
18
|
+
@tmpfiles.each { |tmp| tmp.closed? or tmp.close! }
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_request_with_existing_socket
|
22
|
+
sock = Kgio::Socket.new(@sockaddr)
|
23
|
+
req = HTTP_Spew::HitNRun.new(@env, nil, sock)
|
24
|
+
assert_equal sock, req.to_io
|
25
|
+
assert_nothing_raised { req.close }
|
26
|
+
assert sock.closed?
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_request_single
|
30
|
+
req = HTTP_Spew::HitNRun.new(@env, nil, @sockaddr)
|
31
|
+
sym = req.resume
|
32
|
+
if sym == :wait_writable
|
33
|
+
set = Kgio.poll({req => sym}, 100)
|
34
|
+
assert_equal [ req ], set.keys
|
35
|
+
sym = req.resume
|
36
|
+
end
|
37
|
+
assert_equal HTTP_Spew::HitNRun::RESPONSE.object_id, sym.object_id
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_request_loop
|
41
|
+
req = HTTP_Spew::HitNRun.new(@env, nil, @sockaddr)
|
42
|
+
until Array === (rv = req.resume)
|
43
|
+
Kgio.poll(req => rv)
|
44
|
+
end
|
45
|
+
assert_equal HTTP_Spew::HitNRun::RESPONSE.object_id, rv.object_id
|
46
|
+
end
|
47
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
# -*- encoding: binary -*-
|
2
|
+
require "./test/helper"
|
3
|
+
|
4
|
+
class TestInputSpray < Test::Unit::TestCase
|
5
|
+
BUF = (rand_data(128) * 1024 * 8 * 4).freeze
|
6
|
+
EXPECT = Digest::SHA1.hexdigest(BUF).freeze
|
7
|
+
|
8
|
+
def setup
|
9
|
+
io = StringIO.new(BUF)
|
10
|
+
@env = {
|
11
|
+
"rack.input" => io,
|
12
|
+
"CONTENT_LENGTH" => io.size.to_s
|
13
|
+
}
|
14
|
+
end
|
15
|
+
|
16
|
+
def test_spray_ok
|
17
|
+
sprayer = HTTP_Spew::InputSpray.new(@env, 2)
|
18
|
+
readers = sprayer.readers
|
19
|
+
assert_equal 2, readers.size
|
20
|
+
|
21
|
+
sha1 = Hash[readers.map { |rd| [ rd, Digest::SHA1.new ] } ]
|
22
|
+
|
23
|
+
readers.delete_if do |rd|
|
24
|
+
if buf = rd.read(0x10000)
|
25
|
+
sha1[rd].update buf
|
26
|
+
false
|
27
|
+
else
|
28
|
+
rd.close.nil?
|
29
|
+
end
|
30
|
+
end until readers.empty?
|
31
|
+
|
32
|
+
sha1.each_value { |dig| assert_equal EXPECT, dig.hexdigest }
|
33
|
+
sprayer.instance_variable_get(:@writers).each { |x| assert x.closed? }
|
34
|
+
end
|
35
|
+
|
36
|
+
def test_spray_one_reader_dies
|
37
|
+
sprayer = HTTP_Spew::InputSpray.new(@env, 3)
|
38
|
+
readers = sprayer.readers
|
39
|
+
assert_equal 3, readers.size
|
40
|
+
sha1 = Hash[readers.map { |rd| [ rd, Digest::SHA1.new ] } ]
|
41
|
+
count = Hash[readers.map { |rd| [ rd, 0 ] } ]
|
42
|
+
to_die = readers[0]
|
43
|
+
readers.delete_if do |rd|
|
44
|
+
if buf = rd.read(0x100)
|
45
|
+
sha1[rd].update buf
|
46
|
+
n = count[rd] += buf.size
|
47
|
+
if rd == to_die && n >= 0x20000
|
48
|
+
rd.close.nil?
|
49
|
+
else
|
50
|
+
false
|
51
|
+
end
|
52
|
+
else
|
53
|
+
rd.close.nil?
|
54
|
+
end
|
55
|
+
end until readers.empty?
|
56
|
+
|
57
|
+
dead_sha1 = sha1.delete to_die
|
58
|
+
assert EXPECT != dead_sha1.hexdigest
|
59
|
+
sha1.each_value { |dig| assert_equal EXPECT, dig.hexdigest }
|
60
|
+
sprayer.instance_variable_get(:@writers).each { |x| assert x.closed? }
|
61
|
+
end
|
62
|
+
|
63
|
+
def test_spray_stream
|
64
|
+
rd, wr = IO.pipe
|
65
|
+
assert @env.delete("CONTENT_LENGTH")
|
66
|
+
io = @env.delete("rack.input")
|
67
|
+
buf = ""
|
68
|
+
thr = Thread.new do
|
69
|
+
while buf = io.read(128, buf)
|
70
|
+
wr.write buf
|
71
|
+
end
|
72
|
+
wr.close
|
73
|
+
:ok
|
74
|
+
end
|
75
|
+
@env["rack.input"] = rd
|
76
|
+
sprayer = HTTP_Spew::InputSpray.new(@env, 2)
|
77
|
+
readers = sprayer.readers
|
78
|
+
assert_equal 2, readers.size
|
79
|
+
|
80
|
+
sha1 = Hash[readers.map { |rd| [ rd, Digest::SHA1.new ] } ]
|
81
|
+
|
82
|
+
readers.delete_if do |rd|
|
83
|
+
assert ! rd.respond_to?(:size)
|
84
|
+
if buf = rd.read(0x10000)
|
85
|
+
sha1[rd].update buf
|
86
|
+
false
|
87
|
+
else
|
88
|
+
rd.close.nil?
|
89
|
+
end
|
90
|
+
end until readers.empty?
|
91
|
+
|
92
|
+
sha1.each_value { |dig| assert_equal EXPECT, dig.hexdigest }
|
93
|
+
sprayer.instance_variable_get(:@writers).each { |x| assert x.closed? }
|
94
|
+
thr.join
|
95
|
+
assert_equal :ok, thr.value
|
96
|
+
assert ! rd.closed?
|
97
|
+
assert wr.closed?
|
98
|
+
ensure
|
99
|
+
rd.close
|
100
|
+
end
|
101
|
+
end
|
data/test/test_mirror.rb
ADDED
@@ -0,0 +1,60 @@
|
|
1
|
+
# -*- encoding: binary -*-
|
2
|
+
require "./test/helper"
|
3
|
+
|
4
|
+
class TestMirror < Test::Unit::TestCase
|
5
|
+
def setup
|
6
|
+
@addr, @port, @srv = start_server("./test/mirror.ru")
|
7
|
+
@sockaddr = Socket.pack_sockaddr_in(@port, @addr)
|
8
|
+
@env = {
|
9
|
+
"REQUEST_METHOD" => "PUT",
|
10
|
+
"REQUEST_URI" => "/",
|
11
|
+
"HTTP_HOST" => "example.com",
|
12
|
+
}
|
13
|
+
end
|
14
|
+
|
15
|
+
def teardown
|
16
|
+
Process.kill(:QUIT, @srv)
|
17
|
+
Process.waitpid2(@srv)
|
18
|
+
end
|
19
|
+
|
20
|
+
def test_mirror_small
|
21
|
+
str = rand_data(128)
|
22
|
+
expect = [ str ]
|
23
|
+
req = []
|
24
|
+
req << HTTP_Spew::Request.new(@env, StringIO.new(str), @sockaddr)
|
25
|
+
req << HTTP_Spew::Request.new(@env, StringIO.new(str), @sockaddr)
|
26
|
+
req << HTTP_Spew::Request.new(@env, StringIO.new(str), @sockaddr)
|
27
|
+
rv = HTTP_Spew.wait(3, req, 666000)
|
28
|
+
rv.each do |req|
|
29
|
+
assert_nil req.error
|
30
|
+
response = req.response
|
31
|
+
headers = Rack::Utils::HeaderHash.new(response[1])
|
32
|
+
assert_equal 128, headers["Content-Length"].to_i
|
33
|
+
assert_equal 200, response[0].to_i
|
34
|
+
tmp = []
|
35
|
+
response[2].each { |x| tmp << x.dup }
|
36
|
+
assert_equal expect, tmp
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
# no bidirectional input support
|
41
|
+
def test_mirror_big
|
42
|
+
str = rand_data(128) * (8 * 1024 * 8)
|
43
|
+
expect = str
|
44
|
+
req = []
|
45
|
+
req << HTTP_Spew::Request.new(@env, StringIO.new(str), @sockaddr)
|
46
|
+
req << HTTP_Spew::Request.new(@env, StringIO.new(str), @sockaddr)
|
47
|
+
req << HTTP_Spew::Request.new(@env, StringIO.new(str), @sockaddr)
|
48
|
+
rv = HTTP_Spew.wait(3, req, 6000)
|
49
|
+
rv.each do |req|
|
50
|
+
assert_nil req.error
|
51
|
+
response = req.response
|
52
|
+
headers = Rack::Utils::HeaderHash.new(response[1])
|
53
|
+
assert_equal str.size, headers["Content-Length"].to_i
|
54
|
+
assert_equal 200, response[0].to_i
|
55
|
+
tmp = ""
|
56
|
+
response[2].each { |x| tmp << x }
|
57
|
+
assert_equal expect, tmp
|
58
|
+
end
|
59
|
+
end
|
60
|
+
end
|
@@ -0,0 +1,54 @@
|
|
1
|
+
require "./test/helper"
|
2
|
+
|
3
|
+
class TestRequest < Test::Unit::TestCase
|
4
|
+
def setup
|
5
|
+
@addr, @port, @srv = start_server("./test/sha1.ru", 1)
|
6
|
+
@sockaddr = Socket.pack_sockaddr_in(@port, @addr)
|
7
|
+
@env = {
|
8
|
+
"REQUEST_METHOD" => "PUT",
|
9
|
+
"REQUEST_URI" => "/",
|
10
|
+
"HTTP_HOST" => "example.com",
|
11
|
+
}
|
12
|
+
@tmpfiles = []
|
13
|
+
end
|
14
|
+
|
15
|
+
def teardown
|
16
|
+
Process.kill(:QUIT, @srv)
|
17
|
+
Process.waitpid2(@srv)
|
18
|
+
@tmpfiles.each { |tmp| tmp.closed? or tmp.close! }
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_request_with_existing_socket
|
22
|
+
sock = Kgio::Socket.new(@sockaddr)
|
23
|
+
req = HTTP_Spew::Request.new(@env, nil, sock)
|
24
|
+
assert_equal sock, req.to_io
|
25
|
+
assert_nothing_raised { req.close }
|
26
|
+
assert sock.closed?
|
27
|
+
end
|
28
|
+
|
29
|
+
def test_request_single
|
30
|
+
req = HTTP_Spew::Request.new(@env, nil, @sockaddr)
|
31
|
+
sym = req.resume
|
32
|
+
assert_kind_of(Symbol, sym)
|
33
|
+
if sym == :wait_writable
|
34
|
+
set = Kgio.poll({req => sym}, 100)
|
35
|
+
assert_equal [ req ], set.keys
|
36
|
+
sym = req.resume
|
37
|
+
end
|
38
|
+
assert_equal :wait_readable, sym
|
39
|
+
set = Kgio.poll({req => sym}, 100)
|
40
|
+
assert_equal [ req ], set.keys
|
41
|
+
rv = req.resume
|
42
|
+
assert_equal req, rv[2]
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_request_loop
|
46
|
+
req = HTTP_Spew::Request.new(@env, nil, @sockaddr)
|
47
|
+
until Array === (rv = req.resume)
|
48
|
+
Kgio.poll(req => rv)
|
49
|
+
end
|
50
|
+
assert_kind_of Array, rv
|
51
|
+
assert_equal 3, rv.size
|
52
|
+
assert_equal req, rv[2]
|
53
|
+
end
|
54
|
+
end
|
data/test/test_upload.rb
ADDED
@@ -0,0 +1,127 @@
|
|
1
|
+
# -*- encoding: binary -*-
|
2
|
+
require "./test/helper"
|
3
|
+
|
4
|
+
class TestUpload < Test::Unit::TestCase
|
5
|
+
def setup
|
6
|
+
@addr, @port, @srv = start_server("./test/sha1.ru")
|
7
|
+
@sockaddr = Socket.pack_sockaddr_in(@port, @addr)
|
8
|
+
@env = {
|
9
|
+
"REQUEST_METHOD" => "PUT",
|
10
|
+
"REQUEST_URI" => "/",
|
11
|
+
"HTTP_HOST" => "example.com",
|
12
|
+
}
|
13
|
+
@tmpfiles = []
|
14
|
+
end
|
15
|
+
|
16
|
+
def teardown
|
17
|
+
Process.kill(:QUIT, @srv)
|
18
|
+
Process.waitpid2(@srv)
|
19
|
+
@tmpfiles.each { |tmp| tmp.closed? or tmp.close! }
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_spew_upload_empty
|
23
|
+
req = []
|
24
|
+
req << HTTP_Spew::Request.new(@env, nil, @sockaddr)
|
25
|
+
req << HTTP_Spew::Request.new(@env, nil, @sockaddr)
|
26
|
+
req << HTTP_Spew::Request.new(@env, nil, @sockaddr)
|
27
|
+
rv = HTTP_Spew.wait(3, req, 666000)
|
28
|
+
assert_equal 3, rv.size
|
29
|
+
rv.each do |req|
|
30
|
+
assert_nil req.error
|
31
|
+
response = req.response
|
32
|
+
assert_equal 200, response[0].to_i
|
33
|
+
tmp = []
|
34
|
+
response[2].each { |x| tmp << x.dup }
|
35
|
+
assert_equal [ "da39a3ee5e6b4b0d3255bfef95601890afd80709\n" ], tmp
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def tmp_blob(str)
|
40
|
+
tmp = Tempfile.new "blob"
|
41
|
+
tmp.write str
|
42
|
+
tmp.flush
|
43
|
+
assert_equal str.size, tmp.size
|
44
|
+
tmp.rewind
|
45
|
+
@tmpfiles << tmp
|
46
|
+
tmp
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_spew_upload_big
|
50
|
+
str = rand_data(128) * (8 * 1024 * 4)
|
51
|
+
expect = [ Digest::SHA1.hexdigest(str) << "\n" ]
|
52
|
+
req = []
|
53
|
+
req << HTTP_Spew::Request.new(@env, tmp_blob(str), @sockaddr)
|
54
|
+
req << HTTP_Spew::Request.new(@env, tmp_blob(str), @sockaddr)
|
55
|
+
req << HTTP_Spew::Request.new(@env, tmp_blob(str), @sockaddr)
|
56
|
+
rv = HTTP_Spew.wait(3, req, 666000)
|
57
|
+
assert_equal 3, rv.size
|
58
|
+
rv.each do |req|
|
59
|
+
assert_nil req.error
|
60
|
+
response = req.response
|
61
|
+
assert_equal 200, response[0].to_i
|
62
|
+
tmp = []
|
63
|
+
response[2].each { |x| tmp << x.dup }
|
64
|
+
assert_equal expect, tmp
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def test_spew_upload_small
|
69
|
+
str = rand_data(128)
|
70
|
+
expect = [ Digest::SHA1.hexdigest(str) << "\n" ]
|
71
|
+
req = []
|
72
|
+
req << HTTP_Spew::Request.new(@env, StringIO.new(str), @sockaddr)
|
73
|
+
req << HTTP_Spew::Request.new(@env, StringIO.new(str), @sockaddr)
|
74
|
+
req << HTTP_Spew::Request.new(@env, StringIO.new(str), @sockaddr)
|
75
|
+
rv = HTTP_Spew.wait(3, req, 666000)
|
76
|
+
assert_equal 3, rv.size
|
77
|
+
rv.each do |req|
|
78
|
+
assert_nil req.error
|
79
|
+
response = req.response
|
80
|
+
assert_equal 200, response[0].to_i
|
81
|
+
tmp = []
|
82
|
+
response[2].each { |x| tmp << x.dup }
|
83
|
+
assert_equal expect, tmp
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def test_spew_upload_small_two_of_three
|
88
|
+
str = rand_data(128)
|
89
|
+
expect = [ Digest::SHA1.hexdigest(str) << "\n" ]
|
90
|
+
req = []
|
91
|
+
req << HTTP_Spew::Request.new(@env, StringIO.new(str), @sockaddr)
|
92
|
+
req << HTTP_Spew::Request.new(@env, StringIO.new(str), @sockaddr)
|
93
|
+
req << HTTP_Spew::Request.new(@env, StringIO.new(str), @sockaddr)
|
94
|
+
rv = HTTP_Spew.wait(2, req, 666000)
|
95
|
+
assert_equal 3, rv.size
|
96
|
+
rv[0, 2].each do |req|
|
97
|
+
assert_nil req.error
|
98
|
+
response = req.response
|
99
|
+
assert_equal 200, response[0].to_i
|
100
|
+
tmp = []
|
101
|
+
response[2].each { |x| tmp << x.dup }
|
102
|
+
assert_equal expect, tmp
|
103
|
+
assert_nothing_raised { response[2].close }
|
104
|
+
assert req.to_io.closed?
|
105
|
+
end
|
106
|
+
failed = rv[2]
|
107
|
+
assert_kind_of(HTTP_Spew::ConnectionReset, failed.error)
|
108
|
+
assert failed.to_io.closed?
|
109
|
+
end
|
110
|
+
|
111
|
+
def test_spew_upload_nonblock
|
112
|
+
str = rand_data(128)
|
113
|
+
req = []
|
114
|
+
req << HTTP_Spew::Request.new(@env, StringIO.new(str), @sockaddr)
|
115
|
+
req << HTTP_Spew::Request.new(@env, StringIO.new(str), @sockaddr)
|
116
|
+
req << HTTP_Spew::Request.new(@env, StringIO.new(str), @sockaddr)
|
117
|
+
before = req.dup
|
118
|
+
rv = HTTP_Spew.wait_nonblock!(3, req)
|
119
|
+
assert_nil rv
|
120
|
+
while rv.nil? do
|
121
|
+
rv = HTTP_Spew.wait_nonblock!(3, req)
|
122
|
+
end
|
123
|
+
assert_nil rv.uniq!
|
124
|
+
assert rv.size > 0
|
125
|
+
rv.each { |req| assert before.include?(req) }
|
126
|
+
end
|
127
|
+
end
|