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