rainbows 0.94.0 → 0.95.0
Sign up to get free protection for your applications and to get access to all the features.
- data/.document +1 -0
- data/.manifest +18 -0
- data/ChangeLog +394 -226
- data/GIT-VERSION-FILE +1 -1
- data/GIT-VERSION-GEN +1 -1
- data/GNUmakefile +6 -4
- data/NEWS +18 -0
- data/README +13 -5
- data/Static_Files +71 -0
- data/TODO +12 -0
- data/Test_Suite +1 -1
- data/bin/rainbows +1 -4
- data/lib/rainbows/actor_spawn.rb +1 -1
- data/lib/rainbows/app_pool.rb +1 -1
- data/lib/rainbows/base.rb +79 -89
- data/lib/rainbows/byte_slice.rb +17 -0
- data/lib/rainbows/configurator.rb +46 -0
- data/lib/rainbows/const.rb +2 -2
- data/lib/rainbows/dev_fd_response.rb +52 -44
- data/lib/rainbows/error.rb +1 -0
- data/lib/rainbows/ev_core.rb +3 -2
- data/lib/rainbows/event_machine.rb +26 -24
- data/lib/rainbows/fiber/base.rb +30 -40
- data/lib/rainbows/fiber/body.rb +34 -0
- data/lib/rainbows/fiber/io.rb +28 -8
- data/lib/rainbows/fiber/queue.rb +1 -0
- data/lib/rainbows/fiber/rev.rb +4 -2
- data/lib/rainbows/fiber.rb +1 -0
- data/lib/rainbows/fiber_pool.rb +2 -2
- data/lib/rainbows/fiber_spawn.rb +2 -2
- data/lib/rainbows/http_response.rb +20 -31
- data/lib/rainbows/http_server.rb +3 -4
- data/lib/rainbows/max_body.rb +1 -0
- data/lib/rainbows/never_block/event_machine.rb +2 -0
- data/lib/rainbows/never_block.rb +5 -4
- data/lib/rainbows/queue_pool.rb +1 -0
- data/lib/rainbows/response/body.rb +119 -0
- data/lib/rainbows/response.rb +43 -0
- data/lib/rainbows/rev/client.rb +79 -9
- data/lib/rainbows/rev/core.rb +4 -0
- data/lib/rainbows/rev/deferred_response.rb +1 -44
- data/lib/rainbows/rev/heartbeat.rb +1 -0
- data/lib/rainbows/rev/master.rb +1 -0
- data/lib/rainbows/rev/sendfile.rb +26 -0
- data/lib/rainbows/rev/thread.rb +2 -1
- data/lib/rainbows/rev.rb +2 -0
- data/lib/rainbows/rev_fiber_spawn.rb +3 -1
- data/lib/rainbows/rev_thread_pool.rb +7 -5
- data/lib/rainbows/rev_thread_spawn.rb +2 -2
- data/lib/rainbows/revactor.rb +146 -146
- data/lib/rainbows/sendfile.rb +10 -21
- data/lib/rainbows/server_token.rb +39 -0
- data/lib/rainbows/stream_file.rb +14 -0
- data/lib/rainbows/tee_input.rb +1 -0
- data/lib/rainbows/thread_pool.rb +12 -7
- data/lib/rainbows/thread_spawn.rb +2 -3
- data/lib/rainbows/writer_thread_pool.rb +13 -7
- data/lib/rainbows/writer_thread_spawn.rb +12 -9
- data/lib/rainbows.rb +16 -45
- data/rainbows.gemspec +8 -8
- data/t/.gitignore +1 -1
- data/t/GNUmakefile +26 -16
- data/t/README +1 -1
- data/t/async-response-no-autochunk.ru +0 -1
- data/t/async-response.ru +0 -1
- data/t/cramp/rainsocket.ru +26 -0
- data/t/fork-sleep.ru +0 -1
- data/t/my-tap-lib.sh +3 -2
- data/t/simple-http_ActorSpawn.ru +9 -0
- data/t/t0009-broken-app.sh +1 -1
- data/t/t0009.ru +0 -1
- data/t/t0011-close-on-exec-set.sh +1 -1
- data/t/t0015-working_directory.sh +56 -0
- data/t/t0016-onenine-encoding-is-tricky.sh +28 -0
- data/t/t0016.rb +15 -0
- data/t/t0020-large-sendfile-response.sh +141 -0
- data/t/t0300-async_sinatra.sh +0 -6
- data/t/t0501-cramp-rainsocket.sh +38 -0
- data/t/t9001-sendfile-to-path.sh +5 -4
- data/t/t9002-server-token.sh +37 -0
- data/t/t9002.ru +4 -0
- data/t/test-lib.sh +1 -1
- data/t/test_isolate.rb +14 -11
- metadata +87 -18
data/lib/rainbows.rb
CHANGED
@@ -1,6 +1,10 @@
|
|
1
1
|
# -*- encoding: binary -*-
|
2
2
|
require 'unicorn'
|
3
|
+
# the value passed to TCP_DEFER_ACCEPT actually matters in Linux 2.6.32+
|
4
|
+
Unicorn::SocketHelper::DEFAULTS[:tcp_defer_accept] = 60
|
5
|
+
|
3
6
|
require 'rainbows/error'
|
7
|
+
require 'rainbows/configurator'
|
4
8
|
require 'fcntl'
|
5
9
|
|
6
10
|
module Rainbows
|
@@ -8,6 +12,7 @@ module Rainbows
|
|
8
12
|
# global vars because class/instance variables are confusing me :<
|
9
13
|
# this struct is only accessed inside workers and thus private to each
|
10
14
|
# G.cur may not be used in the network concurrency model
|
15
|
+
# :stopdoc:
|
11
16
|
class State < Struct.new(:alive,:m,:cur,:kato,:server,:tmp,:expire)
|
12
17
|
def tick
|
13
18
|
tmp.chmod(self.m = m == 0 ? 1 : 0)
|
@@ -22,14 +27,13 @@ module Rainbows
|
|
22
27
|
false
|
23
28
|
end
|
24
29
|
end
|
25
|
-
# :stopdoc:
|
26
30
|
G = State.new(true, 0, 0, 5)
|
27
31
|
O = {}
|
28
32
|
# :startdoc:
|
29
33
|
|
30
34
|
require 'rainbows/const'
|
31
35
|
require 'rainbows/http_server'
|
32
|
-
require 'rainbows/
|
36
|
+
require 'rainbows/response'
|
33
37
|
require 'rainbows/base'
|
34
38
|
require 'rainbows/tee_input'
|
35
39
|
autoload :Sendfile, 'rainbows/sendfile'
|
@@ -60,12 +64,12 @@ module Rainbows
|
|
60
64
|
|
61
65
|
# runs the Rainbows! HttpServer with +app+ and +options+ and does
|
62
66
|
# not return until the server has exited.
|
63
|
-
def run(app, options = {})
|
67
|
+
def run(app, options = {}) # :nodoc:
|
64
68
|
HttpServer.new(app, options).start.join
|
65
69
|
end
|
66
70
|
|
67
71
|
# returns nil if accept fails
|
68
|
-
def sync_accept(sock)
|
72
|
+
def sync_accept(sock) # :nodoc:
|
69
73
|
rv = sock.accept
|
70
74
|
rv.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
|
71
75
|
rv
|
@@ -73,7 +77,7 @@ module Rainbows
|
|
73
77
|
end
|
74
78
|
|
75
79
|
# returns nil if accept fails
|
76
|
-
def accept(sock)
|
80
|
+
def accept(sock) # :nodoc:
|
77
81
|
rv = sock.accept_nonblock
|
78
82
|
rv.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC)
|
79
83
|
rv
|
@@ -83,50 +87,18 @@ module Rainbows
|
|
83
87
|
# returns a string representing the address of the given client +io+
|
84
88
|
# For local UNIX domain sockets, this will return a string referred
|
85
89
|
# to by the (non-frozen) Unicorn::HttpRequest::LOCALHOST constant.
|
86
|
-
def addr(io)
|
90
|
+
def addr(io) # :nodoc:
|
87
91
|
io.respond_to?(:peeraddr) ?
|
88
|
-
io.peeraddr
|
92
|
+
io.peeraddr[-1] : Unicorn::HttpRequest::LOCALHOST
|
89
93
|
end
|
90
94
|
|
95
|
+
# :stopdoc:
|
91
96
|
# the default max body size is 1 megabyte (1024 * 1024 bytes)
|
92
97
|
@@max_bytes = 1024 * 1024
|
93
98
|
|
94
99
|
def max_bytes; @@max_bytes; end
|
95
100
|
def max_bytes=(nr); @@max_bytes = nr; end
|
96
|
-
|
97
|
-
|
98
|
-
# configures \Rainbows! with a given concurrency model to +use+ and
|
99
|
-
# a +worker_connections+ upper-bound. This method may be called
|
100
|
-
# inside a Unicorn/Rainbows configuration file:
|
101
|
-
#
|
102
|
-
# Rainbows! do
|
103
|
-
# use :Revactor # this may also be :ThreadSpawn or :ThreadPool
|
104
|
-
# worker_connections 400
|
105
|
-
# keepalive_timeout 0 # zero disables keepalives entirely
|
106
|
-
# client_max_body_size 5*1024*1024 # 5 megabytes
|
107
|
-
# end
|
108
|
-
#
|
109
|
-
# # the rest of the Unicorn configuration
|
110
|
-
# worker_processes 8
|
111
|
-
#
|
112
|
-
# See the documentation for the respective Revactor, ThreadSpawn,
|
113
|
-
# and ThreadPool classes for descriptions and recommendations for
|
114
|
-
# each of them. The total number of clients we're able to serve is
|
115
|
-
# +worker_processes+ * +worker_connections+, so in the above example
|
116
|
-
# we can serve 8 * 400 = 3200 clients concurrently.
|
117
|
-
#
|
118
|
-
# The default is +keepalive_timeout+ is 5 seconds, which should be
|
119
|
-
# enough under most conditions for browsers to render the page and
|
120
|
-
# start retrieving extra elements for. Increasing this beyond 5
|
121
|
-
# seconds is not recommended. Zero disables keepalive entirely
|
122
|
-
# (but pipelining fully-formed requests is still works).
|
123
|
-
#
|
124
|
-
# The default +client_max_body_size+ is 1 megabyte (1024 * 1024 bytes),
|
125
|
-
# setting this to +nil+ will disable body size checks and allow any
|
126
|
-
# size to be specified.
|
127
|
-
def Rainbows!(&block)
|
128
|
-
block_given? or raise ArgumentError, "Rainbows! requires a block"
|
129
|
-
HttpServer.setup(block)
|
101
|
+
# :startdoc:
|
130
102
|
end
|
131
103
|
|
132
104
|
# :stopdoc:
|
@@ -155,8 +127,7 @@ module Rainbows
|
|
155
127
|
end
|
156
128
|
# :startdoc:
|
157
129
|
autoload :Fiber, 'rainbows/fiber' # core class
|
158
|
-
|
130
|
+
autoload :ByteSlice, 'rainbows/byte_slice'
|
131
|
+
autoload :StreamFile, 'rainbows/stream_file'
|
132
|
+
autoload :HttpResponse, 'rainbows/http_response' # deprecated
|
159
133
|
end
|
160
|
-
|
161
|
-
# inject the Rainbows! method into Unicorn::Configurator
|
162
|
-
Unicorn::Configurator.class_eval { include Rainbows }
|
data/rainbows.gemspec
CHANGED
@@ -40,17 +40,17 @@ Gem::Specification.new do |s|
|
|
40
40
|
|
41
41
|
s.test_files = test_files
|
42
42
|
|
43
|
-
# we
|
44
|
-
|
45
|
-
# when exposed directly to untrusted clients.
|
46
|
-
s.add_dependency(%q<unicorn>, [">= 0.97.1", "< 2.0.0"])
|
47
|
-
s.add_development_dependency(%q<isolate>, "~> 2.0.2")
|
43
|
+
# we want a newer Rack for a valid HeaderHash#each
|
44
|
+
s.add_dependency(%q<rack>, ['~> 1.1'])
|
48
45
|
|
49
|
-
# Unicorn
|
50
|
-
#
|
46
|
+
# we need Unicorn for the HTTP parser and process management
|
47
|
+
# Unicorn 0.991.0 handles config.ru when started outside of
|
48
|
+
# the prespecified working_directory
|
49
|
+
s.add_dependency(%q<unicorn>, [">= 1.1.0", "< 2.0.0"])
|
50
|
+
s.add_development_dependency(%q<isolate>, "~> 2.1.0")
|
51
51
|
|
52
52
|
# optional runtime dependencies depending on configuration
|
53
|
-
# see
|
53
|
+
# see t/test_isolate.rb for the exact versions we've tested with
|
54
54
|
#
|
55
55
|
# Revactor >= 0.1.5 includes UNIX domain socket support
|
56
56
|
# s.add_dependency(%q<revactor>, [">= 0.1.5"])
|
data/t/.gitignore
CHANGED
data/t/GNUmakefile
CHANGED
@@ -4,6 +4,7 @@ all::
|
|
4
4
|
|
5
5
|
pid := $(shell echo $$PPID)
|
6
6
|
|
7
|
+
MRI = ruby
|
7
8
|
RUBY = ruby
|
8
9
|
rainbows_lib := $(shell cd ../lib && pwd)
|
9
10
|
-include ../local.mk
|
@@ -15,7 +16,8 @@ ifeq ($(RUBY_VERSION),)
|
|
15
16
|
$(error unable to detect RUBY_VERSION)
|
16
17
|
endif
|
17
18
|
|
18
|
-
|
19
|
+
RUBY_ENGINE := $(shell $(RUBY) -e 'puts((RUBY_ENGINE rescue "ruby"))')
|
20
|
+
export RUBY_VERSION RUBY_ENGINE
|
19
21
|
|
20
22
|
models += WriterThreadPool
|
21
23
|
models += WriterThreadSpawn
|
@@ -27,13 +29,19 @@ models += NeverBlock
|
|
27
29
|
models += RevThreadSpawn
|
28
30
|
models += RevThreadPool
|
29
31
|
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
|
32
|
+
ifeq ($(RUBY_ENGINE),ruby)
|
33
|
+
rp := )
|
34
|
+
ONENINE := $(shell case $(RUBY_VERSION) in 1.9.*$(rp) echo true;;esac)
|
35
|
+
ifeq ($(ONENINE),true)
|
36
|
+
models += Revactor
|
37
|
+
models += FiberSpawn
|
38
|
+
models += RevFiberSpawn
|
39
|
+
models += FiberPool
|
40
|
+
endif
|
41
|
+
endif
|
42
|
+
|
43
|
+
ifeq ($(RUBY_ENGINE),rbx)
|
44
|
+
models += ActorSpawn
|
37
45
|
endif
|
38
46
|
all_models := $(models) Base
|
39
47
|
|
@@ -60,7 +68,7 @@ $(all_models):
|
|
60
68
|
all:: $(T)
|
61
69
|
|
62
70
|
# can't rely on "set -o pipefail" since we don't require bash or ksh93 :<
|
63
|
-
t_pfx = trash/$@-$(RUBY_VERSION)
|
71
|
+
t_pfx = trash/$@-$(RUBY_ENGINE)-$(RUBY_VERSION)
|
64
72
|
TEST_OPTS =
|
65
73
|
# TRACER = strace -f -o $(t_pfx).strace -s 100000
|
66
74
|
# TRACER = /usr/bin/time -o $(t_pfx).time
|
@@ -73,11 +81,13 @@ ifdef V
|
|
73
81
|
endif
|
74
82
|
endif
|
75
83
|
|
76
|
-
|
77
|
-
|
84
|
+
bindir := $(CURDIR)/bin-$(RUBY_ENGINE)-$(RUBY_VERSION)
|
85
|
+
bin_rainbows := $(bindir)/rainbows
|
86
|
+
$(bin_rainbows): ruby_bin = $(shell which $(RUBY))
|
87
|
+
$(bin_rainbows): ../bin/rainbows
|
78
88
|
mkdir -p $(@D)
|
79
89
|
install -m 755 $^ $@.$(pid)
|
80
|
-
$(
|
90
|
+
$(MRI) -i -p -e '$$_.gsub!(%r{^#!.*$$},"#!$(ruby_bin)")' $@.$(pid)
|
81
91
|
mv $@.$(pid) $@
|
82
92
|
|
83
93
|
random_blob:
|
@@ -95,18 +105,18 @@ $(deps):
|
|
95
105
|
{ echo >&2 "E '$(dep_bin)' not found in PATH=$(PATH)"; exit 1; }
|
96
106
|
@mv $@.$(pid) $@
|
97
107
|
|
98
|
-
libs := tmp/isolate
|
108
|
+
libs := tmp/isolate/$(RUBY_ENGINE)-$(RUBY_VERSION)/.libs
|
99
109
|
$(libs): test_isolate.rb
|
100
110
|
mkdir -p $(@D)
|
101
111
|
$(RUBY) $< > $@+
|
102
112
|
mv $@+ $@
|
103
|
-
t_deps := $(libs) $(deps)
|
113
|
+
t_deps := $(libs) $(deps) $(bin_rainbows) trash/.gitignore
|
104
114
|
$(T): $(t_deps)
|
105
115
|
|
106
116
|
$(MODEL_T): export model = $(firstword $(subst ., ,$@))
|
107
117
|
$(MODEL_T): script = $(subst $(model).,,$@)
|
108
118
|
$(MODEL_T): export RUBY := $(RUBY)
|
109
|
-
$(MODEL_T): export PATH := $(
|
119
|
+
$(MODEL_T): export PATH := $(bindir):$(PATH)
|
110
120
|
$(MODEL_T): $(t_deps)
|
111
121
|
RUBYLIB=$(rainbows_lib):$$(cat $(libs)) \
|
112
122
|
$(TRACER) $(SHELL) $(SH_TEST_OPTS) $(script) $(TEST_OPTS)
|
@@ -116,6 +126,6 @@ trash/.gitignore:
|
|
116
126
|
echo '*' > $@
|
117
127
|
|
118
128
|
clean:
|
119
|
-
$(RM) -r trash/*.log trash/*.code
|
129
|
+
$(RM) -r trash/*.log trash/*.code $(bindir)
|
120
130
|
|
121
131
|
.PHONY: $(T) clean
|
data/t/README
CHANGED
@@ -12,7 +12,7 @@ easily portable to non-Ruby web servers.
|
|
12
12
|
== Requirements
|
13
13
|
|
14
14
|
* {Ruby 1.8 or 1.9}[http://www.ruby-lang.org/] (duh!)
|
15
|
-
* {isolate ~> 2.0
|
15
|
+
* {isolate ~> 2.1.0}[http://github.com/jbarnette/isolate] - for dependencies
|
16
16
|
* {GNU make}[http://www.gnu.org/software/make/]
|
17
17
|
* {socat}[http://www.dest-unreach.org/socat/]
|
18
18
|
* {curl >= 7.18.0}[http://curl.haxx.se/]
|
data/t/async-response.ru
CHANGED
@@ -0,0 +1,26 @@
|
|
1
|
+
# based on examples/rainsocket.ru git://github.com/lifo/cramp
|
2
|
+
# Rack::Lint does not like async + EM stuff, so disable it:
|
3
|
+
#\ -E deployment
|
4
|
+
require 'cramp/controller'
|
5
|
+
|
6
|
+
Cramp::Controller::Websocket.backend = :rainbows
|
7
|
+
|
8
|
+
class WelcomeController < Cramp::Controller::Websocket
|
9
|
+
periodic_timer :send_hello_world, :every => 2
|
10
|
+
on_data :received_data
|
11
|
+
|
12
|
+
def received_data(data)
|
13
|
+
if data =~ /fuck/
|
14
|
+
render "You cant say fuck in here"
|
15
|
+
finish
|
16
|
+
else
|
17
|
+
render "Got your #{data}"
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def send_hello_world
|
22
|
+
render "Hello from the Server!\n"
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
run WelcomeController
|
data/t/fork-sleep.ru
CHANGED
data/t/my-tap-lib.sh
CHANGED
@@ -188,9 +188,10 @@ then
|
|
188
188
|
|
189
189
|
(
|
190
190
|
# use a subshell so seds are not waitable
|
191
|
-
$SED -e 's/^/#: /' $t_stdout &
|
192
|
-
$SED -e 's/^/#! /' $t_stderr &
|
191
|
+
$SED -e 's/^/#: /' < $t_stdout &
|
192
|
+
$SED -e 's/^/#! /' < $t_stderr &
|
193
193
|
) &
|
194
|
+
wait
|
194
195
|
exec > $t_stdout 2> $t_stderr
|
195
196
|
else
|
196
197
|
exec > /dev/null 2> /dev/null
|
data/t/t0009-broken-app.sh
CHANGED
data/t/t0009.ru
CHANGED
@@ -0,0 +1,56 @@
|
|
1
|
+
#!/bin/sh
|
2
|
+
if test -n "$RBX_SKIP"
|
3
|
+
then
|
4
|
+
echo "$0 is broken under Rubinius for now"
|
5
|
+
exit 0
|
6
|
+
fi
|
7
|
+
. ./test-lib.sh
|
8
|
+
|
9
|
+
t_plan 4 "config.ru inside alt working_directory"
|
10
|
+
|
11
|
+
t_begin "setup and start" && {
|
12
|
+
rainbows_setup
|
13
|
+
rtmpfiles unicorn_config_tmp
|
14
|
+
rm -rf $t_pfx.app
|
15
|
+
mkdir $t_pfx.app
|
16
|
+
|
17
|
+
cat > $t_pfx.app/config.ru <<EOF
|
18
|
+
#\--daemonize --listen $listen
|
19
|
+
use Rack::ContentLength
|
20
|
+
use Rack::ContentType, "text/plain"
|
21
|
+
run lambda { |env| [ 200, {}, [ "#{\$master_ppid}\\n" ] ] }
|
22
|
+
EOF
|
23
|
+
# we have --host/--port in config.ru instead
|
24
|
+
grep -v ^listen $unicorn_config > $unicorn_config_tmp
|
25
|
+
|
26
|
+
# the whole point of this exercise
|
27
|
+
echo "working_directory '$t_pfx.app'" >> $unicorn_config_tmp
|
28
|
+
|
29
|
+
# allows ppid to be 1 in before_fork
|
30
|
+
echo "preload_app true" >> $unicorn_config_tmp
|
31
|
+
cat >> $unicorn_config_tmp <<\EOF
|
32
|
+
before_fork do |server,worker|
|
33
|
+
$master_ppid = Process.ppid # should be zero to detect daemonization
|
34
|
+
end
|
35
|
+
EOF
|
36
|
+
|
37
|
+
mv $unicorn_config_tmp $unicorn_config
|
38
|
+
|
39
|
+
# rely on --daemonize switch, no & or -D
|
40
|
+
rainbows -c $unicorn_config
|
41
|
+
rainbows_wait_start
|
42
|
+
}
|
43
|
+
|
44
|
+
t_begin "hit with curl" && {
|
45
|
+
body=$(curl -sSf http://$listen/)
|
46
|
+
}
|
47
|
+
|
48
|
+
t_begin "killing succeeds" && {
|
49
|
+
kill $rainbows_pid
|
50
|
+
}
|
51
|
+
|
52
|
+
t_begin "response body ppid == 1 (daemonized)" && {
|
53
|
+
test "$body" -eq 1
|
54
|
+
}
|
55
|
+
|
56
|
+
t_done
|
@@ -0,0 +1,28 @@
|
|
1
|
+
#!/bin/sh
|
2
|
+
. ./test-lib.sh
|
3
|
+
t_plan 4 "proper handling of onenine encoding for $model"
|
4
|
+
|
5
|
+
t_begin "setup and startup" && {
|
6
|
+
rainbows_setup $model
|
7
|
+
rainbows -D ./t0016.rb -c $unicorn_config
|
8
|
+
rainbows_wait_start
|
9
|
+
expect_sha1=8ff79d8115f9fe38d18be858c66aa08a1cc27a66
|
10
|
+
}
|
11
|
+
|
12
|
+
t_begin "response matches expected" && {
|
13
|
+
rm -f $ok
|
14
|
+
(
|
15
|
+
curl -sSf http://$listen/ && echo ok > $ok
|
16
|
+
) | rsha1 > $tmp
|
17
|
+
test x$expect_sha1 = x"$(cat $tmp)"
|
18
|
+
}
|
19
|
+
|
20
|
+
t_begin "shutdown server" && {
|
21
|
+
kill -QUIT $rainbows_pid
|
22
|
+
}
|
23
|
+
|
24
|
+
dbgcat r_err
|
25
|
+
|
26
|
+
t_begin "check stderr" && check_stderr
|
27
|
+
|
28
|
+
t_done
|
data/t/t0016.rb
ADDED
@@ -0,0 +1,15 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
module T0016
|
3
|
+
CHUNK = '©' * 1024 * 1024
|
4
|
+
BODY = (1..50).map { CHUNK }
|
5
|
+
HEADER = {
|
6
|
+
# BODY.inject(0) { |m,c| m += c.bytesize }.to_s,
|
7
|
+
'Content-Length' => '104857600',
|
8
|
+
'Content-Type' => 'text/plain',
|
9
|
+
}
|
10
|
+
|
11
|
+
def self.call(env)
|
12
|
+
[ 200, HEADER, BODY ]
|
13
|
+
end
|
14
|
+
end
|
15
|
+
$0 == __FILE__ and T0016::BODY.each { |x| $stdout.syswrite(x) }
|
@@ -0,0 +1,141 @@
|
|
1
|
+
#!/bin/sh
|
2
|
+
. ./test-lib.sh
|
3
|
+
test -r random_blob || die "random_blob required, run with 'make $0'"
|
4
|
+
case $RUBY_ENGINE in
|
5
|
+
ruby) ;;
|
6
|
+
*)
|
7
|
+
t_info "skipping $T since it can't load the sendfile gem, yet"
|
8
|
+
exit 0
|
9
|
+
;;
|
10
|
+
esac
|
11
|
+
|
12
|
+
t_plan 12 "large sendfile response for $model"
|
13
|
+
|
14
|
+
t_begin "setup and startup" && {
|
15
|
+
rtmpfiles curl_out a b c slow_a slow_b
|
16
|
+
rainbows_setup $model
|
17
|
+
echo 'require "sendfile"' >> $unicorn_config
|
18
|
+
echo 'def (::IO).copy_stream(*x); abort "NO"; end' >> $unicorn_config
|
19
|
+
|
20
|
+
# can't load Rack::Lint here since it clobbers body#to_path
|
21
|
+
rainbows -E none -D large-file-response.ru -c $unicorn_config
|
22
|
+
rainbows_wait_start
|
23
|
+
}
|
24
|
+
|
25
|
+
t_begin "read random blob sha1" && {
|
26
|
+
random_blob_sha1=$(rsha1 < random_blob)
|
27
|
+
three_sha1=$(cat random_blob random_blob random_blob | rsha1)
|
28
|
+
}
|
29
|
+
|
30
|
+
t_begin "send keepalive HTTP/1.1 requests in parallel" && {
|
31
|
+
for i in $a $b $c $slow_a $slow_b
|
32
|
+
do
|
33
|
+
curl -sSf http://$listen/random_blob \
|
34
|
+
http://$listen/random_blob \
|
35
|
+
http://$listen/random_blob | rsha1 > $i &
|
36
|
+
done
|
37
|
+
wait
|
38
|
+
for i in $a $b $c $slow_a $slow_b
|
39
|
+
do
|
40
|
+
test x$(cat $i) = x$three_sha1
|
41
|
+
done
|
42
|
+
}
|
43
|
+
|
44
|
+
t_begin "send a batch of abortive HTTP/1.1 requests in parallel" && {
|
45
|
+
for i in $a $b $c $slow_a $slow_b
|
46
|
+
do
|
47
|
+
rm -f $i
|
48
|
+
(
|
49
|
+
curl -sSf --max-time 5 --limit-rate 1K \
|
50
|
+
http://$listen/random_blob >/dev/null || echo ok > $i
|
51
|
+
) &
|
52
|
+
done
|
53
|
+
wait
|
54
|
+
}
|
55
|
+
|
56
|
+
t_begin "all requests timed out" && {
|
57
|
+
for i in $a $b $c $slow_a $slow_b
|
58
|
+
do
|
59
|
+
test x$(cat $i) = xok
|
60
|
+
done
|
61
|
+
}
|
62
|
+
|
63
|
+
s='$NF ~ /worker_connections=[0-9]+/{gsub(/[^0-9]/,"",$3); print $3; exit}'
|
64
|
+
t_begin "check proc to ensure file is closed properly (Linux only)" && {
|
65
|
+
worker_pid=$(awk "$s" < $r_err)
|
66
|
+
test -n "$worker_pid"
|
67
|
+
if test -d /proc/$worker_pid/fd
|
68
|
+
then
|
69
|
+
if ls -l /proc/$worker_pid/fd | grep random_blob
|
70
|
+
then
|
71
|
+
t_info "random_blob file is open ($model)"
|
72
|
+
fi
|
73
|
+
else
|
74
|
+
t_info "/proc/$worker_pid/fd not found"
|
75
|
+
fi
|
76
|
+
}
|
77
|
+
|
78
|
+
t_begin "send a bunch of HTTP/1.1 requests in parallel" && {
|
79
|
+
(
|
80
|
+
curl -sSf --limit-rate 1M http://$listen/random_blob | \
|
81
|
+
rsha1 > $slow_a
|
82
|
+
) &
|
83
|
+
(
|
84
|
+
curl -sSf --limit-rate 750K http://$listen/random_blob | \
|
85
|
+
rsha1 > $slow_b
|
86
|
+
) &
|
87
|
+
for i in $a $b $c
|
88
|
+
do
|
89
|
+
(
|
90
|
+
curl -sSf http://$listen/random_blob | rsha1 > $i
|
91
|
+
) &
|
92
|
+
done
|
93
|
+
wait
|
94
|
+
for i in $a $b $c $slow_a $slow_b
|
95
|
+
do
|
96
|
+
test x$(cat $i) = x$random_blob_sha1
|
97
|
+
done
|
98
|
+
}
|
99
|
+
|
100
|
+
# this was a problem during development
|
101
|
+
t_begin "HTTP/1.0 test" && {
|
102
|
+
sha1=$( (curl -0 -sSf http://$listen/random_blob &&
|
103
|
+
echo ok >$ok) | rsha1)
|
104
|
+
test $sha1 = $random_blob_sha1
|
105
|
+
test xok = x$(cat $ok)
|
106
|
+
}
|
107
|
+
|
108
|
+
t_begin "HTTP/0.9 test" && {
|
109
|
+
(
|
110
|
+
printf 'GET /random_blob\r\n'
|
111
|
+
rsha1 < $fifo > $tmp &
|
112
|
+
wait
|
113
|
+
echo ok > $ok
|
114
|
+
) | socat - TCP:$listen > $fifo
|
115
|
+
test $(cat $tmp) = $random_blob_sha1
|
116
|
+
test xok = x$(cat $ok)
|
117
|
+
}
|
118
|
+
|
119
|
+
t_begin "check proc to ensure file is closed properly (Linux only)" && {
|
120
|
+
worker_pid=$(awk "$s" < $r_err)
|
121
|
+
test -n "$worker_pid"
|
122
|
+
if test -d /proc/$worker_pid/fd
|
123
|
+
then
|
124
|
+
if ls -l /proc/$worker_pid/fd | grep random_blob
|
125
|
+
then
|
126
|
+
t_info "random_blob file is open ($model)"
|
127
|
+
fi
|
128
|
+
else
|
129
|
+
t_info "/proc/$worker_pid/fd not found"
|
130
|
+
fi
|
131
|
+
}
|
132
|
+
|
133
|
+
t_begin "shutdown server" && {
|
134
|
+
kill -QUIT $rainbows_pid
|
135
|
+
}
|
136
|
+
|
137
|
+
dbgcat r_err
|
138
|
+
|
139
|
+
t_begin "check stderr" && check_stderr
|
140
|
+
|
141
|
+
t_done
|
data/t/t0300-async_sinatra.sh
CHANGED
@@ -0,0 +1,38 @@
|
|
1
|
+
#!/bin/sh
|
2
|
+
. ./test-lib.sh
|
3
|
+
case $model in
|
4
|
+
EventMachine) ;;
|
5
|
+
*)
|
6
|
+
t_info "skipping $T since it's not compatible with $model"
|
7
|
+
exit 0
|
8
|
+
;;
|
9
|
+
esac
|
10
|
+
require_check cramp Cramp::VERSION
|
11
|
+
|
12
|
+
t_plan 4 "WebSocket monkey patch validity test for Cramp"
|
13
|
+
|
14
|
+
CONFIG_RU=cramp/rainsocket.ru
|
15
|
+
|
16
|
+
t_begin "setup and start" && {
|
17
|
+
rainbows_setup
|
18
|
+
rtmpfiles curl_err
|
19
|
+
|
20
|
+
# Like the rest of the EM/async stuff, it's not Rack::Lint compatible
|
21
|
+
rainbows -E deployment -D $CONFIG_RU -c $unicorn_config
|
22
|
+
rainbows_wait_start
|
23
|
+
}
|
24
|
+
|
25
|
+
t_begin "wait for server to say hello to us" && {
|
26
|
+
ok=$((curl --no-buffer -sS http://$listen/ || :) | \
|
27
|
+
awk '/Hello from the Server/ { print "ok"; exit 0 }')
|
28
|
+
|
29
|
+
test x"$ok" = xok
|
30
|
+
}
|
31
|
+
|
32
|
+
t_begin "termination signal sent" && {
|
33
|
+
kill $rainbows_pid
|
34
|
+
}
|
35
|
+
|
36
|
+
t_begin "no errors in stderr" && check_stderr
|
37
|
+
|
38
|
+
t_done
|