rainbows 4.7.0 → 5.0.0
Sign up to get free protection for your applications and to get access to all the features.
- 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"
|