rainbows 4.7.0 → 5.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.
- checksums.yaml +4 -4
- data/.gitattributes +5 -0
- data/GIT-VERSION-GEN +1 -1
- data/README +5 -9
- data/bin/rainbows +3 -3
- data/lib/rainbows.rb +18 -6
- data/lib/rainbows/configurator.rb +8 -8
- data/lib/rainbows/const.rb +0 -3
- data/lib/rainbows/coolio.rb +2 -7
- data/lib/rainbows/coolio/client.rb +6 -6
- data/lib/rainbows/coolio/heartbeat.rb +2 -2
- data/lib/rainbows/coolio/thread_client.rb +3 -3
- data/lib/rainbows/dev_fd_response.rb +8 -14
- data/lib/rainbows/epoll/client.rb +9 -10
- data/lib/rainbows/error.rb +2 -2
- data/lib/rainbows/ev_core.rb +11 -17
- data/lib/rainbows/event_machine/client.rb +7 -7
- data/lib/rainbows/event_machine/try_defer.rb +1 -4
- data/lib/rainbows/fiber.rb +1 -1
- data/lib/rainbows/fiber/base.rb +3 -3
- data/lib/rainbows/fiber/coolio/heartbeat.rb +1 -1
- data/lib/rainbows/fiber/io.rb +1 -1
- data/lib/rainbows/http_parser.rb +24 -0
- data/lib/rainbows/http_server.rb +5 -4
- data/lib/rainbows/join_threads.rb +2 -2
- data/lib/rainbows/max_body.rb +4 -9
- data/lib/rainbows/process_client.rb +11 -12
- data/lib/rainbows/response.rb +20 -37
- data/lib/rainbows/revactor.rb +0 -1
- data/lib/rainbows/revactor/client.rb +2 -3
- data/lib/rainbows/revactor/proxy.rb +1 -1
- data/lib/rainbows/reverse_proxy.rb +9 -19
- data/lib/rainbows/reverse_proxy/coolio.rb +3 -3
- data/lib/rainbows/reverse_proxy/ev_client.rb +2 -5
- data/lib/rainbows/reverse_proxy/event_machine.rb +1 -1
- data/lib/rainbows/sendfile.rb +3 -9
- data/lib/rainbows/server_token.rb +1 -6
- data/lib/rainbows/stream_response_epoll.rb +8 -9
- data/lib/rainbows/thread_timeout.rb +4 -4
- data/lib/rainbows/writer_thread_pool.rb +2 -2
- data/lib/rainbows/xepoll_thread_pool/client.rb +3 -4
- data/lib/rainbows/xepoll_thread_spawn/client.rb +3 -4
- data/rainbows.gemspec +1 -1
- data/t/t0105-rack-input-limit-bigger.sh +10 -2
- data/t/test_isolate.rb +1 -1
- metadata +5 -4
@@ -32,20 +32,20 @@ def on_readable
|
|
32
32
|
when :wait_readable
|
33
33
|
return
|
34
34
|
when nil
|
35
|
-
@env[
|
35
|
+
@env['async.callback'].call(@response)
|
36
36
|
return close
|
37
37
|
end while true # we always read until EAGAIN or EOF
|
38
38
|
|
39
39
|
rescue => e
|
40
40
|
case e
|
41
41
|
when Errno::ECONNRESET
|
42
|
-
@env[
|
42
|
+
@env['async.callback'].call(@response)
|
43
43
|
return close
|
44
44
|
when SystemCallError
|
45
45
|
else
|
46
46
|
Unicorn.log_error(@env["rack.logger"], "on_readable", e)
|
47
47
|
end
|
48
|
-
@env[
|
48
|
+
@env['async.callback'].call(Rainbows::ReverseProxy::E502)
|
49
49
|
close
|
50
50
|
end
|
51
51
|
end
|
@@ -3,18 +3,15 @@
|
|
3
3
|
require 'tempfile'
|
4
4
|
module Rainbows::ReverseProxy::EvClient
|
5
5
|
include Rainbows::ReverseProxy::Synchronous
|
6
|
-
AsyncCallback = "async.callback"
|
7
6
|
CBB = Unicorn::TeeInput.client_body_buffer_size
|
8
|
-
Content_Length = "Content-Length"
|
9
|
-
Transfer_Encoding = "Transfer-Encoding"
|
10
7
|
|
11
8
|
def receive_data(buf)
|
12
9
|
if @body
|
13
10
|
@body << buf
|
14
11
|
else
|
15
12
|
response = @parser.headers(@headers, @rbuf << buf) or return
|
16
|
-
if (cl = @headers[
|
17
|
-
(%r{\bchunked\b} =~ @headers[
|
13
|
+
if (cl = @headers['Content-Length'.freeze] && cl.to_i > CBB) ||
|
14
|
+
(%r{\bchunked\b} =~ @headers['Transfer-Encoding'.freeze])
|
18
15
|
@body = LargeBody.new("")
|
19
16
|
@body << @rbuf
|
20
17
|
@response = response << @body
|
data/lib/rainbows/sendfile.rb
CHANGED
@@ -52,12 +52,10 @@ class Rainbows::Sendfile < Struct.new(:app)
|
|
52
52
|
# +each+ in case a given concurrency model does not optimize
|
53
53
|
# +to_path+ calls.
|
54
54
|
class Body < Struct.new(:to_path) # :nodoc: all
|
55
|
-
CONTENT_LENGTH = 'Content-Length'.freeze
|
56
|
-
|
57
55
|
def self.new(path, headers)
|
58
|
-
unless headers[
|
56
|
+
unless headers['Content-Length'.freeze]
|
59
57
|
stat = File.stat(path)
|
60
|
-
headers[
|
58
|
+
headers['Content-Length'.freeze] = stat.size.to_s if stat.file?
|
61
59
|
end
|
62
60
|
super(path)
|
63
61
|
end
|
@@ -71,14 +69,10 @@ def each
|
|
71
69
|
end
|
72
70
|
end
|
73
71
|
|
74
|
-
# :stopdoc:
|
75
|
-
X_SENDFILE = 'X-Sendfile'
|
76
|
-
# :startdoc:
|
77
|
-
|
78
72
|
def call(env) # :nodoc:
|
79
73
|
status, headers, body = app.call(env)
|
80
74
|
headers = Rack::Utils::HeaderHash.new(headers) unless Hash === headers
|
81
|
-
if path = headers.delete(
|
75
|
+
if path = headers.delete('X-Sendfile'.freeze)
|
82
76
|
body = Body.new(path, headers) unless body.respond_to?(:to_path)
|
83
77
|
end
|
84
78
|
[ status, headers, body ]
|
@@ -19,11 +19,6 @@ module Rainbows
|
|
19
19
|
|
20
20
|
class ServerToken < Struct.new(:app, :token)
|
21
21
|
|
22
|
-
# :stopdoc:
|
23
|
-
#
|
24
|
-
# Freeze constants as they're slightly faster when setting hashes
|
25
|
-
SERVER = "Server".freeze
|
26
|
-
|
27
22
|
def initialize(app, token = Const::RACK_DEFAULTS['SERVER_SOFTWARE'])
|
28
23
|
super
|
29
24
|
end
|
@@ -31,7 +26,7 @@ def initialize(app, token = Const::RACK_DEFAULTS['SERVER_SOFTWARE'])
|
|
31
26
|
def call(env)
|
32
27
|
status, headers, body = app.call(env)
|
33
28
|
headers = Rack::Utils::HeaderHash.new(headers) unless Hash === headers
|
34
|
-
headers[
|
29
|
+
headers['Server'.freeze] = token
|
35
30
|
[ status, headers, body ]
|
36
31
|
end
|
37
32
|
# :startdoc:
|
@@ -20,33 +20,32 @@
|
|
20
20
|
# * sleepy_penguin 3.0.1 or later
|
21
21
|
module Rainbows::StreamResponseEpoll
|
22
22
|
# :stopdoc:
|
23
|
-
CODES = Unicorn::HttpResponse::CODES
|
24
|
-
HEADER_END = "X-Accel-Buffering: no\r\n\r\n"
|
25
23
|
autoload :Client, "rainbows/stream_response_epoll/client"
|
26
24
|
|
27
25
|
def http_response_write(socket, status, headers, body)
|
28
|
-
status = CODES[status.to_i] || status
|
29
26
|
hijack = ep_client = false
|
30
27
|
|
31
28
|
if headers
|
32
29
|
# don't set extra headers here, this is only intended for
|
33
30
|
# consuming by nginx.
|
34
|
-
|
31
|
+
code = status.to_i
|
32
|
+
msg = Rack::Utils::HTTP_STATUS_CODES[code]
|
33
|
+
buf = "HTTP/1.0 #{msg ? %Q(#{code} #{msg}) : status}\r\n"
|
35
34
|
headers.each do |key, value|
|
36
35
|
case key
|
37
36
|
when "rack.hijack"
|
38
|
-
hijack =
|
37
|
+
hijack = value
|
39
38
|
body = nil # ensure we do not close body
|
40
39
|
else
|
41
40
|
if /\n/ =~ value
|
42
41
|
# avoiding blank, key-only cookies with /\n+/
|
43
|
-
|
42
|
+
value.split(/\n+/).each { |v| buf << "#{key}: #{v}\r\n" }
|
44
43
|
else
|
45
44
|
buf << "#{key}: #{value}\r\n"
|
46
45
|
end
|
47
46
|
end
|
48
47
|
end
|
49
|
-
buf <<
|
48
|
+
buf << "X-Accel-Buffering: no\r\n\r\n".freeze
|
50
49
|
|
51
50
|
case rv = socket.kgio_trywrite(buf)
|
52
51
|
when nil then break
|
@@ -101,8 +100,8 @@ def process_client(client)
|
|
101
100
|
status, headers, body = @app.call(env = @request.read(client))
|
102
101
|
|
103
102
|
if 100 == status.to_i
|
104
|
-
client.write(
|
105
|
-
env.delete(
|
103
|
+
client.write("HTTP/1.1 100 Continue\r\n\r\n".freeze)
|
104
|
+
env.delete('HTTP_EXPECT'.freeze)
|
106
105
|
status, headers, body = @app.call(env)
|
107
106
|
end
|
108
107
|
@request.headers? or headers = nil
|
@@ -63,7 +63,7 @@ class Rainbows::ThreadTimeout
|
|
63
63
|
|
64
64
|
# The MRI 1.8 won't be usable in January 2038, we'll raise this
|
65
65
|
# when we eventually drop support for 1.8 (before 2038, hopefully)
|
66
|
-
NEVER =
|
66
|
+
NEVER = 0x7fffffff
|
67
67
|
|
68
68
|
def initialize(app, opts)
|
69
69
|
# @timeout must be Numeric since we add this to Time
|
@@ -114,7 +114,7 @@ def call(env)
|
|
114
114
|
# is hopeless and we might as well just die anyways.
|
115
115
|
# initialize guarantees @timeout will be Numeric
|
116
116
|
start_watchdog(env) unless @watchdog
|
117
|
-
@active[Thread.current] =
|
117
|
+
@active[Thread.current] = Rainbows.now + @timeout
|
118
118
|
|
119
119
|
begin
|
120
120
|
# It is important to unlock inside this begin block
|
@@ -162,7 +162,7 @@ def start_watchdog(env)
|
|
162
162
|
# that are about to release themselves from the eye of the
|
163
163
|
# watchdog thread.
|
164
164
|
@lock.synchronize do
|
165
|
-
now =
|
165
|
+
now = Rainbows.now
|
166
166
|
@active.delete_if do |thread, expire_at|
|
167
167
|
# We also use this loop to get the maximum possible time to
|
168
168
|
# sleep for if we're not killing the thread.
|
@@ -184,7 +184,7 @@ def start_watchdog(env)
|
|
184
184
|
sleep(@timeout)
|
185
185
|
else
|
186
186
|
# sleep until the next known thread is about to expire.
|
187
|
-
sec = next_expiry -
|
187
|
+
sec = next_expiry - Rainbows.now
|
188
188
|
sec > 0.0 ? sleep(sec) : Thread.pass # give other threads a chance
|
189
189
|
end
|
190
190
|
rescue => e
|
@@ -38,15 +38,14 @@ def self.app_run(queue)
|
|
38
38
|
ep = SleepyPenguin::Epoll
|
39
39
|
EP = ep.new
|
40
40
|
IN = ep::IN | ep::ONESHOT
|
41
|
-
KATO = {}
|
42
|
-
KATO.compare_by_identity if KATO.respond_to?(:compare_by_identity)
|
41
|
+
KATO = {}.compare_by_identity
|
43
42
|
LOCK = Mutex.new
|
44
43
|
Rainbows.at_quit do
|
45
44
|
clients = nil
|
46
45
|
LOCK.synchronize { clients = KATO.keys; KATO.clear }
|
47
46
|
clients.each { |io| io.closed? or io.close }
|
48
47
|
end
|
49
|
-
@@last_expire =
|
48
|
+
@@last_expire = Rainbows.now
|
50
49
|
|
51
50
|
def kato_set
|
52
51
|
LOCK.synchronize { KATO[self] = @@last_expire }
|
@@ -70,7 +69,7 @@ def self.loop
|
|
70
69
|
end
|
71
70
|
|
72
71
|
def self.expire
|
73
|
-
return if ((now =
|
72
|
+
return if ((now = Rainbows.now) - @@last_expire) < 1.0
|
74
73
|
if (ot = KEEPALIVE_TIMEOUT) >= 0
|
75
74
|
ot = now - ot
|
76
75
|
defer = []
|
@@ -27,15 +27,14 @@ def self.included(klass) # included in Rainbows::Client
|
|
27
27
|
ep = SleepyPenguin::Epoll
|
28
28
|
EP = ep.new
|
29
29
|
IN = ep::IN | ep::ONESHOT
|
30
|
-
KATO = {}
|
31
|
-
KATO.compare_by_identity if KATO.respond_to?(:compare_by_identity)
|
30
|
+
KATO = {}.compare_by_identity
|
32
31
|
LOCK = Mutex.new
|
33
32
|
Rainbows.at_quit do
|
34
33
|
clients = nil
|
35
34
|
LOCK.synchronize { clients = KATO.keys; KATO.clear }
|
36
35
|
clients.each { |io| io.closed? or io.shutdown }
|
37
36
|
end
|
38
|
-
@@last_expire =
|
37
|
+
@@last_expire = Rainbows.now
|
39
38
|
|
40
39
|
def kato_set
|
41
40
|
LOCK.synchronize { KATO[self] = @@last_expire }
|
@@ -59,7 +58,7 @@ def self.loop
|
|
59
58
|
end
|
60
59
|
|
61
60
|
def self.expire
|
62
|
-
return if ((now =
|
61
|
+
return if ((now = Rainbows.now) - @@last_expire) < 1.0
|
63
62
|
if (ot = KEEPALIVE_TIMEOUT) >= 0
|
64
63
|
ot = now - ot
|
65
64
|
defer = []
|
data/rainbows.gemspec
CHANGED
@@ -27,7 +27,7 @@
|
|
27
27
|
# we need unicorn for the HTTP parser and process management
|
28
28
|
# we need unicorn 4.8.0+ since we depend on undocumented/unsupported
|
29
29
|
# unicorn internals.
|
30
|
-
s.add_dependency(%q<unicorn>, ["~>
|
30
|
+
s.add_dependency(%q<unicorn>, ["~> 5.0"])
|
31
31
|
|
32
32
|
s.add_development_dependency(%q<isolate>, "~> 3.1")
|
33
33
|
s.add_development_dependency(%q<olddoc>, "~> 1.0")
|
@@ -25,7 +25,11 @@ t_begin "stops a regular request" && {
|
|
25
25
|
rm -f $tmp
|
26
26
|
dbgcat curl_err
|
27
27
|
dbgcat curl_out
|
28
|
-
grep 413 $curl_err
|
28
|
+
if ! grep 413 $curl_err
|
29
|
+
then
|
30
|
+
# send error as documented in curl(1) manpage
|
31
|
+
grep -F '(55)' $curl_err
|
32
|
+
fi
|
29
33
|
test -e $ok
|
30
34
|
}
|
31
35
|
|
@@ -36,7 +40,11 @@ t_begin "stops a large chunked request" && {
|
|
36
40
|
http://$listen/ > $curl_out 2> $curl_err || > $ok
|
37
41
|
dbgcat curl_err
|
38
42
|
dbgcat curl_out
|
39
|
-
grep 413 $curl_err
|
43
|
+
if ! grep 413 $curl_err
|
44
|
+
then
|
45
|
+
# send error as documented in curl(1) manpage
|
46
|
+
grep -F '(55)' $curl_err
|
47
|
+
fi
|
40
48
|
test -e $ok
|
41
49
|
}
|
42
50
|
|
data/t/test_isolate.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: rainbows
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version:
|
4
|
+
version: 5.0.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Rainbows! hackers
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-11-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rack
|
@@ -44,14 +44,14 @@ dependencies:
|
|
44
44
|
requirements:
|
45
45
|
- - "~>"
|
46
46
|
- !ruby/object:Gem::Version
|
47
|
-
version: '
|
47
|
+
version: '5.0'
|
48
48
|
type: :runtime
|
49
49
|
prerelease: false
|
50
50
|
version_requirements: !ruby/object:Gem::Requirement
|
51
51
|
requirements:
|
52
52
|
- - "~>"
|
53
53
|
- !ruby/object:Gem::Version
|
54
|
-
version: '
|
54
|
+
version: '5.0'
|
55
55
|
- !ruby/object:Gem::Dependency
|
56
56
|
name: isolate
|
57
57
|
requirement: !ruby/object:Gem::Requirement
|
@@ -139,6 +139,7 @@ extra_rdoc_files:
|
|
139
139
|
- HACKING
|
140
140
|
files:
|
141
141
|
- ".document"
|
142
|
+
- ".gitattributes"
|
142
143
|
- ".gitignore"
|
143
144
|
- ".manifest"
|
144
145
|
- ".olddoc.yml"
|