rainbows 2.1.0 → 3.0.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/GIT-VERSION-GEN +1 -1
- data/GNUmakefile +2 -3
- data/Rakefile +5 -2
- data/lib/rainbows.rb +72 -54
- data/lib/rainbows/base.rb +7 -9
- data/lib/rainbows/client.rb +25 -4
- data/lib/rainbows/const.rb +1 -1
- data/lib/rainbows/coolio.rb +6 -3
- data/lib/rainbows/coolio/client.rb +78 -57
- data/lib/rainbows/coolio/core.rb +1 -4
- data/lib/rainbows/coolio/heartbeat.rb +2 -3
- data/lib/rainbows/coolio/master.rb +3 -2
- data/lib/rainbows/coolio/{deferred_chunk_response.rb → response_chunk_pipe.rb} +1 -2
- data/lib/rainbows/coolio/{deferred_response.rb → response_pipe.rb} +1 -1
- data/lib/rainbows/coolio/thread_client.rb +4 -6
- data/lib/rainbows/coolio_fiber_spawn.rb +1 -1
- data/lib/rainbows/coolio_thread_pool.rb +1 -1
- data/lib/rainbows/coolio_thread_pool/watcher.rb +2 -4
- data/lib/rainbows/coolio_thread_spawn.rb +1 -1
- data/lib/rainbows/dev_fd_response.rb +2 -2
- data/lib/rainbows/error.rb +5 -7
- data/lib/rainbows/ev_core.rb +20 -7
- data/lib/rainbows/event_machine.rb +6 -5
- data/lib/rainbows/event_machine/client.rb +46 -53
- data/lib/rainbows/event_machine/response_pipe.rb +2 -3
- data/lib/rainbows/fiber/base.rb +5 -5
- data/lib/rainbows/fiber/body.rb +4 -13
- data/lib/rainbows/fiber/coolio/heartbeat.rb +1 -3
- data/lib/rainbows/fiber/coolio/server.rb +4 -7
- data/lib/rainbows/fiber_pool.rb +1 -1
- data/lib/rainbows/fiber_spawn.rb +2 -2
- data/lib/rainbows/http_parser.rb +12 -0
- data/lib/rainbows/http_server.rb +5 -7
- data/lib/rainbows/max_body.rb +2 -2
- data/lib/rainbows/never_block/core.rb +1 -1
- data/lib/rainbows/process_client.rb +15 -29
- data/lib/rainbows/queue_pool.rb +1 -3
- data/lib/rainbows/rack_input.rb +3 -3
- data/lib/rainbows/response.rb +164 -38
- data/lib/rainbows/revactor.rb +5 -65
- data/lib/rainbows/revactor/client.rb +60 -0
- data/lib/rainbows/revactor/{body.rb → client/methods.rb} +14 -14
- data/lib/rainbows/revactor/{tee_socket.rb → client/tee_socket.rb} +1 -1
- data/lib/rainbows/sendfile.rb +1 -2
- data/lib/rainbows/server_token.rb +1 -1
- data/lib/rainbows/thread_pool.rb +9 -9
- data/lib/rainbows/thread_spawn.rb +7 -6
- data/lib/rainbows/thread_timeout.rb +1 -1
- data/lib/rainbows/writer_thread_pool.rb +9 -25
- data/lib/rainbows/writer_thread_pool/client.rb +44 -1
- data/lib/rainbows/writer_thread_spawn.rb +2 -11
- data/lib/rainbows/writer_thread_spawn/client.rb +53 -13
- data/rainbows.gemspec +3 -12
- data/t/async_chunk_app.ru +62 -0
- data/t/byte-range-common.sh +142 -0
- data/t/t0022-copy_stream-byte-range.sh +2 -111
- data/t/t0023-sendfile-byte-range.sh +2 -32
- data/t/t0025-write-on-close.sh +23 -0
- data/t/t0040-keepalive_requests-setting.sh +0 -5
- data/t/t0402-async-keepalive.sh +146 -0
- data/t/t0500-cramp-streaming.sh +2 -0
- data/t/t0501-cramp-rainsocket.sh +2 -0
- data/t/t9000-rack-app-pool.sh +1 -1
- data/t/test_isolate.rb +5 -10
- data/t/test_isolate_cramp.rb +26 -0
- data/t/write-on-close.ru +11 -0
- metadata +33 -30
- data/lib/rainbows/coolio/sendfile.rb +0 -17
- data/lib/rainbows/response/body.rb +0 -127
- data/lib/rainbows/response/range.rb +0 -34
- data/lib/rainbows/timed_read.rb +0 -28
@@ -19,19 +19,11 @@ require 'thread'
|
|
19
19
|
# vulnerable to slow client denial-of-service attacks.
|
20
20
|
|
21
21
|
module Rainbows::WriterThreadSpawn
|
22
|
-
# :stopdoc:
|
23
22
|
include Rainbows::Base
|
24
|
-
|
25
|
-
def write_body(my_sock, body, range) # :nodoc:
|
26
|
-
if body.respond_to?(:close)
|
27
|
-
Rainbows::SyncClose.new(body) { |body| my_sock.queue_body(body, range) }
|
28
|
-
else
|
29
|
-
my_sock.queue_body(body, range)
|
30
|
-
end
|
31
|
-
end
|
23
|
+
autoload :Client, 'rainbows/writer_thread_spawn/client'
|
32
24
|
|
33
25
|
def process_client(client) # :nodoc:
|
34
|
-
|
26
|
+
Client.new(client).process_loop
|
35
27
|
end
|
36
28
|
|
37
29
|
def worker_loop(worker) # :nodoc:
|
@@ -42,4 +34,3 @@ module Rainbows::WriterThreadSpawn
|
|
42
34
|
# :startdoc:
|
43
35
|
end
|
44
36
|
# :enddoc:
|
45
|
-
require 'rainbows/writer_thread_spawn/client'
|
@@ -3,17 +3,60 @@
|
|
3
3
|
# used to wrap a BasicSocket to use with +q+ for all writes
|
4
4
|
# this is compatible with IO.select
|
5
5
|
class Rainbows::WriterThreadSpawn::Client < Struct.new(:to_io, :q, :thr)
|
6
|
-
include Rainbows::Response
|
7
6
|
include Rainbows::SocketProxy
|
7
|
+
include Rainbows::ProcessClient
|
8
8
|
include Rainbows::WorkerYield
|
9
9
|
|
10
10
|
CUR = {} # :nodoc:
|
11
11
|
|
12
|
+
module Methods
|
13
|
+
def write_body_each(body)
|
14
|
+
q << [ :write_body_each, body ]
|
15
|
+
end
|
16
|
+
|
17
|
+
def write_response_close(status, headers, body, alive)
|
18
|
+
to_io.instance_variable_set(:@hp, @hp) # XXX ugh
|
19
|
+
Rainbows::SyncClose.new(body) { |sync_body|
|
20
|
+
q << [ :write_response, status, headers, sync_body, alive ]
|
21
|
+
}
|
22
|
+
end
|
23
|
+
|
24
|
+
if IO.respond_to?(:copy_stream) || IO.method_defined?(:sendfile_nonblock)
|
25
|
+
def write_response(status, headers, body, alive)
|
26
|
+
self.q ||= queue_writer
|
27
|
+
if body.respond_to?(:close)
|
28
|
+
write_response_close(status, headers, body, alive)
|
29
|
+
elsif body.respond_to?(:to_path)
|
30
|
+
write_response_path(status, headers, body, alive)
|
31
|
+
else
|
32
|
+
super
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
def write_body_file(body, range)
|
37
|
+
q << [ :write_body_file, body, range ]
|
38
|
+
end
|
39
|
+
|
40
|
+
def write_body_stream(body)
|
41
|
+
q << [ :write_body_stream, body ]
|
42
|
+
end
|
43
|
+
else # each-only body response
|
44
|
+
def write_response(status, headers, body, alive)
|
45
|
+
self.q ||= queue_writer
|
46
|
+
if body.respond_to?(:close)
|
47
|
+
write_response_close(status, headers, body, alive)
|
48
|
+
else
|
49
|
+
super
|
50
|
+
end
|
51
|
+
end
|
52
|
+
end # each-only body response
|
53
|
+
end # module Methods
|
54
|
+
include Methods
|
55
|
+
|
12
56
|
def self.quit
|
13
|
-
g = Rainbows::G
|
14
57
|
CUR.delete_if do |t,q|
|
15
58
|
q << nil
|
16
|
-
|
59
|
+
Rainbows.tick
|
17
60
|
t.alive? ? t.join(0.01) : true
|
18
61
|
end until CUR.empty?
|
19
62
|
end
|
@@ -27,16 +70,17 @@ class Rainbows::WriterThreadSpawn::Client < Struct.new(:to_io, :q, :thr)
|
|
27
70
|
|
28
71
|
q = Queue.new
|
29
72
|
self.thr = Thread.new(to_io, q) do |io, q|
|
30
|
-
while
|
73
|
+
while op = q.shift
|
31
74
|
begin
|
32
|
-
|
33
|
-
case
|
34
|
-
when
|
75
|
+
op, *rest = op
|
76
|
+
case op
|
77
|
+
when String
|
78
|
+
io.kgio_write(op)
|
35
79
|
when :close
|
36
80
|
io.close unless io.closed?
|
37
81
|
break
|
38
82
|
else
|
39
|
-
io.
|
83
|
+
io.__send__ op, *rest
|
40
84
|
end
|
41
85
|
rescue => e
|
42
86
|
Rainbows::Error.write(io, e)
|
@@ -51,10 +95,6 @@ class Rainbows::WriterThreadSpawn::Client < Struct.new(:to_io, :q, :thr)
|
|
51
95
|
(self.q ||= queue_writer) << buf
|
52
96
|
end
|
53
97
|
|
54
|
-
def queue_body(body, range)
|
55
|
-
(self.q ||= queue_writer) << [ :body, body, range ]
|
56
|
-
end
|
57
|
-
|
58
98
|
def close
|
59
99
|
if q
|
60
100
|
q << :close
|
@@ -64,6 +104,6 @@ class Rainbows::WriterThreadSpawn::Client < Struct.new(:to_io, :q, :thr)
|
|
64
104
|
end
|
65
105
|
|
66
106
|
def closed?
|
67
|
-
|
107
|
+
to_io.closed?
|
68
108
|
end
|
69
109
|
end
|
data/rainbows.gemspec
CHANGED
@@ -1,14 +1,6 @@
|
|
1
1
|
# -*- encoding: binary -*-
|
2
|
-
|
3
2
|
ENV["VERSION"] or abort "VERSION= must be specified"
|
4
3
|
manifest = File.readlines('.manifest').map! { |x| x.chomp! }
|
5
|
-
|
6
|
-
# don't bother with tests that fork, not worth our time to get working
|
7
|
-
# with `gem check -t` ... (of course we care for them when testing with
|
8
|
-
# GNU make when they can run in parallel)
|
9
|
-
test_files = manifest.grep(%r{\Atest/unit/test_.*\.rb\z}).map do |f|
|
10
|
-
File.readlines(f).grep(/\bfork\b/).empty? ? f : nil
|
11
|
-
end.compact
|
12
4
|
require 'wrongdoc'
|
13
5
|
extend Wrongdoc::Gemspec
|
14
6
|
name, summary, title = readme_metadata
|
@@ -29,16 +21,15 @@ Gem::Specification.new do |s|
|
|
29
21
|
s.rdoc_options = rdoc_options
|
30
22
|
s.require_paths = %w(lib)
|
31
23
|
s.rubyforge_project = %q{rainbows}
|
32
|
-
|
33
|
-
s.test_files = test_files
|
24
|
+
s.test_files = []
|
34
25
|
|
35
26
|
# we want a newer Rack for a valid HeaderHash#each
|
36
27
|
s.add_dependency(%q<rack>, ['~> 1.1'])
|
37
28
|
|
38
29
|
# we need Unicorn for the HTTP parser and process management
|
39
|
-
s.add_dependency(%q<unicorn>, ["~> 3.
|
30
|
+
s.add_dependency(%q<unicorn>, ["~> 3.3"])
|
40
31
|
s.add_development_dependency(%q<isolate>, "~> 3.0.0")
|
41
|
-
s.add_development_dependency(%q<wrongdoc>, "~> 1.
|
32
|
+
s.add_development_dependency(%q<wrongdoc>, "~> 1.1")
|
42
33
|
|
43
34
|
# optional runtime dependencies depending on configuration
|
44
35
|
# see t/test_isolate.rb for the exact versions we've tested with
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# based on async_examples/async_app.ru by James Tucker
|
2
|
+
class DeferrableChunkBody
|
3
|
+
include EventMachine::Deferrable
|
4
|
+
|
5
|
+
def call(*body)
|
6
|
+
body.each do |chunk|
|
7
|
+
@body_callback.call("#{chunk.size.to_s(16)}\r\n")
|
8
|
+
@body_callback.call(chunk)
|
9
|
+
@body_callback.call("\r\n")
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def each(&block)
|
14
|
+
@body_callback = block
|
15
|
+
end
|
16
|
+
|
17
|
+
def finish
|
18
|
+
@body_callback.call("0\r\n\r\n")
|
19
|
+
end
|
20
|
+
end if defined?(EventMachine)
|
21
|
+
|
22
|
+
class AsyncChunkApp
|
23
|
+
def call(env)
|
24
|
+
headers = {
|
25
|
+
'Content-Type' => 'text/plain',
|
26
|
+
'Transfer-Encoding' => 'chunked',
|
27
|
+
}
|
28
|
+
delay = env["HTTP_X_DELAY"].to_i
|
29
|
+
|
30
|
+
case env["rainbows.model"]
|
31
|
+
when :EventMachine, :NeverBlock
|
32
|
+
body = DeferrableChunkBody.new
|
33
|
+
body.callback { body.finish }
|
34
|
+
task = lambda {
|
35
|
+
env['async.callback'].call([ 200, headers, body ])
|
36
|
+
EM.add_timer(1) {
|
37
|
+
body.call "Hello "
|
38
|
+
|
39
|
+
EM.add_timer(1) {
|
40
|
+
body.call "World #{env['PATH_INFO']}\n"
|
41
|
+
body.succeed
|
42
|
+
}
|
43
|
+
}
|
44
|
+
}
|
45
|
+
delay == 0 ? EM.next_tick(&task) : EM.add_timer(delay, &task)
|
46
|
+
when :Coolio
|
47
|
+
# Cool.io only does one-shot responses due to the lack of the
|
48
|
+
# equivalent of EM::Deferrables
|
49
|
+
body = [ "Hello ", "World #{env['PATH_INFO']}\n", '' ].map do |chunk|
|
50
|
+
"#{chunk.size.to_s(16)}\r\n#{chunk}\r\n"
|
51
|
+
end
|
52
|
+
|
53
|
+
next_tick = Coolio::TimerWatcher.new(delay, false)
|
54
|
+
next_tick.on_timer { env['async.callback'].call([ 200, headers, body ]) }
|
55
|
+
next_tick.attach(Coolio::Loop.default)
|
56
|
+
else
|
57
|
+
raise "Not supported: #{env['rainbows.model']}"
|
58
|
+
end
|
59
|
+
nil
|
60
|
+
end
|
61
|
+
end
|
62
|
+
run AsyncChunkApp.new
|
@@ -0,0 +1,142 @@
|
|
1
|
+
t_begin "byte-range setup vars" && {
|
2
|
+
random_blob_size=$(wc -c < random_blob)
|
3
|
+
rb_1=$(( $random_blob_size - 1 ))
|
4
|
+
range_head=-r-365
|
5
|
+
range_tail=-r155-
|
6
|
+
range_mid=-r200-300
|
7
|
+
range_n1=-r0-$rb_1
|
8
|
+
range_n2=-r0-$(($rb_1 - 1))
|
9
|
+
range_1b_head=-r0-0
|
10
|
+
range_1b_tail=-r$rb_1-$rb_1
|
11
|
+
range_1b_mid=-r200-200
|
12
|
+
range_all=-r0-$random_blob_size
|
13
|
+
url=http://$listen/random_blob
|
14
|
+
}
|
15
|
+
|
16
|
+
check_content_range () {
|
17
|
+
grep '^< HTTP/1\.1 206 Partial Content' $err
|
18
|
+
grep 'Range:' $err
|
19
|
+
# Content-Range: bytes #{offset}-#{offset+count-1}/#{clen}
|
20
|
+
d='\([0-9]\+\)'
|
21
|
+
start= end= size=
|
22
|
+
eval $(< $err sed -n -e \
|
23
|
+
"s/^< Content-Range: bytes $d-$d\/$d"'.*$/start=\1 end=\2 size=\3/p')
|
24
|
+
test -n "$start"
|
25
|
+
test -n "$end"
|
26
|
+
test -n "$size"
|
27
|
+
|
28
|
+
# ensure we didn't screw up the sed invocation
|
29
|
+
expect="< Content-Range: bytes $start-$end/$size"
|
30
|
+
test x"$(grep -F "$expect" $err)" = x"$(grep '^< Content-Range:' $err)"
|
31
|
+
|
32
|
+
test $start -le $end
|
33
|
+
test $end -lt $size
|
34
|
+
}
|
35
|
+
|
36
|
+
t_begin "read random blob sha1s" && {
|
37
|
+
sha1_head=$(curl -sSff $range_head file://random_blob | rsha1)
|
38
|
+
sha1_tail=$(curl -sSff $range_tail file://random_blob | rsha1)
|
39
|
+
sha1_mid=$(curl -sSff $range_mid file://random_blob | rsha1)
|
40
|
+
sha1_n1=$(curl -sSff $range_n1 file://random_blob | rsha1)
|
41
|
+
sha1_n2=$(curl -sSff $range_n2 file://random_blob | rsha1)
|
42
|
+
sha1_1b_head=$(curl -sSff $range_1b_head file://random_blob | rsha1)
|
43
|
+
sha1_1b_tail=$(curl -sSff $range_1b_tail file://random_blob | rsha1)
|
44
|
+
sha1_1b_mid=$(curl -sSff $range_1b_mid file://random_blob | rsha1)
|
45
|
+
sha1_all=$(rsha1 < random_blob)
|
46
|
+
echo "$sha1_all=$sha1_n1"
|
47
|
+
}
|
48
|
+
|
49
|
+
t_begin "normal full request matches" && {
|
50
|
+
sha1="$(curl -v 2>$err -sSf $url | rsha1)"
|
51
|
+
test x"$sha1_all" = x"$sha1"
|
52
|
+
grep 'Content-Range:' $err && die "Content-Range unexpected"
|
53
|
+
grep 'HTTP/1.1 200 OK' $err || die "200 response expected"
|
54
|
+
}
|
55
|
+
|
56
|
+
t_begin "crazy offset goes over" && {
|
57
|
+
range_insane=-r$(($random_blob_size * 2))-$(($random_blob_size * 4))
|
58
|
+
curl -vsS 2>$err $range_insane $url >/dev/null
|
59
|
+
grep '^< HTTP/1\.[01] 416 ' $err || die "expected 416 error"
|
60
|
+
grep '^< Content-Range: bytes \*/'$random_blob_size $err || \
|
61
|
+
die "expected Content-Range: bytes */SIZE"
|
62
|
+
}
|
63
|
+
|
64
|
+
t_begin "keepalive/pipelining is supported on 416 responses" && {
|
65
|
+
rm -f $tmp
|
66
|
+
(
|
67
|
+
cat $fifo > $tmp &
|
68
|
+
printf 'GET /byte-range-common.sh HTTP/1.1\r\n'
|
69
|
+
printf 'Host: %s\r\n' $listen
|
70
|
+
printf 'Range: bytes=9999999999-9999999999\r\n\r\n'
|
71
|
+
printf 'GET /byte-range-common.sh HTTP/1.1\r\n'
|
72
|
+
printf 'Host: %s\r\n' $listen
|
73
|
+
printf 'Connection: close\r\n'
|
74
|
+
printf 'Range: bytes=0-0\r\n\r\n'
|
75
|
+
wait
|
76
|
+
) | socat - TCP:$listen > $fifo
|
77
|
+
|
78
|
+
< $tmp awk '
|
79
|
+
/^HTTP\/1\.1 / && NR == 1 && $2 == 416 { first = $2 }
|
80
|
+
/^HTTP\/1\.1 / && NR != 1 && $2 == 206 { second = $2 }
|
81
|
+
END { exit((first == 416 && second == 206) ? 0 : 1) }
|
82
|
+
'
|
83
|
+
}
|
84
|
+
|
85
|
+
t_begin "full request matches with explicit ranges" && {
|
86
|
+
sha1="$(curl -v 2>$err $range_all -sSf $url | rsha1)"
|
87
|
+
check_content_range
|
88
|
+
test x"$sha1_all" = x"$sha1"
|
89
|
+
|
90
|
+
sha1="$(curl -v 2>$err $range_n1 -sSf $url | rsha1)"
|
91
|
+
check_content_range
|
92
|
+
test x"$sha1_all" = x"$sha1"
|
93
|
+
|
94
|
+
range_over=-r0-$(($random_blob_size * 2))
|
95
|
+
sha1="$(curl -v 2>$err $range_over -sSf $url | rsha1)"
|
96
|
+
check_content_range
|
97
|
+
test x"$sha1_all" = x"$sha1"
|
98
|
+
}
|
99
|
+
|
100
|
+
t_begin "no fence post errors" && {
|
101
|
+
sha1="$(curl -v 2>$err $range_n2 -sSf $url | rsha1)"
|
102
|
+
check_content_range
|
103
|
+
test x"$sha1_n2" = x"$sha1"
|
104
|
+
|
105
|
+
sha1="$(curl -v 2>$err $range_1b_head -sSf $url | rsha1)"
|
106
|
+
check_content_range
|
107
|
+
test x"$sha1_1b_head" = x"$sha1"
|
108
|
+
|
109
|
+
sha1="$(curl -v 2>$err $range_1b_tail -sSf $url | rsha1)"
|
110
|
+
check_content_range
|
111
|
+
test x"$sha1_1b_tail" = x"$sha1"
|
112
|
+
|
113
|
+
sha1="$(curl -v 2>$err $range_1b_mid -sSf $url | rsha1)"
|
114
|
+
check_content_range
|
115
|
+
test x"$sha1_1b_mid" = x"$sha1"
|
116
|
+
}
|
117
|
+
|
118
|
+
t_begin "head range matches" && {
|
119
|
+
sha1="$(curl -sSfv 2>$err $range_head $url | rsha1)"
|
120
|
+
check_content_range
|
121
|
+
test x"$sha1_head" = x"$sha1"
|
122
|
+
}
|
123
|
+
|
124
|
+
t_begin "tail range matches" && {
|
125
|
+
sha1="$(curl -sSfv 2>$err $range_tail $url | rsha1)"
|
126
|
+
check_content_range
|
127
|
+
test x"$sha1_tail" = x"$sha1"
|
128
|
+
}
|
129
|
+
|
130
|
+
t_begin "mid range matches" && {
|
131
|
+
sha1="$(curl -sSfv 2>$err $range_mid $url | rsha1)"
|
132
|
+
check_content_range
|
133
|
+
test x"$sha1_mid" = x"$sha1"
|
134
|
+
}
|
135
|
+
|
136
|
+
t_begin "shutdown server" && {
|
137
|
+
kill -QUIT $rainbows_pid
|
138
|
+
}
|
139
|
+
|
140
|
+
t_begin "check stderr" && check_stderr
|
141
|
+
|
142
|
+
t_done
|
@@ -17,7 +17,7 @@ ThreadSpawn|WriterThreadSpawn|ThreadPool|WriterThreadPool|Base) ;;
|
|
17
17
|
;;
|
18
18
|
esac
|
19
19
|
|
20
|
-
t_plan
|
20
|
+
t_plan 13 "IO.copy_stream byte range response for $model"
|
21
21
|
|
22
22
|
t_begin "setup and startup" && {
|
23
23
|
rtmpfiles out err
|
@@ -25,115 +25,6 @@ t_begin "setup and startup" && {
|
|
25
25
|
# can't load Rack::Lint here since it clobbers body#to_path
|
26
26
|
rainbows -E none -D large-file-response.ru -c $unicorn_config
|
27
27
|
rainbows_wait_start
|
28
|
-
random_blob_size=$(wc -c < random_blob)
|
29
|
-
rb_1=$(( $random_blob_size - 1 ))
|
30
|
-
range_head=-r-365
|
31
|
-
range_tail=-r155-
|
32
|
-
range_mid=-r200-300
|
33
|
-
range_n1=-r0-$rb_1
|
34
|
-
range_n2=-r0-$(($rb_1 - 1))
|
35
|
-
range_1b_head=-r0-0
|
36
|
-
range_1b_tail=-r$rb_1-$rb_1
|
37
|
-
range_1b_mid=-r200-200
|
38
|
-
range_all=-r0-$random_blob_size
|
39
|
-
url=http://$listen/random_blob
|
40
28
|
}
|
41
29
|
|
42
|
-
|
43
|
-
# Content-Range: bytes #{offset}-#{offset+count-1}/#{clen}
|
44
|
-
awk -F/ -v E=0 -v size=$random_blob_size '
|
45
|
-
$2 == size && /^< Content-Range: bytes [0-9]+-[0-9]+\// {
|
46
|
-
split($1, a, /-/);
|
47
|
-
if (a[1] < size) {
|
48
|
-
E = 0;
|
49
|
-
exit(0);
|
50
|
-
}
|
51
|
-
}
|
52
|
-
END { exit(E) }
|
53
|
-
' < $err
|
54
|
-
}
|
55
|
-
|
56
|
-
t_begin "read random blob sha1s" && {
|
57
|
-
sha1_head=$(curl -sSff $range_head file://random_blob | rsha1)
|
58
|
-
sha1_tail=$(curl -sSff $range_tail file://random_blob | rsha1)
|
59
|
-
sha1_mid=$(curl -sSff $range_mid file://random_blob | rsha1)
|
60
|
-
sha1_n1=$(curl -sSff $range_n1 file://random_blob | rsha1)
|
61
|
-
sha1_n2=$(curl -sSff $range_n2 file://random_blob | rsha1)
|
62
|
-
sha1_1b_head=$(curl -sSff $range_1b_head file://random_blob | rsha1)
|
63
|
-
sha1_1b_tail=$(curl -sSff $range_1b_tail file://random_blob | rsha1)
|
64
|
-
sha1_1b_mid=$(curl -sSff $range_1b_mid file://random_blob | rsha1)
|
65
|
-
sha1_all=$(rsha1 < random_blob)
|
66
|
-
echo "$sha1_all=$sha1_n1"
|
67
|
-
}
|
68
|
-
|
69
|
-
t_begin "normal full request matches" && {
|
70
|
-
sha1="$(curl -v 2>$err -sSf $url | rsha1)"
|
71
|
-
test x"$sha1_all" = x"$sha1"
|
72
|
-
grep 'Content-Range:' $err && die "Content-Range unexpected"
|
73
|
-
grep 'HTTP/1.1 200 OK' $err || die "200 response expected"
|
74
|
-
}
|
75
|
-
|
76
|
-
t_begin "crazy offset goes over" && {
|
77
|
-
range_insane=-r$(($random_blob_size * 2))-$(($random_blob_size * 4))
|
78
|
-
curl -vsS 2>$err $range_insane $url
|
79
|
-
grep 'HTTP/1\.[01] 416 ' $err || die "expected 416 error"
|
80
|
-
}
|
81
|
-
|
82
|
-
t_begin "full request matches with explicit ranges" && {
|
83
|
-
sha1="$(curl -v 2>$err $range_all -sSf $url | rsha1)"
|
84
|
-
check_content_range
|
85
|
-
test x"$sha1_all" = x"$sha1"
|
86
|
-
|
87
|
-
sha1="$(curl -v 2>$err $range_n1 -sSf $url | rsha1)"
|
88
|
-
check_content_range
|
89
|
-
test x"$sha1_all" = x"$sha1"
|
90
|
-
|
91
|
-
range_over=-r0-$(($random_blob_size * 2))
|
92
|
-
sha1="$(curl -v 2>$err $range_over -sSf $url | rsha1)"
|
93
|
-
check_content_range
|
94
|
-
test x"$sha1_all" = x"$sha1"
|
95
|
-
}
|
96
|
-
|
97
|
-
t_begin "no fence post errors" && {
|
98
|
-
sha1="$(curl -v 2>$err $range_n2 -sSf $url | rsha1)"
|
99
|
-
check_content_range
|
100
|
-
test x"$sha1_n2" = x"$sha1"
|
101
|
-
|
102
|
-
sha1="$(curl -v 2>$err $range_1b_head -sSf $url | rsha1)"
|
103
|
-
check_content_range
|
104
|
-
test x"$sha1_1b_head" = x"$sha1"
|
105
|
-
|
106
|
-
sha1="$(curl -v 2>$err $range_1b_tail -sSf $url | rsha1)"
|
107
|
-
check_content_range
|
108
|
-
test x"$sha1_1b_tail" = x"$sha1"
|
109
|
-
|
110
|
-
sha1="$(curl -v 2>$err $range_1b_mid -sSf $url | rsha1)"
|
111
|
-
check_content_range
|
112
|
-
test x"$sha1_1b_mid" = x"$sha1"
|
113
|
-
}
|
114
|
-
|
115
|
-
t_begin "head range matches" && {
|
116
|
-
sha1="$(curl -sSfv $range_head $url | rsha1)"
|
117
|
-
check_content_range
|
118
|
-
test x"$sha1_head" = x"$sha1"
|
119
|
-
}
|
120
|
-
|
121
|
-
t_begin "tail range matches" && {
|
122
|
-
sha1="$(curl -sSf $range_tail $url | rsha1)"
|
123
|
-
check_content_range
|
124
|
-
test x"$sha1_tail" = x"$sha1"
|
125
|
-
}
|
126
|
-
|
127
|
-
t_begin "mid range matches" && {
|
128
|
-
sha1="$(curl -sSf $range_mid $url | rsha1)"
|
129
|
-
check_content_range
|
130
|
-
test x"$sha1_mid" = x"$sha1"
|
131
|
-
}
|
132
|
-
|
133
|
-
t_begin "shutdown server" && {
|
134
|
-
kill -QUIT $rainbows_pid
|
135
|
-
}
|
136
|
-
|
137
|
-
t_begin "check stderr" && check_stderr
|
138
|
-
|
139
|
-
t_done
|
30
|
+
. ./byte-range-common.sh
|