* [WIP 0/5] updates for unicorn 5 internal changes
@ 2015-11-14 2:47 Eric Wong
2015-11-14 2:47 ` [PATCH 1/5] http_parser: handle keepalive_requests internally Eric Wong
` (4 more replies)
0 siblings, 5 replies; 6+ messages in thread
From: Eric Wong @ 2015-11-14 2:47 UTC (permalink / raw)
To: rainbows-public
Only passes tests (using unicorn 4.x) so far. There is likely
more to do, but just publishing these changes early to give
folks some time to look at them over the weekend.
lib/rainbows/const.rb | 3 --
lib/rainbows/coolio/client.rb | 10 +++----
lib/rainbows/coolio/thread_client.rb | 6 ++--
lib/rainbows/dev_fd_response.rb | 22 ++++++--------
lib/rainbows/epoll/client.rb | 10 +++----
lib/rainbows/error.rb | 4 +--
lib/rainbows/ev_core.rb | 28 +++++++-----------
lib/rainbows/event_machine/client.rb | 14 ++++-----
lib/rainbows/event_machine/try_defer.rb | 5 +---
lib/rainbows/http_parser.rb | 24 ++++++++++++++++
lib/rainbows/http_server.rb | 4 +--
lib/rainbows/max_body.rb | 13 +++------
lib/rainbows/process_client.rb | 19 ++++++------
lib/rainbows/response.rb | 51 +++++++++++----------------------
lib/rainbows/reverse_proxy.rb | 28 ++++++------------
lib/rainbows/reverse_proxy/ev_client.rb | 7 ++---
lib/rainbows/sendfile.rb | 12 ++------
lib/rainbows/server_token.rb | 7 +----
lib/rainbows/stream_response_epoll.rb | 13 ++++-----
19 files changed, 119 insertions(+), 161 deletions(-)
[PATCH 1/5] http_parser: handle keepalive_requests internally
[PATCH 2/5] kill the moronic Status: header
[PATCH 3/5] reflect changes in Rack::Utils::HTTP_STATUS_CODES
[PATCH 4/5] reduce constant lookup dependencies
[PATCH 5/5] http_parser: workaround hijack changes in unicorn 5
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH 1/5] http_parser: handle keepalive_requests internally
2015-11-14 2:47 [WIP 0/5] updates for unicorn 5 internal changes Eric Wong
@ 2015-11-14 2:47 ` Eric Wong
2015-11-14 2:47 ` [PATCH 2/5] kill the moronic Status: header Eric Wong
` (3 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Eric Wong @ 2015-11-14 2:47 UTC (permalink / raw)
To: rainbows-public
unicorn 5 dropped support for this, essentially allowing unlimited
persistent connections if we used the parser as-is.
Since most of our concurrency models cannot handle infinite
persistent connections without being vulnerable to DoS,
we must support keepalive_requests like nginx does.
---
lib/rainbows/http_parser.rb | 15 +++++++++++++++
lib/rainbows/http_server.rb | 4 ++--
2 files changed, 17 insertions(+), 2 deletions(-)
diff --git a/lib/rainbows/http_parser.rb b/lib/rainbows/http_parser.rb
index ec55fe9..30a67cb 100644
--- a/lib/rainbows/http_parser.rb
+++ b/lib/rainbows/http_parser.rb
@@ -2,6 +2,21 @@
# :enddoc:
# avoid modifying Unicorn::HttpParser
class Rainbows::HttpParser < Unicorn::HttpParser
+ @keepalive_requests = 100
+ class << self
+ attr_accessor :keepalive_requests
+ end
+
+ def initialize(*args)
+ @keepalive_requests = self.class.keepalive_requests
+ super
+ end
+
+ def next?
+ return false if (@keepalive_requests -= 1) <= 0
+ super
+ end
+
def self.quit
alias_method :next?, :never!
end
diff --git a/lib/rainbows/http_server.rb b/lib/rainbows/http_server.rb
index 637710d..09f2589 100644
--- a/lib/rainbows/http_server.rb
+++ b/lib/rainbows/http_server.rb
@@ -92,11 +92,11 @@ class Rainbows::HttpServer < Unicorn::HttpServer
end
def keepalive_requests=(nr)
- Unicorn::HttpRequest.keepalive_requests = nr
+ Rainbows::HttpParser.keepalive_requests = nr
end
def keepalive_requests
- Unicorn::HttpRequest.keepalive_requests
+ Rainbows::HttpParser.keepalive_requests
end
def client_max_header_size=(bytes)
--
EW
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 2/5] kill the moronic Status: header
2015-11-14 2:47 [WIP 0/5] updates for unicorn 5 internal changes Eric Wong
2015-11-14 2:47 ` [PATCH 1/5] http_parser: handle keepalive_requests internally Eric Wong
@ 2015-11-14 2:47 ` Eric Wong
2015-11-14 2:47 ` [PATCH 3/5] reflect changes in Rack::Utils::HTTP_STATUS_CODES Eric Wong
` (2 subsequent siblings)
4 siblings, 0 replies; 6+ messages in thread
From: Eric Wong @ 2015-11-14 2:47 UTC (permalink / raw)
To: rainbows-public
Whatever compatibility reasons which existed in 2009 likely do not exist
now. Other servers (e.g. thin, puma) seem to work alright without it,
so there's no reason to waste precious bytes.
---
lib/rainbows/response.rb | 3 +--
lib/rainbows/stream_response_epoll.rb | 2 +-
2 files changed, 2 insertions(+), 3 deletions(-)
diff --git a/lib/rainbows/response.rb b/lib/rainbows/response.rb
index b7b6aa8..db14ee4 100644
--- a/lib/rainbows/response.rb
+++ b/lib/rainbows/response.rb
@@ -42,8 +42,7 @@ module Rainbows::Response
hijack = nil
status = CODES[status.to_i] || status
buf = "HTTP/1.1 #{status}\r\n" \
- "Date: #{httpdate}\r\n" \
- "Status: #{status}\r\n"
+ "Date: #{httpdate}\r\n"
headers.each do |key, value|
case key
when %r{\A(?:Date\z|Connection\z)}i
diff --git a/lib/rainbows/stream_response_epoll.rb b/lib/rainbows/stream_response_epoll.rb
index 33d7386..c0d90a4 100644
--- a/lib/rainbows/stream_response_epoll.rb
+++ b/lib/rainbows/stream_response_epoll.rb
@@ -31,7 +31,7 @@ module Rainbows::StreamResponseEpoll
if headers
# don't set extra headers here, this is only intended for
# consuming by nginx.
- buf = "HTTP/1.0 #{status}\r\nStatus: #{status}\r\n"
+ buf = "HTTP/1.0 #{status}\r\n"
headers.each do |key, value|
case key
when "rack.hijack"
--
EW
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 3/5] reflect changes in Rack::Utils::HTTP_STATUS_CODES
2015-11-14 2:47 [WIP 0/5] updates for unicorn 5 internal changes Eric Wong
2015-11-14 2:47 ` [PATCH 1/5] http_parser: handle keepalive_requests internally Eric Wong
2015-11-14 2:47 ` [PATCH 2/5] kill the moronic Status: header Eric Wong
@ 2015-11-14 2:47 ` Eric Wong
2015-11-14 2:47 ` [PATCH 4/5] reduce constant lookup dependencies Eric Wong
2015-11-14 2:47 ` [PATCH 5/5] http_parser: workaround hijack changes in unicorn 5 Eric Wong
4 siblings, 0 replies; 6+ messages in thread
From: Eric Wong @ 2015-11-14 2:47 UTC (permalink / raw)
To: rainbows-public
Applications may want to alter the message associated with HTTP
status codes in Rack::Utils::HTTP_STATUS_CODES. Avoid memoizing
status lines ahead-of-time
Note: this introduces a minor performance regression, but ought to
be unnoticeable unless you're running "Hello world"-type apps.
---
lib/rainbows/response.rb | 5 +++--
lib/rainbows/stream_response_epoll.rb | 6 +++---
2 files changed, 6 insertions(+), 5 deletions(-)
diff --git a/lib/rainbows/response.rb b/lib/rainbows/response.rb
index db14ee4..a661ab6 100644
--- a/lib/rainbows/response.rb
+++ b/lib/rainbows/response.rb
@@ -40,8 +40,9 @@ module Rainbows::Response
def write_headers(status, headers, alive, body)
@hp.headers? or return body
hijack = nil
- status = CODES[status.to_i] || status
- buf = "HTTP/1.1 #{status}\r\n" \
+ code = status.to_i
+ msg = Rack::Utils::HTTP_STATUS_CODES[code]
+ buf = "HTTP/1.1 #{msg ? %Q(#{code} #{msg}) : status}\r\n" \
"Date: #{httpdate}\r\n"
headers.each do |key, value|
case key
diff --git a/lib/rainbows/stream_response_epoll.rb b/lib/rainbows/stream_response_epoll.rb
index c0d90a4..1f32dcc 100644
--- a/lib/rainbows/stream_response_epoll.rb
+++ b/lib/rainbows/stream_response_epoll.rb
@@ -20,18 +20,18 @@ require "raindrops"
# * sleepy_penguin 3.0.1 or later
module Rainbows::StreamResponseEpoll
# :stopdoc:
- CODES = Unicorn::HttpResponse::CODES
HEADER_END = "X-Accel-Buffering: no\r\n\r\n"
autoload :Client, "rainbows/stream_response_epoll/client"
def http_response_write(socket, status, headers, body)
- status = CODES[status.to_i] || status
hijack = ep_client = false
if headers
# don't set extra headers here, this is only intended for
# consuming by nginx.
- buf = "HTTP/1.0 #{status}\r\n"
+ code = status.to_i
+ msg = Rack::Utils::HTTP_STATUS_CODES[code]
+ buf = "HTTP/1.0 #{msg ? %Q(#{code} #{msg}) : status}\r\n"
headers.each do |key, value|
case key
when "rack.hijack"
--
EW
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 4/5] reduce constant lookup dependencies
2015-11-14 2:47 [WIP 0/5] updates for unicorn 5 internal changes Eric Wong
` (2 preceding siblings ...)
2015-11-14 2:47 ` [PATCH 3/5] reflect changes in Rack::Utils::HTTP_STATUS_CODES Eric Wong
@ 2015-11-14 2:47 ` Eric Wong
2015-11-14 2:47 ` [PATCH 5/5] http_parser: workaround hijack changes in unicorn 5 Eric Wong
4 siblings, 0 replies; 6+ messages in thread
From: Eric Wong @ 2015-11-14 2:47 UTC (permalink / raw)
To: rainbows-public
Unicorn 5 removes some constants we were using, and constant
lookups + inline caching are waste of time anyways on newer
Rubies with the opt_str_freeze bytecode instruction.
This may reduce performance for folks on older Rubies (probably
not noticeable); but improves performance for folks on newer
Rubies.
---
lib/rainbows/const.rb | 3 ---
lib/rainbows/coolio/client.rb | 8 ++++----
lib/rainbows/coolio/thread_client.rb | 4 ++--
lib/rainbows/dev_fd_response.rb | 22 ++++++++--------------
lib/rainbows/epoll/client.rb | 8 ++++----
lib/rainbows/error.rb | 4 ++--
lib/rainbows/ev_core.rb | 28 +++++++++++-----------------
lib/rainbows/event_machine/client.rb | 12 ++++++------
lib/rainbows/event_machine/try_defer.rb | 5 +----
lib/rainbows/max_body.rb | 13 ++++---------
lib/rainbows/process_client.rb | 15 +++++++--------
lib/rainbows/response.rb | 29 +++++++++++------------------
lib/rainbows/reverse_proxy.rb | 28 +++++++++-------------------
lib/rainbows/reverse_proxy/ev_client.rb | 7 ++-----
lib/rainbows/sendfile.rb | 12 +++---------
lib/rainbows/server_token.rb | 7 +------
lib/rainbows/stream_response_epoll.rb | 7 +++----
17 files changed, 78 insertions(+), 134 deletions(-)
diff --git a/lib/rainbows/const.rb b/lib/rainbows/const.rb
index 8db95c0..14c7a44 100644
--- a/lib/rainbows/const.rb
+++ b/lib/rainbows/const.rb
@@ -13,7 +13,4 @@ module Rainbows::Const
# if they're the response body. Unset by default.
# "rainbows.autochunk" => false,
})
-
- RACK_INPUT = Unicorn::HttpRequest::RACK_INPUT
- REMOTE_ADDR = Unicorn::HttpRequest::REMOTE_ADDR
end
diff --git a/lib/rainbows/coolio/client.rb b/lib/rainbows/coolio/client.rb
index 843f574..c05fd3a 100644
--- a/lib/rainbows/coolio/client.rb
+++ b/lib/rainbows/coolio/client.rb
@@ -122,9 +122,9 @@ class Rainbows::Coolio::Client < Coolio::IO
def app_call input
KATO.delete(self)
disable if enabled?
- @env[RACK_INPUT] = input
- @env[REMOTE_ADDR] = @_io.kgio_addr
- @env[ASYNC_CALLBACK] = method(:write_async_response)
+ @env['rack.input'] = input
+ @env['REMOTE_ADDR'] = @_io.kgio_addr
+ @env['async.callback'] = method(:write_async_response)
@hp.hijack_setup(@env, @_io)
status, headers, body = catch(:async) {
APP.call(@env.merge!(RACK_DEFAULTS))
@@ -157,7 +157,7 @@ class Rainbows::Coolio::Client < Coolio::IO
KATO[self] = Time.now
end
else
- on_read(Z)
+ on_read(''.freeze)
end
end
rescue => e
diff --git a/lib/rainbows/coolio/thread_client.rb b/lib/rainbows/coolio/thread_client.rb
index ee9fa04..4de705f 100644
--- a/lib/rainbows/coolio/thread_client.rb
+++ b/lib/rainbows/coolio/thread_client.rb
@@ -8,7 +8,7 @@ class Rainbows::Coolio::ThreadClient < Rainbows::Coolio::Client
def app_call input
KATO.delete(self)
disable if enabled?
- @env[RACK_INPUT] = input
+ @env['rack.input'] = input
app_dispatch # must be implemented by subclass
end
@@ -25,7 +25,7 @@ class Rainbows::Coolio::ThreadClient < Rainbows::Coolio::Client
# here because that could cause a deadlock and we'd leak FDs
def app_response
begin
- @env[REMOTE_ADDR] = @_io.kgio_addr
+ @env['REMOTE_ADDR'] = @_io.kgio_addr
@hp.hijack_setup(@env, @_io)
APP.call(@env.merge!(RACK_DEFAULTS))
rescue => e
diff --git a/lib/rainbows/dev_fd_response.rb b/lib/rainbows/dev_fd_response.rb
index 7baccfc..8ebaabd 100644
--- a/lib/rainbows/dev_fd_response.rb
+++ b/lib/rainbows/dev_fd_response.rb
@@ -11,12 +11,6 @@ class Rainbows::DevFdResponse < Struct.new(:app)
# :stopdoc:
FD_MAP = Rainbows::FD_MAP
- Content_Length = "Content-Length".freeze
- Transfer_Encoding = "Transfer-Encoding".freeze
- Rainbows_autochunk = "rainbows.autochunk".freeze
- Rainbows_model = "rainbows.model"
- HTTP_VERSION = "HTTP_VERSION"
- Chunked = "chunked"
include Rack::Utils
# Rack middleware entry point, we'll just pass through responses
@@ -40,23 +34,23 @@ class Rainbows::DevFdResponse < Struct.new(:app)
fileno = io.fileno
FD_MAP[fileno] = io
if st.file?
- headers[Content_Length] ||= st.size.to_s
- headers.delete(Transfer_Encoding)
+ headers['Content-Length'.freeze] ||= st.size.to_s
+ headers.delete('Transfer-Encoding'.freeze)
elsif st.pipe? || st.socket? # epoll-able things
- unless headers.include?(Content_Length)
- if env[Rainbows_autochunk]
- case env[HTTP_VERSION]
+ unless headers.include?('Content-Length'.freeze)
+ if env['rainbows.autochunk']
+ case env['HTTP_VERSION']
when "HTTP/1.0", nil
else
- headers[Transfer_Encoding] = Chunked
+ headers['Transfer-Encoding'.freeze] = 'chunked'
end
else
- env[Rainbows_autochunk] = false
+ env['rainbows.autochunk'] = false
end
end
# we need to make sure our pipe output is Fiber-compatible
- case env[Rainbows_model]
+ case env['rainbows.model']
when :FiberSpawn, :FiberPool, :RevFiberSpawn, :CoolioFiberSpawn
io.respond_to?(:kgio_wait_readable) or
io = Rainbows::Fiber::IO.new(io)
diff --git a/lib/rainbows/epoll/client.rb b/lib/rainbows/epoll/client.rb
index 65fcb3e..2d95a99 100644
--- a/lib/rainbows/epoll/client.rb
+++ b/lib/rainbows/epoll/client.rb
@@ -63,8 +63,8 @@ module Rainbows::Epoll::Client
end
def app_call input # called by on_read()
- @env[RACK_INPUT] = input
- @env[REMOTE_ADDR] = kgio_addr
+ @env['rack.input'] = input
+ @env['REMOTE_ADDR'] = kgio_addr
@hp.hijack_setup(@env, self)
status, headers, body = APP.call(@env.merge!(RACK_DEFAULTS))
return hijacked if @hp.hijacked?
@@ -93,7 +93,7 @@ module Rainbows::Epoll::Client
Rainbows::Epoll::ResponsePipe).new(io, self, body)
return @wr_queue << pipe if @wr_queue[0]
stream_pipe(pipe) or return
- @wr_queue[0] or @wr_queue << Z
+ @wr_queue[0] or @wr_queue << ''.freeze
end
def ev_write_response(status, headers, body, alive)
@@ -120,7 +120,7 @@ module Rainbows::Epoll::Client
want_more
else
# pipelined request (already in buffer)
- on_read(Z)
+ on_read(''.freeze)
return if @wr_queue[0] || closed?
return hijacked if @hp.hijacked?
close if :close == @state
diff --git a/lib/rainbows/error.rb b/lib/rainbows/error.rb
index 736d5d8..3686eab 100644
--- a/lib/rainbows/error.rb
+++ b/lib/rainbows/error.rb
@@ -28,11 +28,11 @@ module Rainbows::Error
Errno::EBADF, Errno::ENOTCONN, Errno::ETIMEDOUT, Errno::EHOSTUNREACH
# swallow error if client shuts down one end or disconnects
when Unicorn::HttpParserError
- Rainbows::Const::ERROR_400_RESPONSE # try to tell the client they're bad
+ "HTTP/1.1 400 Bad Request\r\n\r\n" # try to tell the client they're bad
when IOError # HttpParserError is an IOError
else
app(e)
- Rainbows::Const::ERROR_500_RESPONSE
+ "HTTP/1.1 500 Internal Server Error\r\n\r\n"
end
end
end
diff --git a/lib/rainbows/ev_core.rb b/lib/rainbows/ev_core.rb
index 5c3c5b8..fd33786 100644
--- a/lib/rainbows/ev_core.rb
+++ b/lib/rainbows/ev_core.rb
@@ -8,13 +8,9 @@ module Rainbows::EvCore
HttpParser = Rainbows::HttpParser
autoload :CapInput, 'rainbows/ev_core/cap_input'
RBUF = ""
- Z = "".freeze
Rainbows.config!(self, :client_header_buffer_size)
- HTTP_VERSION = "HTTP_VERSION"
# Apps may return this Rack response: AsyncResponse = [ -1, {}, [] ]
- ASYNC_CALLBACK = "async.callback".freeze
- ASYNC_CLOSE = "async.close".freeze
def write_async_response(response)
status, headers, body = response
@@ -23,8 +19,8 @@ module Rainbows::EvCore
# "Transfer-Encoding: chunked", and the async.callback stuff
# isn't Rack::Lint-compatible, so we have to enforce it here.
headers = Rack::Utils::HeaderHash.new(headers) unless Hash === headers
- alive = headers.include?(Content_Length) ||
- !!(%r{\Achunked\z}i =~ headers[Transfer_Encoding])
+ alive = headers.include?('Content-Length'.freeze) ||
+ !!(%r{\Achunked\z}i =~ headers['Transfer-Encoding'.freeze])
end
@deferred = nil
ev_write_response(status, headers, body, alive)
@@ -55,12 +51,12 @@ module Rainbows::EvCore
# returns nil if request was hijacked in response stage
def stream_response_headers(status, headers, alive, body)
headers = Rack::Utils::HeaderHash.new(headers) unless Hash === headers
- if headers.include?(Content_Length)
+ if headers.include?('Content-Length'.freeze)
write_headers(status, headers, alive, body) or return
return false
end
- case @env[HTTP_VERSION]
+ case @env['HTTP_VERSION']
when "HTTP/1.0" # disable HTTP/1.0 keepalive to stream
write_headers(status, headers, false, body) or return
@hp.clear
@@ -68,7 +64,7 @@ module Rainbows::EvCore
when nil # "HTTP/0.9"
false
else
- rv = !!(headers[Transfer_Encoding] =~ %r{\Achunked\z}i)
+ rv = !!(headers['Transfer-Encoding'] =~ %r{\Achunked\z}i)
rv = false unless @env["rainbows.autochunk"]
write_headers(status, headers, alive, body) or return
rv
@@ -78,14 +74,14 @@ module Rainbows::EvCore
def prepare_request_body
# since we don't do streaming input, we have no choice but
# to take over 100-continue handling from the Rack application
- if @env[HTTP_EXPECT] =~ /\A100-continue\z/i
- write(EXPECT_100_RESPONSE)
- @env.delete(HTTP_EXPECT)
+ if @env['HTTP_EXPECT'] =~ /\A100-continue\z/i
+ write("HTTP/1.1 100 Continue\r\n\r\n".freeze)
+ @env.delete('HTTP_EXPECT'.freeze)
end
@input = mkinput
@hp.filter_body(@buf2 = "", @buf)
@input << @buf2
- on_read(Z)
+ on_read(''.freeze)
end
# TeeInput doesn't map too well to this right now...
@@ -111,7 +107,7 @@ module Rainbows::EvCore
elsif data.size > 0
@hp.filter_body(@buf2, @buf << data)
@input << @buf2
- on_read(Z)
+ on_read(''.freeze)
else
want_more
end
@@ -127,10 +123,8 @@ module Rainbows::EvCore
handle_error(e)
end
- ERROR_413_RESPONSE = "HTTP/1.1 413 Request Entity Too Large\r\n\r\n"
-
def err_413(msg)
- write(ERROR_413_RESPONSE)
+ write("HTTP/1.1 413 Request Entity Too Large\r\n\r\n".freeze)
quit
# zip back up the stack
raise IOError, msg, []
diff --git a/lib/rainbows/event_machine/client.rb b/lib/rainbows/event_machine/client.rb
index 9871c09..7fb88f6 100644
--- a/lib/rainbows/event_machine/client.rb
+++ b/lib/rainbows/event_machine/client.rb
@@ -23,7 +23,7 @@ class Rainbows::EventMachine::Client < EM::Connection
end
EM.next_tick { receive_data(nil) } unless @buf.empty?
else
- on_read(data || Z) if (@buf.size > 0) || data
+ on_read(data || ''.freeze) if (@buf.size > 0) || data
end
end
@@ -34,10 +34,10 @@ class Rainbows::EventMachine::Client < EM::Connection
def app_call input
set_comm_inactivity_timeout 0
- @env[RACK_INPUT] = input
- @env[REMOTE_ADDR] = @_io.kgio_addr
- @env[ASYNC_CALLBACK] = method(:write_async_response)
- @env[ASYNC_CLOSE] = EM::DefaultDeferrable.new
+ @env['rack.input'] = input
+ @env['REMOTE_ADDR'] = @_io.kgio_addr
+ @env['async.callback'] = method(:write_async_response)
+ @env['async.close'] = EM::DefaultDeferrable.new
@hp.hijack_setup(@env, @_io)
status, headers, body = catch(:async) {
APP.call(@env.merge!(RACK_DEFAULTS))
@@ -117,7 +117,7 @@ class Rainbows::EventMachine::Client < EM::Connection
def unbind
return if @hp.hijacked?
- async_close = @env[ASYNC_CLOSE] and async_close.succeed
+ async_close = @env['async.close'] and async_close.succeed
@deferred.respond_to?(:fail) and @deferred.fail
begin
@_io.close
diff --git a/lib/rainbows/event_machine/try_defer.rb b/lib/rainbows/event_machine/try_defer.rb
index 615adae..778f3d0 100644
--- a/lib/rainbows/event_machine/try_defer.rb
+++ b/lib/rainbows/event_machine/try_defer.rb
@@ -10,9 +10,6 @@
# See http://brainspl.at/articles/2008/04/18/deferred-requests-with-merb-ebb-and-thin
# for more information.
class Rainbows::EventMachine::TryDefer
- # shortcuts
- ASYNC_CALLBACK = Rainbows::EvCore::ASYNC_CALLBACK # :nodoc:
-
def initialize(app) # :nodoc:
# the entire app becomes multithreaded, even the root (non-deferred)
# thread since any thread can share processes with others
@@ -22,7 +19,7 @@ class Rainbows::EventMachine::TryDefer
def call(env) # :nodoc:
if @app.deferred?(env)
- EM.defer(proc { catch(:async) { @app.call(env) } }, env[ASYNC_CALLBACK])
+ EM.defer(proc { catch(:async) { @app.call(env) } }, env['async.callback'])
# all of the async/deferred stuff breaks Rack::Lint :<
nil
else
diff --git a/lib/rainbows/max_body.rb b/lib/rainbows/max_body.rb
index a8abbf7..56a77ab 100644
--- a/lib/rainbows/max_body.rb
+++ b/lib/rainbows/max_body.rb
@@ -48,19 +48,14 @@ class Rainbows::MaxBody
@app, @limit = app, limit
end
- # :stopdoc:
- RACK_INPUT = "rack.input".freeze
- CONTENT_LENGTH = "CONTENT_LENGTH"
- HTTP_TRANSFER_ENCODING = "HTTP_TRANSFER_ENCODING"
-
# our main Rack middleware endpoint
def call(env)
@limit = Rainbows.server.client_max_body_size if nil == @limit
catch(:rainbows_EFBIG) do
- len = env[CONTENT_LENGTH]
+ len = env['CONTENT_LENGTH']
if len && len.to_i > @limit
return err
- elsif /\Achunked\z/i =~ env[HTTP_TRANSFER_ENCODING]
+ elsif /\Achunked\z/i =~ env['HTTP_TRANSFER_ENCODING']
limit_input!(env)
end
@app.call(env)
@@ -89,9 +84,9 @@ class Rainbows::MaxBody
end
def limit_input!(env)
- input = env[RACK_INPUT]
+ input = env['rack.input']
klass = input.respond_to?(:rewind) ? RewindableWrapper : Wrapper
- env[RACK_INPUT] = klass.new(input, @limit)
+ env['rack.input'] = klass.new(input, @limit)
end
# :startdoc:
diff --git a/lib/rainbows/process_client.rb b/lib/rainbows/process_client.rb
index f58770c..492b8a6 100644
--- a/lib/rainbows/process_client.rb
+++ b/lib/rainbows/process_client.rb
@@ -5,7 +5,6 @@ module Rainbows::ProcessClient
include Rainbows::Const
NULL_IO = Unicorn::HttpRequest::NULL_IO
- RACK_INPUT = Unicorn::HttpRequest::RACK_INPUT
IC = Unicorn::HttpRequest.input_class
Rainbows.config!(self, :client_header_buffer_size, :keepalive_timeout)
@@ -39,13 +38,13 @@ module Rainbows::ProcessClient
end
set_input(env, hp)
- env[REMOTE_ADDR] = kgio_addr
+ env['REMOTE_ADDR'] = kgio_addr
hp.hijack_setup(env, to_io)
status, headers, body = APP.call(env.merge!(RACK_DEFAULTS))
if 100 == status.to_i
- write(EXPECT_100_RESPONSE)
- env.delete(HTTP_EXPECT)
+ write("HTTP/1.1 100 Continue\r\n\r\n".freeze)
+ env.delete('HTTP_EXPECT'.freeze)
status, headers, body = APP.call(env)
end
return if hp.hijacked?
@@ -66,18 +65,18 @@ module Rainbows::ProcessClient
end
def set_input(env, hp)
- env[RACK_INPUT] = 0 == hp.content_length ? NULL_IO : IC.new(self, hp)
+ env['rack.input'] = 0 == hp.content_length ? NULL_IO : IC.new(self, hp)
end
def process_pipeline(env, hp)
begin
set_input(env, hp)
- env[REMOTE_ADDR] = kgio_addr
+ env['REMOTE_ADDR'] = kgio_addr
hp.hijack_setup(env, to_io)
status, headers, body = APP.call(env.merge!(RACK_DEFAULTS))
if 100 == status.to_i
- write(EXPECT_100_RESPONSE)
- env.delete(HTTP_EXPECT)
+ write("HTTP/1.1 100 Continue\r\n\r\n".freeze)
+ env.delete('HTTP_EXPECT'.freeze)
status, headers, body = APP.call(env)
end
return if hp.hijacked?
diff --git a/lib/rainbows/response.rb b/lib/rainbows/response.rb
index a661ab6..2e8d2d8 100644
--- a/lib/rainbows/response.rb
+++ b/lib/rainbows/response.rb
@@ -2,10 +2,6 @@
# :enddoc:
module Rainbows::Response
include Unicorn::HttpResponse
- Close = "close"
- KeepAlive = "keep-alive"
- Content_Length = "Content-Length".freeze
- Transfer_Encoding = "Transfer-Encoding".freeze
Rainbows.config!(self, :copy_stream)
# private file class for IO objects opened by Rainbows! itself (and not
@@ -21,14 +17,12 @@ module Rainbows::Response
# Rack 1.5.0 (protocol version 1.2) adds response hijacking support
if ((Rack::VERSION[0] << 8) | Rack::VERSION[1]) >= 0x0102
- RACK_HIJACK = "rack.hijack"
-
def hijack_prepare(value)
value
end
def hijack_socket
- @hp.env[RACK_HIJACK].call
+ @hp.env['rack.hijack'].call
end
else
def hijack_prepare(_)
@@ -62,7 +56,8 @@ module Rainbows::Response
end
end
end
- write(buf << "Connection: #{alive ? KeepAlive : Close}\r\n\r\n")
+ write(buf << "Connection: #{alive ? 'keep-alive'.freeze
+ : 'close'.freeze}\r\n\r\n")
if hijack
body = nil # ensure caller does not close body
@@ -152,22 +147,19 @@ module Rainbows::Response
end # ! COPY_STREAM
if IO.method_defined?(:trysendfile) || COPY_STREAM
- HTTP_RANGE = 'HTTP_RANGE'
- Content_Range = 'Content-Range'.freeze
-
# This does not support multipart responses (does anybody actually
# use those?)
def sendfile_range(status, headers)
status = status.to_i
if 206 == status
- if %r{\Abytes (\d+)-(\d+)/\d+\z} =~ headers[Content_Range]
+ if %r{\Abytes (\d+)-(\d+)/\d+\z} =~ headers['Content-Range'.freeze]
a, b = $1.to_i, $2.to_i
return 206, headers, [ a, b - a + 1 ]
end
return # wtf...
end
200 == status &&
- /\Abytes=(\d+-\d*|\d*-\d+)\z/ =~ @hp.env[HTTP_RANGE] or
+ /\Abytes=(\d+-\d*|\d*-\d+)\z/ =~ @hp.env['HTTP_RANGE'] or
return
a, b = $1.split(/-/)
@@ -175,7 +167,7 @@ module Rainbows::Response
# uses a regular Ruby Hash with properly-cased headers the
# same way they're presented in rfc2616.
headers = Rack::Utils::HeaderHash.new(headers) unless Hash === headers
- clen = headers[Content_Length] or return
+ clen = headers['Content-Length'.freeze] or return
size = clen.to_i
if b.nil? # bytes=M-
@@ -190,13 +182,14 @@ module Rainbows::Response
end
if 0 > count || offset >= size
- headers[Content_Length] = "0"
- headers[Content_Range] = "bytes */#{clen}"
+ headers['Content-Length'.freeze] = "0"
+ headers['Content-Range'.freeze] = "bytes */#{clen}"
return 416, headers, nil
else
count = size if count > size
- headers[Content_Length] = count.to_s
- headers[Content_Range] = "bytes #{offset}-#{offset+count-1}/#{clen}"
+ headers['Content-Length'.freeze] = count.to_s
+ headers['Content-Range'.freeze] =
+ "bytes #{offset}-#{offset+count-1}/#{clen}"
return 206, headers, [ offset, count ]
end
end
diff --git a/lib/rainbows/reverse_proxy.rb b/lib/rainbows/reverse_proxy.rb
index c1f1dc2..16a6f65 100644
--- a/lib/rainbows/reverse_proxy.rb
+++ b/lib/rainbows/reverse_proxy.rb
@@ -47,15 +47,6 @@ class Rainbows::ReverseProxy
autoload :EventMachine, 'rainbows/reverse_proxy/event_machine'
autoload :EvClient, 'rainbows/reverse_proxy/ev_client'
- HTTP_X_FORWARDED_FOR = "HTTP_X_FORWARDED_FOR"
- REMOTE_ADDR = "REMOTE_ADDR"
- REQUEST_METHOD = "REQUEST_METHOD"
- REQUEST_URI = "REQUEST_URI"
- CRLF = "\r\n"
- TR = %w(_ -)
- CONTENT_LENGTH = "CONTENT_LENGTH"
- HTTP_TRANSFER_ENCODING = "HTTP_TRANSFER_ENCODING"
- RackInput = "rack.input"
E502 = [ 502, [ %w(Content-Length 0), %w(Content-Type text/plain) ], [] ]
def initialize(opts)
@@ -113,24 +104,23 @@ class Rainbows::ReverseProxy
# returns request headers for sending to the upstream as a string
def build_headers(env, input)
- remote_addr = env[REMOTE_ADDR]
- xff = env[HTTP_X_FORWARDED_FOR]
+ remote_addr = env['REMOTE_ADDR']
+ xff = env['HTTP_X_FORWARDED_FOR']
xff = xff ? "#{xff},#{remote_addr}" : remote_addr
- req = "#{env[REQUEST_METHOD]} #{env[REQUEST_URI]} HTTP/1.0\r\n" \
+ req = "#{env['REQUEST_METHOD']} #{env['REQUEST_URI']} HTTP/1.0\r\n" \
"Connection: close\r\n" \
"X-Forwarded-For: #{xff}\r\n"
- uscore, dash = *TR
env.each do |key, value|
%r{\AHTTP_(\w+)\z} =~ key or next
key = $1
next if %r{\A(?:VERSION|CONNECTION|KEEP_ALIVE|X_FORWARDED_FOR)\z}x =~ key
- key.tr!(uscore, dash)
+ key.tr!('_'.freeze, '-'.freeze)
req << "#{key}: #{value}\r\n"
end
input and req << (input.respond_to?(:size) ?
"Content-Length: #{input.size}\r\n" :
- "Transfer-Encoding: chunked\r\n")
- req << CRLF
+ "Transfer-Encoding: chunked\r\n".freeze)
+ req << "\r\n".freeze
end
def pick_upstream(env) # +env+ is reserved for future expansion
@@ -139,16 +129,16 @@ class Rainbows::ReverseProxy
end
def prepare_input!(env)
- if cl = env[CONTENT_LENGTH]
+ if cl = env['CONTENT_LENGTH']
size = cl.to_i
size > 0 or return
- elsif %r{\Achunked\z}i =~ env.delete(HTTP_TRANSFER_ENCODING)
+ elsif %r{\Achunked\z}i =~ env.delete('HTTP_TRANSFER_ENCODING')
# do people use multiple transfer-encodings?
else
return
end
- input = env[RackInput]
+ input = env['rack.input']
if input.respond_to?(:rewind)
if input.respond_to?(:size)
input.size # TeeInput-specific behavior
diff --git a/lib/rainbows/reverse_proxy/ev_client.rb b/lib/rainbows/reverse_proxy/ev_client.rb
index cf97c4d..ab3f7a3 100644
--- a/lib/rainbows/reverse_proxy/ev_client.rb
+++ b/lib/rainbows/reverse_proxy/ev_client.rb
@@ -3,18 +3,15 @@
require 'tempfile'
module Rainbows::ReverseProxy::EvClient
include Rainbows::ReverseProxy::Synchronous
- AsyncCallback = "async.callback"
CBB = Unicorn::TeeInput.client_body_buffer_size
- Content_Length = "Content-Length"
- Transfer_Encoding = "Transfer-Encoding"
def receive_data(buf)
if @body
@body << buf
else
response = @parser.headers(@headers, @rbuf << buf) or return
- if (cl = @headers[Content_Length] && cl.to_i > CBB) ||
- (%r{\bchunked\b} =~ @headers[Transfer_Encoding])
+ if (cl = @headers['Content-Length'.freeze] && cl.to_i > CBB) ||
+ (%r{\bchunked\b} =~ @headers['Transfer-Encoding'.freeze])
@body = LargeBody.new("")
@body << @rbuf
@response = response << @body
diff --git a/lib/rainbows/sendfile.rb b/lib/rainbows/sendfile.rb
index 767c0f9..59906e2 100644
--- a/lib/rainbows/sendfile.rb
+++ b/lib/rainbows/sendfile.rb
@@ -52,12 +52,10 @@ class Rainbows::Sendfile < Struct.new(:app)
# +each+ in case a given concurrency model does not optimize
# +to_path+ calls.
class Body < Struct.new(:to_path) # :nodoc: all
- CONTENT_LENGTH = 'Content-Length'.freeze
-
def self.new(path, headers)
- unless headers[CONTENT_LENGTH]
+ unless headers['Content-Length'.freeze]
stat = File.stat(path)
- headers[CONTENT_LENGTH] = stat.size.to_s if stat.file?
+ headers['Content-Length'.freeze] = stat.size.to_s if stat.file?
end
super(path)
end
@@ -71,14 +69,10 @@ class Rainbows::Sendfile < Struct.new(:app)
end
end
- # :stopdoc:
- X_SENDFILE = 'X-Sendfile'
- # :startdoc:
-
def call(env) # :nodoc:
status, headers, body = app.call(env)
headers = Rack::Utils::HeaderHash.new(headers) unless Hash === headers
- if path = headers.delete(X_SENDFILE)
+ if path = headers.delete('X-Sendfile'.freeze)
body = Body.new(path, headers) unless body.respond_to?(:to_path)
end
[ status, headers, body ]
diff --git a/lib/rainbows/server_token.rb b/lib/rainbows/server_token.rb
index 0ee87ac..09897d4 100644
--- a/lib/rainbows/server_token.rb
+++ b/lib/rainbows/server_token.rb
@@ -19,11 +19,6 @@ module Rainbows
class ServerToken < Struct.new(:app, :token)
- # :stopdoc:
- #
- # Freeze constants as they're slightly faster when setting hashes
- SERVER = "Server".freeze
-
def initialize(app, token = Const::RACK_DEFAULTS['SERVER_SOFTWARE'])
super
end
@@ -31,7 +26,7 @@ class ServerToken < Struct.new(:app, :token)
def call(env)
status, headers, body = app.call(env)
headers = Rack::Utils::HeaderHash.new(headers) unless Hash === headers
- headers[SERVER] = token
+ headers['Server'.freeze] = token
[ status, headers, body ]
end
# :startdoc:
diff --git a/lib/rainbows/stream_response_epoll.rb b/lib/rainbows/stream_response_epoll.rb
index 1f32dcc..c36acaf 100644
--- a/lib/rainbows/stream_response_epoll.rb
+++ b/lib/rainbows/stream_response_epoll.rb
@@ -20,7 +20,6 @@ require "raindrops"
# * sleepy_penguin 3.0.1 or later
module Rainbows::StreamResponseEpoll
# :stopdoc:
- HEADER_END = "X-Accel-Buffering: no\r\n\r\n"
autoload :Client, "rainbows/stream_response_epoll/client"
def http_response_write(socket, status, headers, body)
@@ -46,7 +45,7 @@ module Rainbows::StreamResponseEpoll
end
end
end
- buf << HEADER_END
+ buf << "X-Accel-Buffering: no\r\n\r\n".freeze
case rv = socket.kgio_trywrite(buf)
when nil then break
@@ -101,8 +100,8 @@ module Rainbows::StreamResponseEpoll
status, headers, body = @app.call(env = @request.read(client))
if 100 == status.to_i
- client.write(Unicorn::Const::EXPECT_100_RESPONSE)
- env.delete(Unicorn::Const::HTTP_EXPECT)
+ client.write("HTTP/1.1 100 Continue\r\n\r\n".freeze)
+ env.delete('HTTP_EXPECT'.freeze)
status, headers, body = @app.call(env)
end
@request.headers? or headers = nil
--
EW
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH 5/5] http_parser: workaround hijack changes in unicorn 5
2015-11-14 2:47 [WIP 0/5] updates for unicorn 5 internal changes Eric Wong
` (3 preceding siblings ...)
2015-11-14 2:47 ` [PATCH 4/5] reduce constant lookup dependencies Eric Wong
@ 2015-11-14 2:47 ` Eric Wong
4 siblings, 0 replies; 6+ messages in thread
From: Eric Wong @ 2015-11-14 2:47 UTC (permalink / raw)
To: rainbows-public
unicorn lost the hijack_setup method in version 5,
so we must recreate it ourselves.
---
lib/rainbows/coolio/client.rb | 2 +-
lib/rainbows/coolio/thread_client.rb | 2 +-
lib/rainbows/epoll/client.rb | 2 +-
lib/rainbows/event_machine/client.rb | 2 +-
lib/rainbows/http_parser.rb | 9 +++++++++
lib/rainbows/process_client.rb | 4 ++--
lib/rainbows/response.rb | 16 +++-------------
7 files changed, 18 insertions(+), 19 deletions(-)
diff --git a/lib/rainbows/coolio/client.rb b/lib/rainbows/coolio/client.rb
index c05fd3a..ad827f6 100644
--- a/lib/rainbows/coolio/client.rb
+++ b/lib/rainbows/coolio/client.rb
@@ -125,7 +125,7 @@ class Rainbows::Coolio::Client < Coolio::IO
@env['rack.input'] = input
@env['REMOTE_ADDR'] = @_io.kgio_addr
@env['async.callback'] = method(:write_async_response)
- @hp.hijack_setup(@env, @_io)
+ @hp.hijack_setup(@_io)
status, headers, body = catch(:async) {
APP.call(@env.merge!(RACK_DEFAULTS))
}
diff --git a/lib/rainbows/coolio/thread_client.rb b/lib/rainbows/coolio/thread_client.rb
index 4de705f..a3a2ebf 100644
--- a/lib/rainbows/coolio/thread_client.rb
+++ b/lib/rainbows/coolio/thread_client.rb
@@ -26,7 +26,7 @@ class Rainbows::Coolio::ThreadClient < Rainbows::Coolio::Client
def app_response
begin
@env['REMOTE_ADDR'] = @_io.kgio_addr
- @hp.hijack_setup(@env, @_io)
+ @hp.hijack_setup(@_io)
APP.call(@env.merge!(RACK_DEFAULTS))
rescue => e
Rainbows::Error.app(e) # we guarantee this does not raise
diff --git a/lib/rainbows/epoll/client.rb b/lib/rainbows/epoll/client.rb
index 2d95a99..6dcbb81 100644
--- a/lib/rainbows/epoll/client.rb
+++ b/lib/rainbows/epoll/client.rb
@@ -65,7 +65,7 @@ module Rainbows::Epoll::Client
def app_call input # called by on_read()
@env['rack.input'] = input
@env['REMOTE_ADDR'] = kgio_addr
- @hp.hijack_setup(@env, self)
+ @hp.hijack_setup(self)
status, headers, body = APP.call(@env.merge!(RACK_DEFAULTS))
return hijacked if @hp.hijacked?
ev_write_response(status, headers, body, @hp.next?)
diff --git a/lib/rainbows/event_machine/client.rb b/lib/rainbows/event_machine/client.rb
index 7fb88f6..039b7a6 100644
--- a/lib/rainbows/event_machine/client.rb
+++ b/lib/rainbows/event_machine/client.rb
@@ -38,7 +38,7 @@ class Rainbows::EventMachine::Client < EM::Connection
@env['REMOTE_ADDR'] = @_io.kgio_addr
@env['async.callback'] = method(:write_async_response)
@env['async.close'] = EM::DefaultDeferrable.new
- @hp.hijack_setup(@env, @_io)
+ @hp.hijack_setup(@_io)
status, headers, body = catch(:async) {
APP.call(@env.merge!(RACK_DEFAULTS))
}
diff --git a/lib/rainbows/http_parser.rb b/lib/rainbows/http_parser.rb
index 30a67cb..bcf1dba 100644
--- a/lib/rainbows/http_parser.rb
+++ b/lib/rainbows/http_parser.rb
@@ -17,6 +17,15 @@ class Rainbows::HttpParser < Unicorn::HttpParser
super
end
+ def hijack_setup(io)
+ @hijack_io = io
+ env['rack.hijack'] = self # avoid allocating a new proc this way
+ end
+
+ def call # for rack.hijack
+ env['rack.hijack_io'] = @hijack_io
+ end
+
def self.quit
alias_method :next?, :never!
end
diff --git a/lib/rainbows/process_client.rb b/lib/rainbows/process_client.rb
index 492b8a6..a39d6cd 100644
--- a/lib/rainbows/process_client.rb
+++ b/lib/rainbows/process_client.rb
@@ -39,7 +39,7 @@ module Rainbows::ProcessClient
set_input(env, hp)
env['REMOTE_ADDR'] = kgio_addr
- hp.hijack_setup(env, to_io)
+ hp.hijack_setup(to_io)
status, headers, body = APP.call(env.merge!(RACK_DEFAULTS))
if 100 == status.to_i
@@ -72,7 +72,7 @@ module Rainbows::ProcessClient
begin
set_input(env, hp)
env['REMOTE_ADDR'] = kgio_addr
- hp.hijack_setup(env, to_io)
+ hp.hijack_setup(to_io)
status, headers, body = APP.call(env.merge!(RACK_DEFAULTS))
if 100 == status.to_i
write("HTTP/1.1 100 Continue\r\n\r\n".freeze)
diff --git a/lib/rainbows/response.rb b/lib/rainbows/response.rb
index 2e8d2d8..0b5e542 100644
--- a/lib/rainbows/response.rb
+++ b/lib/rainbows/response.rb
@@ -15,18 +15,8 @@ module Rainbows::Response
Rainbows::HttpParser.keepalive_requests = 0
end
- # Rack 1.5.0 (protocol version 1.2) adds response hijacking support
- if ((Rack::VERSION[0] << 8) | Rack::VERSION[1]) >= 0x0102
- def hijack_prepare(value)
- value
- end
-
- def hijack_socket
- @hp.env['rack.hijack'].call
- end
- else
- def hijack_prepare(_)
- end
+ def hijack_socket
+ @hp.env['rack.hijack'].call
end
# returns the original body on success
@@ -45,7 +35,7 @@ module Rainbows::Response
when "rack.hijack"
# this was an illegal key in Rack < 1.5, so it should be
# OK to silently discard it for those older versions
- hijack = hijack_prepare(value)
+ hijack = value
alive = false # No persistent connections for hijacking
else
if /\n/ =~ value
--
EW
^ permalink raw reply related [flat|nested] 6+ messages in thread
end of thread, other threads:[~2015-11-14 2:47 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-11-14 2:47 [WIP 0/5] updates for unicorn 5 internal changes Eric Wong
2015-11-14 2:47 ` [PATCH 1/5] http_parser: handle keepalive_requests internally Eric Wong
2015-11-14 2:47 ` [PATCH 2/5] kill the moronic Status: header Eric Wong
2015-11-14 2:47 ` [PATCH 3/5] reflect changes in Rack::Utils::HTTP_STATUS_CODES Eric Wong
2015-11-14 2:47 ` [PATCH 4/5] reduce constant lookup dependencies Eric Wong
2015-11-14 2:47 ` [PATCH 5/5] http_parser: workaround hijack changes in unicorn 5 Eric Wong
Code repositories for project(s) associated with this public inbox
https://yhbt.net/rainbows.git/
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).