rainbows 4.4.3 → 4.5.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 +1 -0
- data/.gitignore +1 -0
- data/Documentation/rainbows.1.txt +8 -4
- data/GIT-VERSION-GEN +34 -35
- data/GNUmakefile +4 -2
- data/HACKING +72 -0
- data/bin/rainbows +5 -0
- data/lib/rainbows/const.rb +3 -3
- data/lib/rainbows/coolio/client.rb +18 -6
- data/lib/rainbows/coolio/thread_client.rb +2 -0
- data/lib/rainbows/epoll/client.rb +35 -12
- data/lib/rainbows/ev_core.rb +5 -4
- data/lib/rainbows/event_machine/client.rb +9 -4
- data/lib/rainbows/process_client.rb +7 -3
- data/lib/rainbows/response.rb +54 -18
- data/lib/rainbows/revactor/client/methods.rb +1 -1
- data/lib/rainbows/stream_response_epoll.rb +34 -15
- data/lib/rainbows/stream_response_epoll/client.rb +11 -3
- data/lib/rainbows/writer_thread_pool/client.rb +2 -0
- data/lib/rainbows/xepoll/client.rb +0 -3
- data/lib/rainbows/xepoll_thread_pool/client.rb +1 -1
- data/lib/rainbows/xepoll_thread_spawn/client.rb +1 -1
- data/rainbows.gemspec +6 -3
- data/t/GNUmakefile +10 -3
- data/t/byte-range-common.sh +1 -1
- data/t/hijack.ru +56 -0
- data/t/t0000-simple-http.sh +9 -9
- data/t/t0001-unix-http.sh +8 -8
- data/t/t0003-reopen-logs.sh +8 -8
- data/t/t0004-heartbeat-timeout.sh +3 -3
- data/t/t0005-large-file-response.sh +1 -1
- data/t/t0010-keepalive-timeout-effective.sh +2 -2
- data/t/t0011-close-on-exec-set.sh +2 -2
- data/t/t0017-keepalive-timeout-zero.sh +2 -2
- data/t/t0024-pipelined-sendfile-response.sh +2 -2
- data/t/t0027-nil-copy_stream.sh +1 -1
- data/t/t0030-fast-pipe-response.sh +1 -1
- data/t/t0034-pipelined-pipe-response.sh +2 -2
- data/t/t0035-kgio-pipe-response.sh +1 -1
- data/t/t0040-keepalive_requests-setting.sh +4 -4
- data/t/t0043-quit-keepalive-disconnect.sh +3 -3
- data/t/t0044-autopush.sh +2 -2
- data/t/t0045-client_max_header_size.sh +2 -2
- data/t/t0100-rack-input-hammer-chunked.sh +4 -4
- data/t/t0100-rack-input-hammer-content-length.sh +4 -4
- data/t/t0106-rack-input-keepalive.sh +6 -6
- data/t/t0200-async-response.sh +5 -5
- data/t/t0202-async-response-one-oh.sh +5 -5
- data/t/t0300-async_sinatra.sh +5 -5
- data/t/t0400-em-async-app.sh +2 -2
- data/t/t0401-em-async-tailer.sh +2 -2
- data/t/t0402-async-keepalive.sh +23 -23
- data/t/t0500-cramp-streaming.sh +3 -3
- data/t/t0600-rack-fiber_pool.sh +1 -1
- data/t/t0700-app-deferred.sh +2 -2
- data/t/t0800-rack-hijack.sh +27 -0
- data/t/t9000-rack-app-pool.sh +3 -3
- data/t/t9001-sendfile-to-path.sh +1 -1
- data/t/t9100-thread-timeout.sh +1 -1
- data/t/t9101-thread-timeout-threshold.sh +1 -1
- data/t/test-lib.sh +15 -0
- data/t/test_isolate.rb +4 -3
- metadata +26 -6
- data/t/bin/utee +0 -12
data/.document
CHANGED
data/.gitignore
CHANGED
@@ -58,6 +58,10 @@ with rackup(1) but strongly discouraged.
|
|
58
58
|
For production deployments, specifying the "listen" directive in
|
59
59
|
CONFIG_FILE is recommended as it allows fine-tuning of socket
|
60
60
|
options.
|
61
|
+
-N, \--no-default-middleware
|
62
|
+
: Disables loading middleware implied by RACK_ENV. This bypasses the
|
63
|
+
configuration documented in the RACK ENVIRONMENT section, but still
|
64
|
+
allows RACK_ENV to be used for application/framework-specific purposes.
|
61
65
|
|
62
66
|
# RACKUP COMPATIBILITY OPTIONS
|
63
67
|
-o, \--host HOST
|
@@ -137,10 +141,10 @@ All unrecognized values for RACK_ENV are assumed to be
|
|
137
141
|
"none". Production deployments are strongly encouraged to use
|
138
142
|
"deployment" or "none" for maximum performance.
|
139
143
|
|
140
|
-
Note
|
141
|
-
|
142
|
-
individually specified in the
|
143
|
-
not require them.
|
144
|
+
Note the Rack::ContentLength and Rack::Chunked middlewares are also
|
145
|
+
loaded by "deployment" and "development", but no other values of
|
146
|
+
RACK_ENV. If needed, they must be individually specified in the
|
147
|
+
RACKUP_FILE, some frameworks do not require them.
|
144
148
|
|
145
149
|
# SEE ALSO
|
146
150
|
|
data/GIT-VERSION-GEN
CHANGED
@@ -1,40 +1,39 @@
|
|
1
|
-
#!/bin/
|
2
|
-
|
3
|
-
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
'
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
DEF_VER = "v4.5.0"
|
3
|
+
CONSTANT = "Rainbows::Const::RAINBOWS_VERSION"
|
4
|
+
RVF = "lib/rainbows/version.rb"
|
5
|
+
GVF = "GIT-VERSION-FILE"
|
6
|
+
vn = DEF_VER
|
8
7
|
|
9
8
|
# First see if there is a version file (included in release tarballs),
|
10
9
|
# then try git-describe, then default.
|
11
|
-
if
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
24
|
-
|
25
|
-
|
26
|
-
|
27
|
-
|
10
|
+
if File.exist?(".git")
|
11
|
+
describe = `git describe --abbrev=4 HEAD 2>/dev/null`.strip
|
12
|
+
case describe
|
13
|
+
when /\Av[0-9]*/
|
14
|
+
vn = describe
|
15
|
+
system(*%w(git update-index -q --refresh))
|
16
|
+
unless `git diff-index --name-only HEAD --`.chomp.empty?
|
17
|
+
vn << "-dirty"
|
18
|
+
end
|
19
|
+
vn.tr!('-', '.')
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
vn = vn.sub!(/\Av/, "")
|
24
|
+
|
25
|
+
# generate the Ruby constant
|
26
|
+
new_ruby_version = "#{CONSTANT} = '#{vn}'\n"
|
27
|
+
cur_ruby_version = File.read(RVF) rescue nil
|
28
|
+
if new_ruby_version != cur_ruby_version
|
29
|
+
File.open(RVF, "w") { |fp| fp.write(new_ruby_version) }
|
30
|
+
end
|
28
31
|
|
29
|
-
|
32
|
+
# generate the makefile snippet
|
33
|
+
new_make_version = "GIT_VERSION = #{vn}\n"
|
34
|
+
cur_make_version = File.read(GVF) rescue nil
|
35
|
+
if new_make_version != cur_make_version
|
36
|
+
File.open(GVF, "w") { |fp| fp.write(new_make_version) }
|
37
|
+
end
|
30
38
|
|
31
|
-
if
|
32
|
-
then
|
33
|
-
VC=$(sed -e 's/^GIT_VERSION = //' <$GVF)
|
34
|
-
else
|
35
|
-
VC=unset
|
36
|
-
fi
|
37
|
-
test "$VN" = "$VC" || {
|
38
|
-
echo >&2 "GIT_VERSION = $VN"
|
39
|
-
echo "GIT_VERSION = $VN" >$GVF
|
40
|
-
}
|
39
|
+
puts vn if $0 == __FILE__
|
data/GNUmakefile
CHANGED
@@ -28,14 +28,16 @@ clean:
|
|
28
28
|
man html:
|
29
29
|
$(MAKE) -C Documentation install-$@
|
30
30
|
|
31
|
-
pkg_extra += $(man1_paths)
|
31
|
+
pkg_extra += $(man1_paths) lib/rainbows/version.rb
|
32
32
|
|
33
33
|
doc::
|
34
34
|
cat Documentation/comparison.css >> doc/rdoc.css
|
35
35
|
$(RM) $(man1_rdoc)
|
36
36
|
|
37
|
+
lib/rainbows/version.rb: GIT-VERSION-FILE
|
38
|
+
|
37
39
|
all:: test
|
38
|
-
test:
|
40
|
+
test: lib/rainbows/version.rb
|
39
41
|
$(MAKE) -C t
|
40
42
|
|
41
43
|
.PHONY: man html
|
data/HACKING
ADDED
@@ -0,0 +1,72 @@
|
|
1
|
+
= Rainbows! Hacker's Guide
|
2
|
+
|
3
|
+
=== Tests
|
4
|
+
|
5
|
+
All tests are written in POSIX shell. See README file in the t/ directory.
|
6
|
+
|
7
|
+
=== Documentation
|
8
|
+
|
9
|
+
We use RDoc 3.9.x with Darkfish for documentation as much as possible,
|
10
|
+
if you're on Ruby 1.8 you want to install the latest "rdoc" gem. Due to
|
11
|
+
the lack of RDoc-to-manpage converters we know about, we're writing
|
12
|
+
manpages in Markdown and converting to troff/HTML with Pandoc.
|
13
|
+
|
14
|
+
Please wrap documentation at 72 characters-per-line or less (long URLs
|
15
|
+
are exempt) so it is comfortably readable from terminals.
|
16
|
+
|
17
|
+
When referencing mailing list posts, use
|
18
|
+
"http://mid.gmane.org/$MESSAGE_ID" if possible since the Message-ID
|
19
|
+
remains searchable even if Gmane becomes unavailable.
|
20
|
+
|
21
|
+
== Contributing
|
22
|
+
|
23
|
+
Contributions are welcome in the form of patches, pull requests, code
|
24
|
+
review, testing, documentation, user support or any other feedback is
|
25
|
+
welcome. The mailing list is the central coordination point for all
|
26
|
+
user and developer feedback and bug reports.
|
27
|
+
|
28
|
+
=== Submitting Patches
|
29
|
+
|
30
|
+
Follow conventions already established in the code and do not exceed 80
|
31
|
+
characters per line.
|
32
|
+
|
33
|
+
Inline patches (from "git format-patch -M") to the mailing list are
|
34
|
+
preferred because they allow code review and comments in the reply to
|
35
|
+
the patch.
|
36
|
+
|
37
|
+
We will adhere to mostly the same conventions for patch submissions as
|
38
|
+
git itself. See the Documentation/SubmittingPatches document
|
39
|
+
distributed with git on on patch submission guidelines to follow. Just
|
40
|
+
don't email the git mailing list or maintainer with Rainbows! patches :)
|
41
|
+
|
42
|
+
No subscription is required to post to the mailing list at
|
43
|
+
rainbows-talk@rubyforge.org
|
44
|
+
|
45
|
+
Please ask for Cc: if you are not subscribed (Cc:-by-default is uncommon
|
46
|
+
on Ruby mailing lists)
|
47
|
+
|
48
|
+
== Building a Gem
|
49
|
+
|
50
|
+
In order to build the gem, you must install the following components:
|
51
|
+
|
52
|
+
* wrongdoc
|
53
|
+
* pandoc
|
54
|
+
|
55
|
+
You can build the Unicorn gem with the following command:
|
56
|
+
|
57
|
+
gmake gem
|
58
|
+
|
59
|
+
== Running Development Versions
|
60
|
+
|
61
|
+
It is easy to install the contents of your git working directory:
|
62
|
+
|
63
|
+
Via RubyGems (recommended):
|
64
|
+
|
65
|
+
gmake install-gem
|
66
|
+
|
67
|
+
Without RubyGems (via setup.rb):
|
68
|
+
|
69
|
+
ruby setup.rb
|
70
|
+
|
71
|
+
It is not at all recommended to mix a RubyGems installation with an
|
72
|
+
installation done without RubyGems, however.
|
data/bin/rainbows
CHANGED
@@ -59,6 +59,11 @@ op = OptionParser.new("", 24, ' ') do |opts|
|
|
59
59
|
ENV["RACK_ENV"] = e
|
60
60
|
end
|
61
61
|
|
62
|
+
opts.on("-N", "--no-default-middleware",
|
63
|
+
"do not load middleware implied by RACK_ENV") do |e|
|
64
|
+
rackup_opts[:no_default_middleware] = true
|
65
|
+
end
|
66
|
+
|
62
67
|
opts.on("-D", "--daemonize", "run daemonized in the background") do |d|
|
63
68
|
rackup_opts[:daemonize] = !!d
|
64
69
|
end
|
data/lib/rainbows/const.rb
CHANGED
@@ -86,6 +86,12 @@ class Rainbows::Coolio::Client < Coolio::IO
|
|
86
86
|
@deferred = true
|
87
87
|
end
|
88
88
|
|
89
|
+
def hijacked
|
90
|
+
CONN.delete(self)
|
91
|
+
detach
|
92
|
+
nil
|
93
|
+
end
|
94
|
+
|
89
95
|
def write_response_path(status, headers, body, alive)
|
90
96
|
io = body_to_io(body)
|
91
97
|
st = io.stat
|
@@ -93,7 +99,8 @@ class Rainbows::Coolio::Client < Coolio::IO
|
|
93
99
|
if st.file?
|
94
100
|
defer_file(status, headers, body, alive, io, st)
|
95
101
|
elsif st.socket? || st.pipe?
|
96
|
-
chunk = stream_response_headers(status, headers, alive)
|
102
|
+
chunk = stream_response_headers(status, headers, alive, body)
|
103
|
+
return hijacked if nil == chunk
|
97
104
|
stream_response_body(body, io, chunk)
|
98
105
|
else
|
99
106
|
# char or block device... WTF?
|
@@ -103,10 +110,11 @@ class Rainbows::Coolio::Client < Coolio::IO
|
|
103
110
|
|
104
111
|
def ev_write_response(status, headers, body, alive)
|
105
112
|
if body.respond_to?(:to_path)
|
106
|
-
write_response_path(status, headers, body, alive)
|
113
|
+
body = write_response_path(status, headers, body, alive)
|
107
114
|
else
|
108
|
-
write_response(status, headers, body, alive)
|
115
|
+
body = write_response(status, headers, body, alive)
|
109
116
|
end
|
117
|
+
return hijacked unless body
|
110
118
|
return quit unless alive && :close != @state
|
111
119
|
@state = :headers
|
112
120
|
end
|
@@ -117,9 +125,11 @@ class Rainbows::Coolio::Client < Coolio::IO
|
|
117
125
|
@env[RACK_INPUT] = input
|
118
126
|
@env[REMOTE_ADDR] = @_io.kgio_addr
|
119
127
|
@env[ASYNC_CALLBACK] = method(:write_async_response)
|
128
|
+
@hp.hijack_setup(@env, @_io)
|
120
129
|
status, headers, body = catch(:async) {
|
121
130
|
APP.call(@env.merge!(RACK_DEFAULTS))
|
122
131
|
}
|
132
|
+
return hijacked if @hp.hijacked?
|
123
133
|
|
124
134
|
(nil == status || -1 == status) ? @deferred = true :
|
125
135
|
ev_write_response(status, headers, body, @hp.next?)
|
@@ -186,12 +196,13 @@ class Rainbows::Coolio::Client < Coolio::IO
|
|
186
196
|
def defer_file(status, headers, body, alive, io, st)
|
187
197
|
if r = sendfile_range(status, headers)
|
188
198
|
status, headers, range = r
|
189
|
-
write_headers(status, headers, alive)
|
199
|
+
body = write_headers(status, headers, alive, body) or return hijacked
|
190
200
|
range and defer_file_stream(range[0], range[1], io, body)
|
191
201
|
else
|
192
|
-
write_headers(status, headers, alive)
|
202
|
+
write_headers(status, headers, alive, body) or return hijacked
|
193
203
|
defer_file_stream(0, st.size, io, body)
|
194
204
|
end
|
205
|
+
body
|
195
206
|
end
|
196
207
|
|
197
208
|
def stream_file_chunk(sf) # +sf+ is a Rainbows::StreamFile object
|
@@ -207,8 +218,9 @@ class Rainbows::Coolio::Client < Coolio::IO
|
|
207
218
|
end
|
208
219
|
else
|
209
220
|
def defer_file(status, headers, body, alive, io, st)
|
210
|
-
write_headers(status, headers, alive)
|
221
|
+
write_headers(status, headers, alive, body) or return hijacked
|
211
222
|
defer_file_stream(0, st.size, io, body)
|
223
|
+
body
|
212
224
|
end
|
213
225
|
|
214
226
|
def stream_file_chunk(body)
|
@@ -14,6 +14,7 @@ class Rainbows::Coolio::ThreadClient < Rainbows::Coolio::Client
|
|
14
14
|
|
15
15
|
# this is only called in the master thread
|
16
16
|
def response_write(response)
|
17
|
+
return hijacked if @hp.hijacked?
|
17
18
|
ev_write_response(*response, @hp.next?)
|
18
19
|
rescue => e
|
19
20
|
handle_error(e)
|
@@ -25,6 +26,7 @@ class Rainbows::Coolio::ThreadClient < Rainbows::Coolio::Client
|
|
25
26
|
def app_response
|
26
27
|
begin
|
27
28
|
@env[REMOTE_ADDR] = @_io.kgio_addr
|
29
|
+
@hp.hijack_setup(@env, @_io)
|
28
30
|
APP.call(@env.merge!(RACK_DEFAULTS))
|
29
31
|
rescue => e
|
30
32
|
Rainbows::Error.app(e) # we guarantee this does not raise
|
@@ -6,14 +6,14 @@ module Rainbows::Epoll::Client
|
|
6
6
|
include Rainbows::EvCore
|
7
7
|
APP = Rainbows.server.app
|
8
8
|
Server = Rainbows::Epoll::Server
|
9
|
-
IN = SleepyPenguin::Epoll::IN | SleepyPenguin::Epoll::
|
10
|
-
OUT = SleepyPenguin::Epoll::OUT | SleepyPenguin::Epoll::
|
9
|
+
IN = SleepyPenguin::Epoll::IN | SleepyPenguin::Epoll::ONESHOT
|
10
|
+
OUT = SleepyPenguin::Epoll::OUT | SleepyPenguin::Epoll::ONESHOT
|
11
|
+
EPINOUT = IN | OUT
|
11
12
|
KATO = {}
|
12
13
|
KATO.compare_by_identity if KATO.respond_to?(:compare_by_identity)
|
13
14
|
Rainbows.at_quit { KATO.each_key { |k| k.timeout! }.clear }
|
14
15
|
Rainbows.config!(self, :keepalive_timeout)
|
15
16
|
EP = Rainbows::EP
|
16
|
-
ReRun = []
|
17
17
|
@@last_expire = Time.now
|
18
18
|
|
19
19
|
def self.expire
|
@@ -28,9 +28,6 @@ module Rainbows::Epoll::Client
|
|
28
28
|
def self.loop
|
29
29
|
begin
|
30
30
|
EP.wait(nil, 1000) { |_, obj| obj.epoll_run }
|
31
|
-
while obj = ReRun.shift
|
32
|
-
obj.epoll_run
|
33
|
-
end
|
34
31
|
expire
|
35
32
|
rescue Errno::EINTR
|
36
33
|
rescue => e
|
@@ -52,6 +49,7 @@ module Rainbows::Epoll::Client
|
|
52
49
|
when String
|
53
50
|
on_read(rv)
|
54
51
|
return if @wr_queue[0] || closed?
|
52
|
+
return hijacked if @hp.hijacked?
|
55
53
|
when :wait_readable
|
56
54
|
KATO[self] = @@last_expire if :headers == @state
|
57
55
|
return EP.set(self, IN)
|
@@ -67,7 +65,9 @@ module Rainbows::Epoll::Client
|
|
67
65
|
def app_call input # called by on_read()
|
68
66
|
@env[RACK_INPUT] = input
|
69
67
|
@env[REMOTE_ADDR] = kgio_addr
|
68
|
+
@hp.hijack_setup(@env, self)
|
70
69
|
status, headers, body = APP.call(@env.merge!(RACK_DEFAULTS))
|
70
|
+
return hijacked if @hp.hijacked?
|
71
71
|
ev_write_response(status, headers, body, @hp.next?)
|
72
72
|
end
|
73
73
|
|
@@ -78,7 +78,8 @@ module Rainbows::Epoll::Client
|
|
78
78
|
if st.file?
|
79
79
|
defer_file(status, headers, body, alive, io, st)
|
80
80
|
elsif st.socket? || st.pipe?
|
81
|
-
chunk = stream_response_headers(status, headers, alive)
|
81
|
+
chunk = stream_response_headers(status, headers, alive, body)
|
82
|
+
return hijacked if nil == chunk
|
82
83
|
stream_response_body(body, io, chunk)
|
83
84
|
else
|
84
85
|
# char or block device... WTF?
|
@@ -102,7 +103,28 @@ module Rainbows::Epoll::Client
|
|
102
103
|
else
|
103
104
|
write_response(status, headers, body, alive)
|
104
105
|
end
|
105
|
-
|
106
|
+
return hijacked if @hp.hijacked?
|
107
|
+
# try to read more if we didn't have to buffer writes
|
108
|
+
next_request if alive && 0 == @wr_queue.size
|
109
|
+
end
|
110
|
+
|
111
|
+
def hijacked
|
112
|
+
KATO.delete(self)
|
113
|
+
Server.decr # no other place to do this
|
114
|
+
EP.delete(self)
|
115
|
+
nil
|
116
|
+
end
|
117
|
+
|
118
|
+
def next_request
|
119
|
+
if 0 == @buf.size
|
120
|
+
want_more
|
121
|
+
else
|
122
|
+
# pipelined request (already in buffer)
|
123
|
+
on_read(Z)
|
124
|
+
return if @wr_queue[0] || closed?
|
125
|
+
return hijacked if @hp.hijacked?
|
126
|
+
close if :close == @state
|
127
|
+
end
|
106
128
|
end
|
107
129
|
|
108
130
|
def epoll_run
|
@@ -115,12 +137,12 @@ module Rainbows::Epoll::Client
|
|
115
137
|
end
|
116
138
|
|
117
139
|
def want_more
|
118
|
-
|
140
|
+
EP.set(self, EPINOUT)
|
119
141
|
end
|
120
142
|
|
121
143
|
def on_deferred_write_complete
|
122
144
|
:close == @state and return close
|
123
|
-
|
145
|
+
next_request
|
124
146
|
end
|
125
147
|
|
126
148
|
def handle_error(e)
|
@@ -185,13 +207,14 @@ module Rainbows::Epoll::Client
|
|
185
207
|
true
|
186
208
|
end
|
187
209
|
|
210
|
+
# Rack apps should not hijack here, but they may...
|
188
211
|
def defer_file(status, headers, body, alive, io, st)
|
189
212
|
if r = sendfile_range(status, headers)
|
190
213
|
status, headers, range = r
|
191
|
-
write_headers(status, headers, alive)
|
214
|
+
write_headers(status, headers, alive, body) or return hijacked
|
192
215
|
range and defer_file_stream(range[0], range[1], io, body)
|
193
216
|
else
|
194
|
-
write_headers(status, headers, alive)
|
217
|
+
write_headers(status, headers, alive, body) or return hijacked
|
195
218
|
defer_file_stream(0, st.size, io, body)
|
196
219
|
end
|
197
220
|
end
|
data/lib/rainbows/ev_core.rb
CHANGED
@@ -52,16 +52,17 @@ module Rainbows::EvCore
|
|
52
52
|
end
|
53
53
|
|
54
54
|
# returns whether to enable response chunking for autochunk models
|
55
|
-
|
55
|
+
# returns nil if request was hijacked in response stage
|
56
|
+
def stream_response_headers(status, headers, alive, body)
|
56
57
|
headers = Rack::Utils::HeaderHash.new(headers) unless Hash === headers
|
57
58
|
if headers.include?(Content_Length)
|
58
|
-
write_headers(status, headers, alive)
|
59
|
+
write_headers(status, headers, alive, body) or return
|
59
60
|
return false
|
60
61
|
end
|
61
62
|
|
62
63
|
case @env[HTTP_VERSION]
|
63
64
|
when "HTTP/1.0" # disable HTTP/1.0 keepalive to stream
|
64
|
-
write_headers(status, headers, false)
|
65
|
+
write_headers(status, headers, false, body) or return
|
65
66
|
@hp.clear
|
66
67
|
false
|
67
68
|
when nil # "HTTP/0.9"
|
@@ -69,7 +70,7 @@ module Rainbows::EvCore
|
|
69
70
|
else
|
70
71
|
rv = !!(headers[Transfer_Encoding] =~ %r{\Achunked\z}i)
|
71
72
|
rv = false unless @env["rainbows.autochunk"]
|
72
|
-
write_headers(status, headers, alive)
|
73
|
+
write_headers(status, headers, alive, body) or return
|
73
74
|
rv
|
74
75
|
end
|
75
76
|
end
|