rainbows 2.1.0 → 3.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
@@ -1,17 +0,0 @@
|
|
1
|
-
# -*- encoding: binary -*-
|
2
|
-
# :enddoc:
|
3
|
-
module Rainbows::Coolio::Sendfile
|
4
|
-
if IO.method_defined?(:sendfile_nonblock)
|
5
|
-
def rev_sendfile(sf) # +sf+ is a Rainbows::StreamFile object
|
6
|
-
sf.offset += (n = @_io.sendfile_nonblock(sf, sf.offset, sf.count))
|
7
|
-
0 == (sf.count -= n) and raise EOFError
|
8
|
-
enable_write_watcher
|
9
|
-
rescue Errno::EAGAIN
|
10
|
-
enable_write_watcher
|
11
|
-
end
|
12
|
-
else
|
13
|
-
def rev_sendfile(body)
|
14
|
-
write(body.to_io.sysread(0x4000))
|
15
|
-
end
|
16
|
-
end
|
17
|
-
end
|
@@ -1,127 +0,0 @@
|
|
1
|
-
# -*- encoding: binary -*-
|
2
|
-
# :enddoc:
|
3
|
-
# non-portable body response stuff goes here
|
4
|
-
#
|
5
|
-
# The sendfile 1.0.0 RubyGem includes IO#sendfile and
|
6
|
-
# IO#sendfile_nonblock. Previous versions of "sendfile" didn't have
|
7
|
-
# IO#sendfile_nonblock, and IO#sendfile in previous versions could
|
8
|
-
# block other threads under 1.8 with large files
|
9
|
-
#
|
10
|
-
# IO#sendfile currently (June 2010) beats 1.9 IO.copy_stream with
|
11
|
-
# non-Linux support and large files on 32-bit. We still fall back to
|
12
|
-
# IO.copy_stream (if available) if we're dealing with DevFdResponse
|
13
|
-
# objects, though.
|
14
|
-
#
|
15
|
-
# Linux-only splice(2) support via the "io_splice" gem will eventually
|
16
|
-
# be added for streaming sockets/pipes, too.
|
17
|
-
#
|
18
|
-
# * write_body_file - regular files (sendfile or pread+write)
|
19
|
-
# * write_body_stream - socket/pipes (read+write, splice later)
|
20
|
-
# * write_body_each - generic fallback
|
21
|
-
#
|
22
|
-
# callgraph is as follows:
|
23
|
-
#
|
24
|
-
# write_body
|
25
|
-
# `- write_body_each
|
26
|
-
# `- write_body_path
|
27
|
-
# `- write_body_file
|
28
|
-
# `- write_body_stream
|
29
|
-
#
|
30
|
-
module Rainbows::Response::Body # :nodoc:
|
31
|
-
ALIASES = {}
|
32
|
-
|
33
|
-
FD_MAP = Rainbows::FD_MAP
|
34
|
-
|
35
|
-
class F < File; end
|
36
|
-
|
37
|
-
def close_if_private(io)
|
38
|
-
io.close if F === io
|
39
|
-
end
|
40
|
-
|
41
|
-
def io_for_fd(fd)
|
42
|
-
FD_MAP.delete(fd) || F.for_fd(fd)
|
43
|
-
end
|
44
|
-
|
45
|
-
# to_io is not part of the Rack spec, but make an exception here
|
46
|
-
# since we can conserve path lookups and file descriptors.
|
47
|
-
# \Rainbows! will never get here without checking for the existence
|
48
|
-
# of body.to_path first.
|
49
|
-
def body_to_io(body)
|
50
|
-
if body.respond_to?(:to_io)
|
51
|
-
body.to_io
|
52
|
-
else
|
53
|
-
# try to take advantage of Rainbows::DevFdResponse, calling File.open
|
54
|
-
# is a last resort
|
55
|
-
path = body.to_path
|
56
|
-
path =~ %r{\A/dev/fd/(\d+)\z} ? io_for_fd($1.to_i) : F.open(path)
|
57
|
-
end
|
58
|
-
end
|
59
|
-
|
60
|
-
if IO.method_defined?(:sendfile_nonblock)
|
61
|
-
def write_body_file(sock, body, range)
|
62
|
-
io = body_to_io(body)
|
63
|
-
range ? sock.sendfile(io, range[0], range[1]) : sock.sendfile(io, 0)
|
64
|
-
ensure
|
65
|
-
close_if_private(io)
|
66
|
-
end
|
67
|
-
end
|
68
|
-
|
69
|
-
if IO.respond_to?(:copy_stream)
|
70
|
-
unless method_defined?(:write_body_file)
|
71
|
-
# try to use sendfile() via IO.copy_stream, otherwise pread()+write()
|
72
|
-
def write_body_file(sock, body, range)
|
73
|
-
range ? IO.copy_stream(body, sock, range[1], range[0]) :
|
74
|
-
IO.copy_stream(body, sock, nil, 0)
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
# only used when body is a pipe or socket that can't handle
|
79
|
-
# pread() semantics
|
80
|
-
def write_body_stream(sock, body, range)
|
81
|
-
IO.copy_stream(body, sock)
|
82
|
-
end
|
83
|
-
else
|
84
|
-
# fall back to body#each, which is a Rack standard
|
85
|
-
ALIASES[:write_body_stream] = :write_body_each
|
86
|
-
end
|
87
|
-
|
88
|
-
if method_defined?(:write_body_file)
|
89
|
-
# middlewares/apps may return with a body that responds to +to_path+
|
90
|
-
def write_body_path(sock, body, range)
|
91
|
-
stat = File.stat(body.to_path)
|
92
|
-
stat.file? ? write_body_file(sock, body, range) :
|
93
|
-
write_body_stream(sock, body, range)
|
94
|
-
ensure
|
95
|
-
body.respond_to?(:close) and body.close
|
96
|
-
end
|
97
|
-
elsif method_defined?(:write_body_stream)
|
98
|
-
def write_body_path(sock, body, range)
|
99
|
-
write_body_stream(sock, body, range)
|
100
|
-
ensure
|
101
|
-
body.respond_to?(:close) and body.close
|
102
|
-
end
|
103
|
-
end
|
104
|
-
|
105
|
-
if method_defined?(:write_body_path)
|
106
|
-
def write_body(client, body, range)
|
107
|
-
body.respond_to?(:to_path) ?
|
108
|
-
write_body_path(client, body, range) :
|
109
|
-
write_body_each(client, body, range)
|
110
|
-
end
|
111
|
-
else
|
112
|
-
ALIASES[:write_body] = :write_body_each
|
113
|
-
end
|
114
|
-
|
115
|
-
# generic body writer, used for most dynamically generated responses
|
116
|
-
def write_body_each(socket, body, range = nil)
|
117
|
-
body.each { |chunk| socket.write(chunk) }
|
118
|
-
ensure
|
119
|
-
body.respond_to?(:close) and body.close
|
120
|
-
end
|
121
|
-
|
122
|
-
def self.included(klass)
|
123
|
-
ALIASES.each do |new_method, orig_method|
|
124
|
-
klass.__send__(:alias_method, new_method, orig_method)
|
125
|
-
end
|
126
|
-
end
|
127
|
-
end
|
@@ -1,34 +0,0 @@
|
|
1
|
-
# -*- encoding: binary -*-
|
2
|
-
# :enddoc:
|
3
|
-
module Rainbows::Response::Range
|
4
|
-
HTTP_RANGE = 'HTTP_RANGE'
|
5
|
-
Content_Range = 'Content-Range'.freeze
|
6
|
-
Content_Length = 'Content-Length'.freeze
|
7
|
-
|
8
|
-
# This does not support multipart responses (does anybody actually
|
9
|
-
# use those?) +headers+ is always a Rack::Utils::HeaderHash
|
10
|
-
def make_range!(env, status, headers)
|
11
|
-
if 200 == status.to_i &&
|
12
|
-
(clen = headers[Content_Length]) &&
|
13
|
-
/\Abytes=(\d+-\d*|\d*-\d+)\z/ =~ env[HTTP_RANGE]
|
14
|
-
a, b = $1.split(/-/)
|
15
|
-
clen = clen.to_i
|
16
|
-
if b.nil? # bytes=M-
|
17
|
-
offset = a.to_i
|
18
|
-
count = clen - offset
|
19
|
-
elsif a.empty? # bytes=-N
|
20
|
-
offset = clen - b.to_i
|
21
|
-
count = clen - offset
|
22
|
-
else # bytes=M-N
|
23
|
-
offset = a.to_i
|
24
|
-
count = b.to_i + 1 - offset
|
25
|
-
end
|
26
|
-
raise Rainbows::Response416 if count <= 0 || offset >= clen
|
27
|
-
count = clen if count > clen
|
28
|
-
headers[Content_Length] = count.to_s
|
29
|
-
headers[Content_Range] = "bytes #{offset}-#{offset+count-1}/#{clen}"
|
30
|
-
[ status, offset, count ]
|
31
|
-
end
|
32
|
-
# nil if no status
|
33
|
-
end
|
34
|
-
end
|
data/lib/rainbows/timed_read.rb
DELETED
@@ -1,28 +0,0 @@
|
|
1
|
-
# -*- encoding: binary -*-
|
2
|
-
# :enddoc:
|
3
|
-
module Rainbows::TimedRead
|
4
|
-
G = Rainbows::G # :nodoc:
|
5
|
-
|
6
|
-
def read_expire
|
7
|
-
Time.now + G.kato
|
8
|
-
end
|
9
|
-
|
10
|
-
def kgio_wait_readable
|
11
|
-
IO.select([self], nil, nil, G.kato)
|
12
|
-
end
|
13
|
-
|
14
|
-
# used for reading headers (respecting keepalive_timeout)
|
15
|
-
def timed_read(buf)
|
16
|
-
expire = nil
|
17
|
-
begin
|
18
|
-
case rv = kgio_tryread(16384, buf)
|
19
|
-
when :wait_readable
|
20
|
-
return if expire && expire < Time.now
|
21
|
-
expire ||= read_expire
|
22
|
-
kgio_wait_readable
|
23
|
-
else
|
24
|
-
return rv
|
25
|
-
end
|
26
|
-
end while true
|
27
|
-
end
|
28
|
-
end
|