rainbows 0.93.0 → 0.94.0

Sign up to get free protection for your applications and to get access to all the features.
data/.document CHANGED
@@ -11,3 +11,4 @@ TODO
11
11
  TUNING
12
12
  vs_Unicorn
13
13
  Summary
14
+ Test_Suite
data/.gitignore CHANGED
@@ -16,4 +16,3 @@ pkg/
16
16
  /.manifest
17
17
  /GIT-VERSION-FILE
18
18
  /man
19
- /tmp
data/GIT-VERSION-GEN CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/bin/sh
2
2
 
3
3
  GVF=GIT-VERSION-FILE
4
- DEF_VER=v0.93.0.GIT
4
+ DEF_VER=v0.94.0.GIT
5
5
 
6
6
  LF='
7
7
  '
data/GNUmakefile CHANGED
@@ -2,8 +2,8 @@
2
2
  all::
3
3
  RUBY = ruby
4
4
  RAKE = rake
5
+ RSYNC = rsync
5
6
  GIT_URL = git://git.bogomips.org/rainbows.git
6
- ISOLATE_CONFIG = config/isolate.rb
7
7
 
8
8
  GIT-VERSION-FILE: .FORCE-GIT-VERSION-FILE
9
9
  @./GIT-VERSION-GEN
@@ -16,12 +16,6 @@ ifeq ($(RUBY_VERSION),)
16
16
  RUBY_VERSION := $(shell $(RUBY) -e 'puts RUBY_VERSION')
17
17
  endif
18
18
 
19
- # rake takes forever to start
20
- isolate: tmp/isolate/ruby-$(RUBY_VERSION)/.isolate
21
- tmp/isolate/ruby-$(RUBY_VERSION)/.isolate: $(ISOLATE_CONFIG)
22
- ISOLATE_CONFIG=$(ISOLATE_CONFIG) $(RAKE) isolate
23
- > $@
24
-
25
19
  base_bins := rainbows
26
20
  bins := $(addprefix bin/, $(base_bins))
27
21
  man1_rdoc := $(addsuffix _1, $(base_bins))
@@ -112,6 +106,19 @@ doc: .document NEWS ChangeLog
112
106
  cat Documentation/comparison.css >> doc/rdoc.css
113
107
  $(RM) $(man1_rdoc)
114
108
 
109
+ # publishes docs to http://rainbows.rubyforge.org
110
+ publish_doc: NEWS
111
+ -git set-file-times
112
+ $(RM) -r doc ChangeLog NEWS
113
+ $(MAKE) doc LOG_VERSION=$(shell git tag -l | tail -1)
114
+ awk 'BEGIN{RS="=== ";ORS=""}NR==2{sub(/\n$$/,"");print RS""$$0 }' \
115
+ < NEWS > doc/LATEST
116
+ -find doc/images doc/js -type f | \
117
+ TZ=UTC xargs touch -d '1970-01-01 00:00:01' doc/rdoc.css
118
+ chmod 644 $$(find doc -type f)
119
+ $(RSYNC) -av doc/ rubyforge.org:/var/www/gforge-projects/rainbows/
120
+ git ls-files | xargs touch
121
+
115
122
  ifneq ($(VERSION),)
116
123
  rfproject := rainbows
117
124
  rfpackage := rainbows
@@ -172,6 +179,8 @@ release: verify package $(release_notes) $(release_changes)
172
179
  # in case of gem downloads from RubyForge releases page
173
180
  -rubyforge add_file \
174
181
  $(rfproject) $(rfpackage) $(VERSION) $(pkggem)
182
+ $(RAKE) raa_update VERSION=$(VERSION)
183
+ $(RAKE) fm_update VERSION=$(VERSION)
175
184
  else
176
185
  gem install-gem: GIT-VERSION-FILE
177
186
  $(MAKE) $@ VERSION=$(GIT_VERSION)
data/Rakefile CHANGED
@@ -183,24 +183,3 @@ task :fm_update do
183
183
  p http.post(uri.path, req, {'Content-Type'=>'application/json'})
184
184
  end
185
185
  end
