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
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b971749285f91c7a3a1b8c6340e8e349ee3d0468
|
4
|
+
data.tar.gz: a8e7bf3756f75ceafc3c4bd9333f6885079055ae
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f5e3e727d58a0916e748c1029aeb8433623406a4e8816e24db77452bde792974f066558322a7d38b1360aaa63f5451dbf6eb4f5ef7b9ef5667e45ccd2619ff92
|
7
|
+
data.tar.gz: 7ff15b6b42d53fc040a4bd1a46382dbfbcd6ccefacf12fc266bed97f10e6b49d2f0947f64db9db8b54103710273f5dfbd576b0a505afd8ad3430e8e82eb28f7f
|
data/.gitattributes
ADDED
data/GIT-VERSION-GEN
CHANGED
data/README
CHANGED
@@ -6,18 +6,13 @@ request/response times and/or slow clients.
|
|
6
6
|
|
7
7
|
If you're on GNU/Linux and overwhelmed by options in \Rainbows!,
|
8
8
|
consider {yahns}[http://yahns.yhbt.net/] as it has fewer options
|
9
|
-
and more energy-efficient during non-peak traffic
|
9
|
+
and more energy-efficient during non-peak traffic and may also
|
10
|
+
be configured as a single worker process.
|
10
11
|
|
11
12
|
For Rack applications not heavily bound by slow external network
|
12
13
|
dependencies, consider unicorn instead as it simpler and easier to
|
13
14
|
debug.
|
14
15
|
|
15
|
-
If you're on a small system, or write extremely tight and reliable code
|
16
|
-
and don't want multiple worker processes, check out
|
17
|
-
{Zbatery}[http://zbatery.bogomip.org/], too. Zbatery can use all the
|
18
|
-
crazy network concurrency options of \Rainbows! in a single worker
|
19
|
-
process.
|
20
|
-
|
21
16
|
== \Rainbows! is about Diversity
|
22
17
|
|
23
18
|
We aim to support as many concurrency models as we can because they all
|
@@ -169,9 +164,10 @@ and we'll try our best to fix it.
|
|
169
164
|
All feedback (bug reports, user/development discussion, patches, pull
|
170
165
|
requests) go to the mailing list. Patches must be sent inline
|
171
166
|
(git format-patch -M + git send-email). No subscription is necessary
|
172
|
-
to post on the mailing list. No top posting.
|
173
|
-
the mailing list.
|
167
|
+
to post on the mailing list. No top posting.
|
174
168
|
|
175
169
|
* email: mailto:rainbows-public@bogomips.org
|
176
170
|
* subscribe: mailto:rainbows-public+subscribe@bogomips.org
|
177
171
|
* archives: http://bogomips.org/rainbows-public/
|
172
|
+
nntp://news.public-inbox.org/inbox.comp.lang.ruby.rainbows
|
173
|
+
nntp://news.gmane.org/gmane.comp.lang.ruby.rainbows.general
|
data/bin/rainbows
CHANGED
data/lib/rainbows.rb
CHANGED
@@ -11,8 +11,7 @@ module Rainbows
|
|
11
11
|
|
12
12
|
# map of numeric file descriptors to IO objects to avoid using IO.new
|
13
13
|
# and potentially causing race conditions when using /dev/fd/
|
14
|
-
FD_MAP = {}
|
15
|
-
FD_MAP.compare_by_identity if FD_MAP.respond_to?(:compare_by_identity)
|
14
|
+
FD_MAP = {}.compare_by_identity
|
16
15
|
|
17
16
|
require 'rainbows/const'
|
18
17
|
require 'rainbows/http_parser'
|
@@ -75,8 +74,8 @@ def self.at_quit(&block)
|
|
75
74
|
end
|
76
75
|
|
77
76
|
def self.tick
|
78
|
-
@worker.tick =
|
79
|
-
exit!(2) if @expire &&
|
77
|
+
@worker.tick = now.to_i
|
78
|
+
exit!(2) if @expire && now >= @expire
|
80
79
|
@alive && @server.master_pid == Process.ppid or quit!
|
81
80
|
end
|
82
81
|
|
@@ -88,11 +87,11 @@ def self.quit!
|
|
88
87
|
unless @expire
|
89
88
|
@alive = false
|
90
89
|
Rainbows::HttpParser.quit
|
91
|
-
@expire =
|
90
|
+
@expire = now + (@server.timeout * 2.0)
|
92
91
|
tmp = @readers.dup
|
93
92
|
@readers.clear
|
94
93
|
tmp.each { |s| s.close rescue nil }.clear
|
95
|
-
@at_quit.each
|
94
|
+
@at_quit.each(&:call)
|
96
95
|
|
97
96
|
# XXX hack to break out of IO.select in worker_loop for some models
|
98
97
|
Process.kill(:QUIT, $$)
|
@@ -100,6 +99,19 @@ def self.quit!
|
|
100
99
|
false
|
101
100
|
end
|
102
101
|
|
102
|
+
# try to use the monotonic clock in Ruby >= 2.1, it is immune to clock
|
103
|
+
# offset adjustments and generates less garbage (Float vs Time object)
|
104
|
+
begin
|
105
|
+
Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
106
|
+
def self.now
|
107
|
+
Process.clock_gettime(Process::CLOCK_MONOTONIC)
|
108
|
+
end
|
109
|
+
rescue NameError, NoMethodError
|
110
|
+
def self.now # Ruby <= 2.0
|
111
|
+
Time.now.to_f
|
112
|
+
end
|
113
|
+
end
|
114
|
+
|
103
115
|
autoload :Base, "rainbows/base"
|
104
116
|
autoload :WriterThreadPool, "rainbows/writer_thread_pool"
|
105
117
|
autoload :WriterThreadSpawn, "rainbows/writer_thread_spawn"
|
@@ -21,14 +21,14 @@
|
|
21
21
|
# stdout_path "/path/to/output.log"
|
22
22
|
module Rainbows::Configurator
|
23
23
|
Unicorn::Configurator::DEFAULTS.merge!({
|
24
|
-
:
|
25
|
-
:
|
26
|
-
:
|
27
|
-
:
|
28
|
-
:
|
29
|
-
:
|
30
|
-
:
|
31
|
-
|
24
|
+
use: Rainbows::Base,
|
25
|
+
worker_connections: 50,
|
26
|
+
keepalive_timeout: 5,
|
27
|
+
keepalive_requests: 100,
|
28
|
+
client_max_body_size: 1024 * 1024,
|
29
|
+
client_header_buffer_size: 1024,
|
30
|
+
client_max_header_size: 112 * 1024,
|
31
|
+
copy_stream: IO,
|
32
32
|
})
|
33
33
|
|
34
34
|
# Configures \Rainbows! with a given concurrency model to +use+ and
|
data/lib/rainbows/const.rb
CHANGED
data/lib/rainbows/coolio.rb
CHANGED
@@ -27,15 +27,10 @@
|
|
27
27
|
module Rainbows::Coolio
|
28
28
|
# :stopdoc:
|
29
29
|
# keep-alive timeout scoreboard
|
30
|
-
KATO = {}
|
30
|
+
KATO = {}.compare_by_identity
|
31
31
|
|
32
32
|
# all connected clients
|
33
|
-
CONN = {}
|
34
|
-
|
35
|
-
if {}.respond_to?(:compare_by_identity)
|
36
|
-
CONN.compare_by_identity
|
37
|
-
KATO.compare_by_identity
|
38
|
-
end
|
33
|
+
CONN = {}.compare_by_identity
|
39
34
|
|
40
35
|
autoload :Client, 'rainbows/coolio/client'
|
41
36
|
autoload :Master, 'rainbows/coolio/master'
|
@@ -122,10 +122,10 @@ def ev_write_response(status, headers, body, alive)
|
|
122
122
|
def app_call input
|
123
123
|
KATO.delete(self)
|
124
124
|
disable if enabled?
|
125
|
-
@env[
|
126
|
-
@env[REMOTE_ADDR] = @_io.kgio_addr
|
127
|
-
@env[
|
128
|
-
@hp.hijack_setup(@
|
125
|
+
@env['rack.input'] = input
|
126
|
+
@env['REMOTE_ADDR'] = @_io.kgio_addr
|
127
|
+
@env['async.callback'] = method(:write_async_response)
|
128
|
+
@hp.hijack_setup(@_io)
|
129
129
|
status, headers, body = catch(:async) {
|
130
130
|
APP.call(@env.merge!(RACK_DEFAULTS))
|
131
131
|
}
|
@@ -154,10 +154,10 @@ def on_write_complete
|
|
154
154
|
# buf == :wait_readable
|
155
155
|
unless enabled?
|
156
156
|
enable
|
157
|
-
KATO[self] =
|
157
|
+
KATO[self] = Rainbows.now
|
158
158
|
end
|
159
159
|
else
|
160
|
-
on_read(
|
160
|
+
on_read(''.freeze)
|
161
161
|
end
|
162
162
|
end
|
163
163
|
rescue => e
|
@@ -9,11 +9,11 @@ class Rainbows::Coolio::Heartbeat < Coolio::TimerWatcher
|
|
9
9
|
KATO = Rainbows::Coolio::KATO
|
10
10
|
CONN = Rainbows::Coolio::CONN
|
11
11
|
Rainbows.config!(self, :keepalive_timeout)
|
12
|
-
Rainbows.at_quit { KATO.each_key
|
12
|
+
Rainbows.at_quit { KATO.each_key(&:timeout?).clear }
|
13
13
|
|
14
14
|
def on_timer
|
15
15
|
if (ot = KEEPALIVE_TIMEOUT) >= 0
|
16
|
-
ot =
|
16
|
+
ot = Rainbows.now - ot
|
17
17
|
KATO.delete_if { |client, time| time < ot and client.timeout? }
|
18
18
|
end
|
19
19
|
exit if (! Rainbows.tick && CONN.size <= 0)
|
@@ -8,7 +8,7 @@ class Rainbows::Coolio::ThreadClient < Rainbows::Coolio::Client
|
|
8
8
|
def app_call input
|
9
9
|
KATO.delete(self)
|
10
10
|
disable if enabled?
|
11
|
-
@env[
|
11
|
+
@env['rack.input'] = input
|
12
12
|
app_dispatch # must be implemented by subclass
|
13
13
|
end
|
14
14
|
|
@@ -25,8 +25,8 @@ def response_write(response)
|
|
25
25
|
# here because that could cause a deadlock and we'd leak FDs
|
26
26
|
def app_response
|
27
27
|
begin
|
28
|
-
@env[REMOTE_ADDR] = @_io.kgio_addr
|
29
|
-
@hp.hijack_setup(@
|
28
|
+
@env['REMOTE_ADDR'] = @_io.kgio_addr
|
29
|
+
@hp.hijack_setup(@_io)
|
30
30
|
APP.call(@env.merge!(RACK_DEFAULTS))
|
31
31
|
rescue => e
|
32
32
|
Rainbows::Error.app(e) # we guarantee this does not raise
|
@@ -11,12 +11,6 @@ class Rainbows::DevFdResponse < Struct.new(:app)
|
|
11
11
|
|
12
12
|
# :stopdoc:
|
13
13
|
FD_MAP = Rainbows::FD_MAP
|
14
|
-
Content_Length = "Content-Length".freeze
|
15
|
-
Transfer_Encoding = "Transfer-Encoding".freeze
|
16
|
-
Rainbows_autochunk = "rainbows.autochunk".freeze
|
17
|
-
Rainbows_model = "rainbows.model"
|
18
|
-
HTTP_VERSION = "HTTP_VERSION"
|
19
|
-
Chunked = "chunked"
|
20
14
|
include Rack::Utils
|
21
15
|
|
22
16
|
# Rack middleware entry point, we'll just pass through responses
|
@@ -40,23 +34,23 @@ def call(env)
|
|
40
34
|
fileno = io.fileno
|
41
35
|
FD_MAP[fileno] = io
|
42
36
|
if st.file?
|
43
|
-
headers[
|
44
|
-
headers.delete(
|
37
|
+
headers['Content-Length'.freeze] ||= st.size.to_s
|
38
|
+
headers.delete('Transfer-Encoding'.freeze)
|
45
39
|
elsif st.pipe? || st.socket? # epoll-able things
|
46
|
-
unless headers.include?(
|
47
|
-
if env[
|
48
|
-
case env[HTTP_VERSION]
|
40
|
+
unless headers.include?('Content-Length'.freeze)
|
41
|
+
if env['rainbows.autochunk']
|
42
|
+
case env['HTTP_VERSION']
|
49
43
|
when "HTTP/1.0", nil
|
50
44
|
else
|
51
|
-
headers[
|
45
|
+
headers['Transfer-Encoding'.freeze] = 'chunked'
|
52
46
|
end
|
53
47
|
else
|
54
|
-
env[
|
48
|
+
env['rainbows.autochunk'] = false
|
55
49
|
end
|
56
50
|
end
|
57
51
|
|
58
52
|
# we need to make sure our pipe output is Fiber-compatible
|
59
|
-
case env[
|
53
|
+
case env['rainbows.model']
|
60
54
|
when :FiberSpawn, :FiberPool, :RevFiberSpawn, :CoolioFiberSpawn
|
61
55
|
io.respond_to?(:kgio_wait_readable) or
|
62
56
|
io = Rainbows::Fiber::IO.new(io)
|
@@ -9,15 +9,14 @@ module Rainbows::Epoll::Client
|
|
9
9
|
IN = SleepyPenguin::Epoll::IN | SleepyPenguin::Epoll::ONESHOT
|
10
10
|
OUT = SleepyPenguin::Epoll::OUT | SleepyPenguin::Epoll::ONESHOT
|
11
11
|
EPINOUT = IN | OUT
|
12
|
-
KATO = {}
|
13
|
-
|
14
|
-
Rainbows.at_quit { KATO.each_key { |k| k.timeout! }.clear }
|
12
|
+
KATO = {}.compare_by_identity
|
13
|
+
Rainbows.at_quit { KATO.each_key(&:timeout!).clear }
|
15
14
|
Rainbows.config!(self, :keepalive_timeout)
|
16
15
|
EP = Rainbows::EP
|
17
|
-
@@last_expire =
|
16
|
+
@@last_expire = Rainbows.now
|
18
17
|
|
19
18
|
def self.expire
|
20
|
-
return if ((now =
|
19
|
+
return if ((now = Rainbows.now) - @@last_expire) < 1.0
|
21
20
|
if (ot = KEEPALIVE_TIMEOUT) >= 0
|
22
21
|
ot = now - ot
|
23
22
|
KATO.delete_if { |client, time| time < ot and client.timeout! }
|
@@ -63,9 +62,9 @@ def on_readable
|
|
63
62
|
end
|
64
63
|
|
65
64
|
def app_call input # called by on_read()
|
66
|
-
@env[
|
67
|
-
@env[REMOTE_ADDR] = kgio_addr
|
68
|
-
@hp.hijack_setup(
|
65
|
+
@env['rack.input'] = input
|
66
|
+
@env['REMOTE_ADDR'] = kgio_addr
|
67
|
+
@hp.hijack_setup(self)
|
69
68
|
status, headers, body = APP.call(@env.merge!(RACK_DEFAULTS))
|
70
69
|
return hijacked if @hp.hijacked?
|
71
70
|
ev_write_response(status, headers, body, @hp.next?)
|
@@ -93,7 +92,7 @@ def stream_response_body(body, io, chunk)
|
|
93
92
|
Rainbows::Epoll::ResponsePipe).new(io, self, body)
|
94
93
|
return @wr_queue << pipe if @wr_queue[0]
|
95
94
|
stream_pipe(pipe) or return
|
96
|
-
@wr_queue[0] or @wr_queue <<
|
95
|
+
@wr_queue[0] or @wr_queue << ''.freeze
|
97
96
|
end
|
98
97
|
|
99
98
|
def ev_write_response(status, headers, body, alive)
|
@@ -120,7 +119,7 @@ def next_request
|
|
120
119
|
want_more
|
121
120
|
else
|
122
121
|
# pipelined request (already in buffer)
|
123
|
-
on_read(
|
122
|
+
on_read(''.freeze)
|
124
123
|
return if @wr_queue[0] || closed?
|
125
124
|
return hijacked if @hp.hijacked?
|
126
125
|
close if :close == @state
|
data/lib/rainbows/error.rb
CHANGED
@@ -28,11 +28,11 @@ def self.response(e)
|
|
28
28
|
Errno::EBADF, Errno::ENOTCONN, Errno::ETIMEDOUT, Errno::EHOSTUNREACH
|
29
29
|
# swallow error if client shuts down one end or disconnects
|
30
30
|
when Unicorn::HttpParserError
|
31
|
-
|
31
|
+
"HTTP/1.1 400 Bad Request\r\n\r\n" # try to tell the client they're bad
|
32
32
|
when IOError # HttpParserError is an IOError
|
33
33
|
else
|
34
34
|
app(e)
|
35
|
-
|
35
|
+
"HTTP/1.1 500 Internal Server Error\r\n\r\n"
|
36
36
|
end
|
37
37
|
end
|
38
38
|
end
|
data/lib/rainbows/ev_core.rb
CHANGED
@@ -8,13 +8,9 @@ module Rainbows::EvCore
|
|
8
8
|
HttpParser = Rainbows::HttpParser
|
9
9
|
autoload :CapInput, 'rainbows/ev_core/cap_input'
|
10
10
|
RBUF = ""
|
11
|
-
Z = "".freeze
|
12
11
|
Rainbows.config!(self, :client_header_buffer_size)
|
13
|
-
HTTP_VERSION = "HTTP_VERSION"
|
14
12
|
|
15
13
|
# Apps may return this Rack response: AsyncResponse = [ -1, {}, [] ]
|
16
|
-
ASYNC_CALLBACK = "async.callback".freeze
|
17
|
-
ASYNC_CLOSE = "async.close".freeze
|
18
14
|
|
19
15
|
def write_async_response(response)
|
20
16
|
status, headers, body = response
|
@@ -23,8 +19,8 @@ def write_async_response(response)
|
|
23
19
|
# "Transfer-Encoding: chunked", and the async.callback stuff
|
24
20
|
# isn't Rack::Lint-compatible, so we have to enforce it here.
|
25
21
|
headers = Rack::Utils::HeaderHash.new(headers) unless Hash === headers
|
26
|
-
alive = headers.include?(
|
27
|
-
!!(%r{\Achunked\z}i =~ headers[
|
22
|
+
alive = headers.include?('Content-Length'.freeze) ||
|
23
|
+
!!(%r{\Achunked\z}i =~ headers['Transfer-Encoding'.freeze])
|
28
24
|
end
|
29
25
|
@deferred = nil
|
30
26
|
ev_write_response(status, headers, body, alive)
|
@@ -55,12 +51,12 @@ def handle_error(e)
|
|
55
51
|
# returns nil if request was hijacked in response stage
|
56
52
|
def stream_response_headers(status, headers, alive, body)
|
57
53
|
headers = Rack::Utils::HeaderHash.new(headers) unless Hash === headers
|
58
|
-
if headers.include?(
|
54
|
+
if headers.include?('Content-Length'.freeze)
|
59
55
|
write_headers(status, headers, alive, body) or return
|
60
56
|
return false
|
61
57
|
end
|
62
58
|
|
63
|
-
case @env[HTTP_VERSION]
|
59
|
+
case @env['HTTP_VERSION']
|
64
60
|
when "HTTP/1.0" # disable HTTP/1.0 keepalive to stream
|
65
61
|
write_headers(status, headers, false, body) or return
|
66
62
|
@hp.clear
|
@@ -68,7 +64,7 @@ def stream_response_headers(status, headers, alive, body)
|
|
68
64
|
when nil # "HTTP/0.9"
|
69
65
|
false
|
70
66
|
else
|
71
|
-
rv = !!(headers[
|
67
|
+
rv = !!(headers['Transfer-Encoding'] =~ %r{\Achunked\z}i)
|
72
68
|
rv = false unless @env["rainbows.autochunk"]
|
73
69
|
write_headers(status, headers, alive, body) or return
|
74
70
|
rv
|
@@ -78,14 +74,14 @@ def stream_response_headers(status, headers, alive, body)
|
|
78
74
|
def prepare_request_body
|
79
75
|
# since we don't do streaming input, we have no choice but
|
80
76
|
# to take over 100-continue handling from the Rack application
|
81
|
-
if @env[HTTP_EXPECT] =~ /\A100-continue\z/i
|
82
|
-
write(
|
83
|
-
@env.delete(HTTP_EXPECT)
|
77
|
+
if @env['HTTP_EXPECT'] =~ /\A100-continue\z/i
|
78
|
+
write("HTTP/1.1 100 Continue\r\n\r\n".freeze)
|
79
|
+
@env.delete('HTTP_EXPECT'.freeze)
|
84
80
|
end
|
85
81
|
@input = mkinput
|
86
82
|
@hp.filter_body(@buf2 = "", @buf)
|
87
83
|
@input << @buf2
|
88
|
-
on_read(
|
84
|
+
on_read(''.freeze)
|
89
85
|
end
|
90
86
|
|
91
87
|
# TeeInput doesn't map too well to this right now...
|
@@ -111,7 +107,7 @@ def on_read(data)
|
|
111
107
|
elsif data.size > 0
|
112
108
|
@hp.filter_body(@buf2, @buf << data)
|
113
109
|
@input << @buf2
|
114
|
-
on_read(
|
110
|
+
on_read(''.freeze)
|
115
111
|
else
|
116
112
|
want_more
|
117
113
|
end
|
@@ -127,10 +123,8 @@ def on_read(data)
|
|
127
123
|
handle_error(e)
|
128
124
|
end
|
129
125
|
|
130
|
-
ERROR_413_RESPONSE = "HTTP/1.1 413 Request Entity Too Large\r\n\r\n"
|
131
|
-
|
132
126
|
def err_413(msg)
|
133
|
-
write(
|
127
|
+
write("HTTP/1.1 413 Request Entity Too Large\r\n\r\n".freeze)
|
134
128
|
quit
|
135
129
|
# zip back up the stack
|
136
130
|
raise IOError, msg, []
|
@@ -23,7 +23,7 @@ def receive_data(data)
|
|
23
23
|
end
|
24
24
|
EM.next_tick { receive_data(nil) } unless @buf.empty?
|
25
25
|
else
|
26
|
-
on_read(data ||
|
26
|
+
on_read(data || ''.freeze) if (@buf.size > 0) || data
|
27
27
|
end
|
28
28
|
end
|
29
29
|
|
@@ -34,11 +34,11 @@ def quit
|
|
34
34
|
|
35
35
|
def app_call input
|
36
36
|
set_comm_inactivity_timeout 0
|
37
|
-
@env[
|
38
|
-
@env[REMOTE_ADDR] = @_io.kgio_addr
|
39
|
-
@env[
|
40
|
-
@env[
|
41
|
-
@hp.hijack_setup(@
|
37
|
+
@env['rack.input'] = input
|
38
|
+
@env['REMOTE_ADDR'] = @_io.kgio_addr
|
39
|
+
@env['async.callback'] = method(:write_async_response)
|
40
|
+
@env['async.close'] = EM::DefaultDeferrable.new
|
41
|
+
@hp.hijack_setup(@_io)
|
42
42
|
status, headers, body = catch(:async) {
|
43
43
|
APP.call(@env.merge!(RACK_DEFAULTS))
|
44
44
|
}
|
@@ -117,7 +117,7 @@ def next!
|
|
117
117
|
|
118
118
|
def unbind
|
119
119
|
return if @hp.hijacked?
|
120
|
-
async_close = @env[
|
120
|
+
async_close = @env['async.close'] and async_close.succeed
|
121
121
|
@deferred.respond_to?(:fail) and @deferred.fail
|
122
122
|
begin
|
123
123
|
@_io.close
|