186
-
187
- desc 'isolate gems for development'
188
- task :isolate do
189
- require 'isolate'
190
- require 'rbconfig'
191
-
192
- Isolate.now! :file => ENV['ISOLATE_CONFIG'], :system => false
193
-
194
- # for Ruby 1.8 isolate uses "1.8" instead of "1.8.7" for paths,
195
- # but we'll still try to support 1.8.6 for now even though isolate
196
- # does not.
197
- if Gem.ruby_engine == "ruby" &&
198
- RbConfig::CONFIG["ruby_version"] != RUBY_VERSION
199
- require 'fileutils'
200
- Dir.chdir('tmp/isolate') do
201
- FileUtils.rm_rf("ruby-#{RUBY_VERSION}")
202
- File.symlink "ruby-#{RbConfig::CONFIG["ruby_version"]}",
203
- "ruby-#{RUBY_VERSION}"
204
- end
205
- end
206
- end
data/Test_Suite ADDED
@@ -0,0 +1,63 @@
1
+ = \Rainbows! test suite - YES OUR TEST SUITE IS CONCURRENT!
2
+
3
+ These are all integration tests that start the server on random, unused
4
+ TCP ports or Unix domain sockets. They're all designed to run
5
+ concurrently with other tests to minimize test time, but tests may be
6
+ run independently as well.
7
+
8
+ We write our tests primarily in Bourne shell because that's what we're
9
+ comfortable writing integration tests with. This test suite is also
10
+ easily portable to non-Ruby web servers.
11
+
12
+ == Requirements
13
+
14
+ * {Ruby 1.8 or 1.9}[http://www.ruby-lang.org/] (duh!)
15
+ * {isolate ~> 2.0.2}[http://github.com/jbarnette/isolate] - for dependencies
16
+ * {GNU make}[http://www.gnu.org/software/make/]
17
+ * {socat}[http://www.dest-unreach.org/socat/]
18
+ * {curl >= 7.18.0}[http://curl.haxx.se/]
19
+ * standard UNIX shell utilities (Bourne sh, awk, sed, grep, ...)
20
+
21
+ We do not use bashisms or any non-portable, non-POSIX constructs
22
+ in our shell code. We use the "pipefail" option if available and
23
+ mainly test with {ksh}[http://kornshell.com/], but occasionally
24
+ with {dash}[http://gondor.apana.org.au/~herbert/dash/] and
25
+ {bash}[http://www.gnu.org/software/bash/], too.
26
+
27
+ == Running Tests
28
+
29
+ *BSD users: use "gmake" instead of "make"
30
+
31
+ To run the entire test suite with 8 tests running at once:
32
+
33
+ make -j8
34
+
35
+ To run one individual test for all concurrency models:
36
+
37
+ make t0000-simple-http.sh
38
+
39
+ To run one individual test for one concurrency model:
40
+
41
+ make Revactor.t0000-simple-http.sh
42
+
43
+ To run all tests for one concurrency model:
44
+
45
+ make EventMachine
46
+
47
+ You may also increase verbosity by setting the "V" variable for
48
+ GNU make. To disable trapping of stdout/stderr:
49
+
50
+ make V=1
51
+
52
+ To enable the "set -x" option in shell scripts to trace execution
53
+
54
+ make V=2
55
+
56
+ == Performance
57
+
58
+ Some of the tests are rather I/O intensive due to the rewindability
59
+ requirement of "rack.input" in the Rack specification and the somewhat
60
+ complicated (but awesome!) nature of the TeeInput class leading us to
61
+ test it very heavily. If you have lots of RAM and a large tmpfs
62
+ partition, it is advisable to set your TMPDIR and also make the t/trash/
63
+ directory a symlink to a directory inside in your TMPDIR.
data/lib/rainbows.rb CHANGED
@@ -32,6 +32,7 @@ module Rainbows
32
32
  require 'rainbows/http_response'
33
33
  require 'rainbows/base'
34
34
  require 'rainbows/tee_input'
35
+ autoload :Sendfile, 'rainbows/sendfile'
35
36
  autoload :AppPool, 'rainbows/app_pool'
36
37
  autoload :DevFdResponse, 'rainbows/dev_fd_response'
37
38
  autoload :MaxBody, 'rainbows/max_body'
@@ -3,7 +3,7 @@
3
3
  module Rainbows
4
4
 
5
5
  module Const
6
- RAINBOWS_VERSION = '0.93.0'
6
+ RAINBOWS_VERSION = '0.94.0'
7
7
 
8
8
  include Unicorn::Const
9
9
 
@@ -0,0 +1,100 @@
1
+ # -*- encoding: binary -*-
2
+ module Rainbows
3
+
4
+ # This middleware handles X-\Sendfile headers generated by applications
5
+ # or middlewares down the stack. It should be placed at the top
6
+ # (outermost layer) of the middleware stack to avoid having its
7
+ # +to_path+ method clobbered by another middleware.
8
+ #
9
+ # This converts X-\Sendfile responses to bodies which respond to the
10
+ # +to_path+ method which allows certain concurrency models to serve
11
+ # efficiently using sendfile() or similar. With multithreaded models
12
+ # under Ruby 1.9, IO.copy_stream will be used.
13
+ #
14
+ # This middleware is the opposite of Rack::Contrib::Sendfile as it
15
+ # reverses the effect of Rack::Contrib::Sendfile. Unlike many Ruby
16
+ # web servers, some configurations of \Rainbows! are capable of
17
+ # serving static files efficiently.
18
+ #
19
+ # === Compatibility (via IO.copy_stream in Ruby 1.9):
20
+ # * ThreadSpawn
21
+ # * ThreadPool
22
+ # * WriterThreadPool
23
+ # * WriterThreadSpawn
24
+ #
25
+ # === Compatibility (Ruby 1.8 and 1.9)
26
+ # * EventMachine
27
+ # * NeverBlock (using EventMachine)
28
+ #
29
+ # DO NOT use this middleware if you're proxying to \Rainbows! with a
30
+ # server that understands X-\Sendfile (e.g. Apache, Lighttpd) natively.
31
+ #
32
+ # This does NOT understand X-Accel-Redirect headers intended for nginx.
33
+ # X-Accel-Redirect requires the application to be highly coupled with
34
+ # the corresponding nginx configuration, and is thus too complicated to
35
+ # be worth supporting.
36
+ #
37
+ # Example config.ru:
38
+ #
39
+ # use Rainbows::Sendfile
40
+ # run lambda { |env|
41
+ # path = "#{Dir.pwd}/random_blob"
42
+ # [ 200,
43
+ # {
44
+ # 'X-Sendfile' => path,
45
+ # 'Content-Type' => 'application/octet-stream'
46
+ # },
47
+ # []
48
+ # ]
49
+ # }
50
+
51
+ class Sendfile < Struct.new(:app)
52
+
53
+ # :stopdoc:
54
+ HH = Rack::Utils::HeaderHash
55
+ # :startdoc:
56
+
57
+ # Body wrapper, this allows us to fall back gracefully to
58
+ # +each+ in case a given concurrency model does not optimize
59
+ # +to_path+ calls.
60
+ class Body < Struct.new(:to_io)
61
+
62
+ def initialize(path, headers)
63
+ # Rainbows! will try #to_io if #to_path exists to avoid unnecessary
64
+ # open() calls.
65
+ self.to_io = File.open(path, 'rb')
66
+
67
+ unless headers['Content-Length']
68
+ stat = to_io.stat
69
+ headers['Content-Length'] = stat.size.to_s if stat.file?
70
+ end
71
+ end
72
+
73
+ def to_path
74
+ to_io.path
75
+ end
76
+
77
+ # fallback in case our +to_path+ doesn't get handled for whatever reason
78
+ def each(&block)
79
+ buf = ''
80
+ while to_io.read(0x4000, buf)
81
+ yield buf
82
+ end
83
+ end
84
+
85
+ def close
86
+ to_io.close
87
+ end
88
+ end
89
+
90
+ def call(env)
91
+ status, headers, body = app.call(env)
92
+ headers = HH.new(headers)
93
+ if path = headers.delete('X-Sendfile')
94
+ body = Body.new(path, headers) unless body.respond_to?(:to_path)
95
+ end
96
+ [ status, headers, body ]
97
+ end
98
+ end
99
+
100
+ end
@@ -46,13 +46,8 @@ module Rainbows
46
46
  end
47
47
  end
48
48
 
49
- alias base_write_body write_body
50
- if IO.respond_to?(:copy_stream)
51
- undef_method :write_body
52
-
53
- def write_body(qclient, body)
54
- qclient.q << [ qclient.to_io, :body, body ]
55
- end
49
+ def write_body(qclient, body)
50
+ qclient.q << [ qclient.to_io, :body, body ]
56
51
  end
57
52
 
58
53
  @@nr = 0
@@ -71,7 +66,7 @@ module Rainbows
71
66
  begin
72
67
  io, arg1, arg2 = response
73
68
  case arg1
74
- when :body then base_write_body(io, arg2)
69
+ when :body then Base.write_body(io, arg2)
75
70
  when :close then io.close unless io.closed?
76
71
  else
77
72
  io.write(arg1)
@@ -88,12 +88,8 @@ module Rainbows
88
88
  end
89
89
  end
90
90
 
91
- if IO.respond_to?(:copy_stream)
92
- undef_method :write_body
93
-
94
- def write_body(my_sock, body)
95
- my_sock.write_body(body)
96
- end
91
+ def write_body(my_sock, body)
92
+ my_sock.write_body(body)
97
93
  end
98
94
 
99
95
  def process_client(client)
data/local.mk.sample CHANGED
@@ -4,37 +4,32 @@
4
4
  #
5
5
  # This is depends on a bunch of GNU-isms from bash, sed, touch.
6
6
 
7
- RSYNC = rsync
8
7
  DLEXT := so
9
8
 
9
+ # if you have a decent amount of RAM, setting TMPDIR to be on tmpfs
10
+ # can significantly improve performance because uploads take a lot
11
+ # of disk I/O due to the rewindability requirement in Rack.
12
+ # TMPDIR := /dev/shm
13
+ # export TMPDIR
14
+
10
15
  # Avoid loading rubygems to speed up tests because gmake is
11
16
  # fork+exec heavy with Ruby.
12
17
  prefix = $(HOME)
13
18
 
14
- ifeq ($(r19),)
15
- RUBY := $(prefix)/bin/ruby
19
+ ifeq ($(r192),)
20
+ ifeq ($(r19),)
21
+ RUBY := $(prefix)/bin/ruby
22
+ else
23
+ prefix := $(prefix)/ruby-1.9
24
+ export PATH := $(prefix)/bin:$(PATH)
25
+ RUBY := $(prefix)/bin/ruby --disable-gems
26
+ endif
16
27
  else
17
- prefix := $(prefix)/ruby-1.9
28
+ prefix := $(prefix)/ruby-1.9.2
18
29
  export PATH := $(prefix)/bin:$(PATH)
19
30
  RUBY := $(prefix)/bin/ruby --disable-gems
20
31
  endif
21
32
 
22
- ifndef NO_ISOLATE
23
- x := $(shell test -d t/ && \
24
- PATH=$(PATH) NO_ISOLATE=T $(MAKE) -s isolate RUBY:="$(RUBY)")
25
- endif
26
-
27
- RUBY_VERSION := $(shell $(RUBY) -e 'puts RUBY_VERSION')
28
-
29
- updir := $(shell git rev-parse --show-cdup)
30
- gem_paths := $(wildcard $(updir)tmp/isolate/ruby-$(RUBY_VERSION)/gems/*-*)
31
-
32
- ifdef gem_paths
33
- sp :=
34
- sp +=
35
- export RUBYLIB := $(subst $(sp),:,$(addsuffix /lib,$(gem_paths)))
36
- endif
37
-
38
33
  # pipefail is THE reason to use bash (v3+) or never revisions of ksh93
39
34
  # SHELL := /bin/bash -e -o pipefail
40
35
  SHELL := /bin/ksh93 -e -o pipefail
@@ -43,37 +38,10 @@ SHELL := /bin/ksh93 -e -o pipefail
43
38
  # TRACER = strace -f -o $(t_pfx).strace -s 100000
44
39
  TRACER = /usr/bin/time -v -o $(t_pfx).time
45
40
 
46
- full-test: test-18 test-19
41
+ full-test: test-18 test-191 test-192
47
42
  test-18:
48
43
  $(MAKE) test 2>&1 | sed -e 's!^!1.8 !'
49
- test-19:
50
- $(MAKE) test r19=T 2>&1 | sed -e 's!^!1.9 !'
51
-
52
- latest: NEWS
53
- @awk 'BEGIN{RS="=== ";ORS=""}NR==2{sub(/\n$$/,"");print RS""$$0 }' < $<
54
-
55
- # publishes docs to http://rainbows.rubyforge.org
56
- publish_doc:
57
- -git set-file-times
58
- $(RM) -r doc ChangeLog NEWS
59
- $(MAKE) doc LOG_VERSION=$(shell git tag -l | tail -1)
60
- $(MAKE) -s latest > doc/LATEST
61
- find doc/images doc/js -type f | \
62
- TZ=UTC xargs touch -d '1970-01-01 00:00:00' doc/rdoc.css
63
- $(MAKE) doc_gz
64
- chmod 644 $$(find doc -type f)
65
- $(RSYNC) -av doc/ rubyforge.org:/var/www/gforge-projects/rainbows/
66
- $(RSYNC) -av doc/ dcvr:/srv/rainbows/
67
- git ls-files | xargs touch
68
-
69
- # Create gzip variants of the same timestamp as the original so nginx
70
- # "gzip_static on" can serve the gzipped versions directly.
71
- doc_gz: docs = $(shell find doc -type f ! -regex '^.*\.\(gif\|jpg\|png\|gz\)$$')
72
- doc_gz:
73
- touch doc/NEWS.atom.xml -d "$$(awk 'NR==1{print $$4,$$5,$$6}' NEWS)"
74
- for i in $(docs); do \
75
- gzip --rsyncable -9 < $$i > $$i.gz; touch -r $$i $$i.gz; done
76
-
77
- # launches any of the following shells with RUBYLIB set
78
- irb sh bash ksh:
79
- $@
44
+ test-191:
45
+ $(MAKE) test r19=T 2>&1 | sed -e 's!^!1.9.1 !'
46
+ test-192:
47
+ $(MAKE) test r192=T 2>&1 | sed -e 's!^!1.9.2 !'
data/rainbows.gemspec CHANGED
@@ -44,6 +44,7 @@ Gem::Specification.new do |s|
44
44
  # The HTTP parser in Unicorn <= 0.97.0 was vulnerable to a remote DoS
45
45
  # when exposed directly to untrusted clients.
46
46
  s.add_dependency(%q<unicorn>, [">= 0.97.1", "< 2.0.0"])
47
+ s.add_development_dependency(%q<isolate>, "~> 2.0.2")
47
48
 
48
49
  # Unicorn already depends on Rack
49
50
  # s.add_dependency(%q<rack>)
data/t/.gitignore CHANGED
@@ -3,3 +3,4 @@
3
3
  /random_blob
4
4
  /.dep+*
5
5
  /trash
6
+ /tmp
data/t/GNUmakefile CHANGED
@@ -15,12 +15,7 @@ ifeq ($(RUBY_VERSION),)
15
15
  $(error unable to detect RUBY_VERSION)
16
16
  endif
17
17
 
18
- ifeq ($(RUBYLIB),)
19
- RUBYLIB := $(rainbows_lib)
20
- else
21
- RUBYLIB := $(rainbows_lib):$(RUBYLIB)
22
- endif
23
- export RUBYLIB RUBY_VERSION
18
+ export RUBY_VERSION
24
19
 
25
20
  models += WriterThreadPool
26
21
  models += WriterThreadSpawn
@@ -99,15 +94,22 @@ $(deps):
99
94
  @test -s $@.$(pid) || \
100
95
  { echo >&2 "E '$(dep_bin)' not found in PATH=$(PATH)"; exit 1; }
101
96
  @mv $@.$(pid) $@
102
- dep: $(deps)
97
+
98
+ libs := tmp/isolate/ruby-$(RUBY_VERSION)/.libs
99
+ $(libs): test_isolate.rb
100
+ mkdir -p $(@D)
101
+ $(RUBY) $< > $@+
102
+ mv $@+ $@
103
+ t_deps := $(libs) $(deps) test-bin-$(RUBY_VERSION)/rainbows trash/.gitignore
104
+ $(T): $(t_deps)
103
105
 
104
106
  $(MODEL_T): export model = $(firstword $(subst ., ,$@))
105
107
  $(MODEL_T): script = $(subst $(model).,,$@)
106
- $(MODEL_T): trash/.gitignore
107
108
  $(MODEL_T): export RUBY := $(RUBY)
108
109
  $(MODEL_T): export PATH := $(CURDIR)/test-bin-$(RUBY_VERSION):$(PATH)
109
- $(MODEL_T): test-bin-$(RUBY_VERSION)/rainbows dep
110
- $(TRACER) $(SHELL) $(SH_TEST_OPTS) $(script) $(TEST_OPTS)
110
+ $(MODEL_T): $(t_deps)
111
+ RUBYLIB=$(rainbows_lib):$$(cat $(libs)) \
112
+ $(TRACER) $(SHELL) $(SH_TEST_OPTS) $(script) $(TEST_OPTS)
111
113
 
112
114
  trash/.gitignore:
113
115
  mkdir -p $(@D)
data/t/README CHANGED
@@ -1,19 +1,21 @@
1
- = Rainbows! test suite
1
+ = \Rainbows! test suite - YES OUR TEST SUITE IS CONCURRENT!
2
2
 
3
3
  These are all integration tests that start the server on random, unused
4
4
  TCP ports or Unix domain sockets. They're all designed to run
5
5
  concurrently with other tests to minimize test time, but tests may be
6
6
  run independently as well.
7
7
 
8
- We write our tests in Bourne shell because that's what we're
9
- comfortable writing integration tests with.
8
+ We write our tests primarily in Bourne shell because that's what we're
9
+ comfortable writing integration tests with. This test suite is also
10
+ easily portable to non-Ruby web servers.
10
11
 
11
12
  == Requirements
12
13
 
13
14
  * {Ruby 1.8 or 1.9}[http://www.ruby-lang.org/] (duh!)
15
+ * {isolate ~> 2.0.2}[http://github.com/jbarnette/isolate] - for dependencies
14
16
  * {GNU make}[http://www.gnu.org/software/make/]
15
17
  * {socat}[http://www.dest-unreach.org/socat/]
16
- * {curl}[http://curl.haxx.se/]
18
+ * {curl >= 7.18.0}[http://curl.haxx.se/]
17
19
  * standard UNIX shell utilities (Bourne sh, awk, sed, grep, ...)
18
20
 
19
21
  We do not use bashisms or any non-portable, non-POSIX constructs
@@ -24,6 +26,8 @@ with {dash}[http://gondor.apana.org.au/~herbert/dash/] and
24
26
 
25
27
  == Running Tests
26
28
 
29
+ *BSD users: use "gmake" instead of "make"
30
+
27
31
  To run the entire test suite with 8 tests running at once:
28
32
 
29
33
  make -j8
@@ -36,6 +40,10 @@ To run one individual test for one concurrency model:
36
40
 
37
41
  make Revactor.t0000-simple-http.sh
38
42
 
43
+ To run all tests for one concurrency model:
44
+
45
+ make EventMachine
46
+
39
47
  You may also increase verbosity by setting the "V" variable for
40
48
  GNU make. To disable trapping of stdout/stderr:
41
49
 
@@ -44,3 +52,12 @@ GNU make. To disable trapping of stdout/stderr:
44
52
  To enable the "set -x" option in shell scripts to trace execution
45
53
 
46
54
  make V=2
55
+
56
+ == Performance
57
+
58
+ Some of the tests are rather I/O intensive due to the rewindability
59
+ requirement of "rack.input" in the Rack specification and the somewhat
60
+ complicated (but awesome!) nature of the TeeInput class leading us to
61
+ test it very heavily. If you have lots of RAM and a large tmpfs
62
+ partition, it is advisable to set your TMPDIR and also make the t/trash/
63
+ directory a symlink to a directory inside in your TMPDIR.
@@ -18,7 +18,8 @@ t_begin "setup and startup" && {
18
18
  rainbows_wait_start
19
19
  }
20
20
 
21
- t_begin "read random blob size" && {
21
+ t_begin "read random blob sha1 and size" && {
22
+ random_blob_sha1=$(rsha1 < random_blob)
22
23
  random_blob_size=$(wc -c < random_blob)
23
24
  }
24
25
 
@@ -32,18 +33,18 @@ t_begin "read current RSS" && {
32
33
  t_begin "send a series HTTP/1.1 requests sequentially" && {
33
34
  for i in a b c
34
35
  do
35
- size=$( (curl -sSfv http://$listen/random_blob &&
36
- echo ok >$ok) |wc -c)
37
- test $size -eq $random_blob_size
36
+ sha1=$( (curl -sSfv http://$listen/random_blob &&
37
+ echo ok >$ok) | rsha1)
38
+ test $sha1 = $random_blob_sha1
38
39
  test xok = x$(cat $ok)
39
40
  done
40
41
  }
41
42
 
42
43
  # this was a problem during development
43
44
  t_begin "HTTP/1.0 test" && {
44
- size=$( (curl -0 -sSfv http://$listen/random_blob &&
45
- echo ok >$ok) |wc -c)
46
- test $size -eq $random_blob_size
45
+ sha1=$( (curl -0 -sSfv http://$listen/random_blob &&
46
+ echo ok >$ok) | rsha1)
47
+ test $sha1 = $random_blob_sha1
47
48
  test xok = x$(cat $ok)
48
49
  }
49
50
 
@@ -54,7 +55,7 @@ t_begin "HTTP/0.9 test" && {
54
55
  wait
55
56
  echo ok > $ok
56
57
  ) | socat - TCP:$listen > $fifo
57
- test $(cat $tmp) = $(rsha1 < random_blob)
58
+ test $(cat $tmp) = $random_blob_sha1
58
59
  test xok = x$(cat $ok)
59
60
  }
60
61
 
@@ -1,5 +1,11 @@
1
1
  #!/bin/sh
2
2
  . ./test-lib.sh
3
+ case $RUBY_VERSION in
4
+ 1.9.2)
5
+ t_info "RUBY_VERSION=$RUBY_VERSION not supported with async_sinatra"
6
+ exit 0
7
+ ;;
8
+ esac
3
9
 
4
10
  # n - number of seconds to sleep
5
11
  n=10
@@ -0,0 +1,45 @@
1
+ #!/bin/sh
2
+ . ./test-lib.sh
3
+
4
+ t_plan 7 "Sendfile middleware test for $model"
5
+
6
+ t_begin "configure and start" && {
7
+ rtmpfiles curl_out curl_err
8
+ rainbows_setup
9
+
10
+ # do not allow default middleware to be loaded since it may
11
+ # kill body#to_path
12
+ rainbows -E none -D t9001.ru -c $unicorn_config
13
+ rainbows_wait_start
14
+ }
15
+
16
+ t_begin "hit with curl" && {
17
+ curl -sSfv http://$listen/ > $curl_out 2> $curl_err
18
+ }
19
+
20
+ t_begin "kill server" && {
21
+ kill $rainbows_pid
22
+ }
23
+
24
+ t_begin "file matches source" && {
25
+ cmp $curl_out random_blob
26
+ }
27
+
28
+ t_begin "no errors in Rainbows! stderr" && {
29
+ check_stderr
30
+ }
31
+
32
+ t_begin "X-Sendfile does not show up in headers" && {
33
+ dbgcat curl_err
34
+ if grep -i x-sendfile $curl_err
35
+ then
36
+ die "X-Sendfile did show up!"
37
+ fi
38
+ }
39
+
40
+ t_begin "Content-Length is set correctly in headers" && {
41
+ expect=$(wc -c < random_blob)
42
+ grep "^< Content-Length: $expect" $curl_err
43
+ }
44
+
45
+ t_done
data/t/t9001.ru ADDED
@@ -0,0 +1,11 @@
1
+ use Rainbows::Sendfile
2
+ run lambda { |env|
3
+ path = "#{Dir.pwd}/random_blob"
4
+ [ 200,
5
+ {
6
+ 'X-Sendfile' => path,
7
+ 'Content-Type' => 'application/octet-stream'
8
+ },
9
+ []
10
+ ]
11
+ }
data/t/test-lib.sh CHANGED
@@ -3,6 +3,12 @@
3
3
  . ./my-tap-lib.sh
4
4
 
5
5
  set +u
6
+
7
+ # sometimes we rely on http_proxy to avoid wasting bandwidth with Isolate
8
+ # and multiple Ruby versions
9
+ NO_PROXY=${UNICORN_TEST_ADDR-127.0.0.1}
10
+ export NO_PROXY
11
+
6
12
  if test -z "$model"
7
13
  then
8
14
  # defaulting to Base would unfortunately fail some concurrency tests
@@ -21,16 +27,6 @@ export PATH
21
27
 
22
28
  test -x $PWD/bin/unused_listen || die "must be run in 't' directory"
23
29
 
24
- wait_for_pid () {
25
- path="$1"
26
- nr=30
27
- while ! test -s "$path" && test $nr -gt 0
28
- do
29
- nr=$(($nr - 1))
30
- sleep 1
31
- done
32
- }
33
-
34
30
  # requires $1 and prints out the value of $2
35
31
  require_check () {
36
32
  lib=$1
data/t/test_isolate.rb ADDED
@@ -0,0 +1,39 @@
1
+ require 'rubygems'
2
+ require 'isolate'
3
+
4
+ path = "tmp/isolate/ruby-#{RUBY_VERSION}"
5
+ opts = {
6
+ :system => false,
7
+ # we want "ruby-1.8.7" and not "ruby-1.8", so disable multiruby
8
+ :multiruby => false,
9
+ :path => path,
10
+ }
11
+
12
+ old_out = $stdout.dup
13
+ $stdout.reopen($stderr)
14
+
15
+ Isolate.now!(opts) do
16
+ gem 'rack', '1.1.0'
17
+ gem 'unicorn', '0.99.0'
18
+
19
+ gem 'iobuffer', '0.1.3'
20
+ gem 'rev', '0.3.2'
21
+
22
+ gem 'eventmachine', '0.12.10'
23
+
24
+ gem 'sinatra', '0.9.4'
25
+ gem 'async_sinatra', '0.1.5'
26
+
27
+ gem 'neverblock', '0.1.6.2'
28
+
29
+ if defined?(::Fiber)
30
+ gem 'case', '0.5'
31
+ gem 'revactor', '0.1.5'
32
+ gem 'rack-fiber_pool', '0.9.0'
33
+ end
34
+
35
+ gem 'cramp', '0.11'
36
+ end
37
+
38
+ $stdout.reopen(old_out)
39
+ puts Dir["#{path}/gems/*-*/lib"].map { |x| File.expand_path(x) }.join(':')
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rainbows
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.93.0
4
+ version: 0.94.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Rainbows! hackers
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2010-05-29 00:00:00 +00:00
12
+ date: 2010-06-04 00:00:00 +00:00
13
13
  default_executable:
14
14
  dependencies:
15
15
  - !ruby/object:Gem::Dependency
@@ -25,6 +25,16 @@ dependencies:
25
25
  - !ruby/object:Gem::Version
26
26
  version: 2.0.0
27
27
  version:
28
+ - !ruby/object:Gem::Dependency
29
+ name: isolate
30
+ type: :development
31
+ version_requirement:
32
+ version_requirements: !ruby/object:Gem::Requirement
33
+ requirements:
34
+ - - ~>
35
+ - !ruby/object:Gem::Version
36
+ version: 2.0.2
37
+ version:
28
38
  description: |-
29
39
  \Rainbows! is an HTTP server for sleepy Rack applications. It is based on
30
40
  Unicorn, but designed to handle applications that expect long
@@ -73,6 +83,7 @@ extra_rdoc_files:
73
83
  - lib/rainbows/rev_thread_pool.rb
74
84
  - lib/rainbows/rev_thread_spawn.rb
75
85
  - lib/rainbows/revactor.rb
86
+ - lib/rainbows/sendfile.rb
76
87
  - lib/rainbows/tee_input.rb
77
88
  - lib/rainbows/thread_pool.rb
78
89
  - lib/rainbows/thread_spawn.rb
@@ -86,6 +97,7 @@ extra_rdoc_files:
86
97
  - TUNING
87
98
  - vs_Unicorn
88
99
  - Summary
100
+ - Test_Suite
89
101
  files:
90
102
  - .document
91
103
  - .gitignore
@@ -110,9 +122,8 @@ files:
110
122
  - Summary
111
123
  - TODO
112
124
  - TUNING
125
+ - Test_Suite
113
126
  - bin/rainbows
114
- - config/.gitignore
115
- - config/isolate.rb
116
127
  - lib/rainbows.rb
117
128
  - lib/rainbows/actor_spawn.rb
118
129
  - lib/rainbows/app_pool.rb
@@ -146,6 +157,7 @@ files:
146
157
  - lib/rainbows/rev_thread_pool.rb
147
158
  - lib/rainbows/rev_thread_spawn.rb
148
159
  - lib/rainbows/revactor.rb
160
+ - lib/rainbows/sendfile.rb
149
161
  - lib/rainbows/tee_input.rb
150
162
  - lib/rainbows/thread_pool.rb
151
163
  - lib/rainbows/thread_spawn.rb
@@ -231,7 +243,10 @@ files:
231
243
  - t/t0700-app-deferred.sh
232
244
  - t/t9000-rack-app-pool.sh
233
245
  - t/t9000.ru
246
+ - t/t9001-sendfile-to-path.sh
247
+ - t/t9001.ru
234
248
  - t/test-lib.sh
249
+ - t/test_isolate.rb
235
250
  - t/worker-follows-master-to-death.ru
236
251
  - vs_Unicorn
237
252
  has_rdoc: true
data/config/.gitignore DELETED
@@ -1 +0,0 @@
1
- /isolate_*.rb
data/config/isolate.rb DELETED
@@ -1,25 +0,0 @@
1
- # this the default config file used by John Barnette's isolate gem
2
- # you can create a config/isolate_local.rb file to override this
3
- # See the corresponding tasks in Rakefile and GNUmakefile
4
- # `rake isolate' or (faster in the unmodified case, `make isolate')
5
-
6
- gem 'rack', '1.1.0'
7
- gem 'unicorn', '0.99.0'
8
-
9
- gem 'iobuffer', '0.1.3'
10
- gem 'rev', '0.3.2'
11
-
12
- gem 'eventmachine', '0.12.10'
13
-
14
- gem 'sinatra', '0.9.4'
15
- gem 'async_sinatra', '0.1.5'
16
-
17
- gem 'neverblock', '0.1.6.2'
18
-
19
- if defined?(::Fiber)
20
- gem 'case', '0.5'
21
- gem 'revactor', '0.1.5'
22
- gem 'rack-fiber_pool', '0.9.0'
23
- end
24
-
25
- gem 'cramp', '0.11'