diff options
-rw-r--r-- | lib/rainbows.rb | 5 | ||||
-rw-r--r-- | lib/rainbows/client.rb | 6 | ||||
-rw-r--r-- | lib/rainbows/configurator.rb | 1 | ||||
-rw-r--r-- | lib/rainbows/coolio/client.rb | 4 | ||||
-rw-r--r-- | lib/rainbows/epoll/client.rb | 2 | ||||
-rw-r--r-- | lib/rainbows/ev_core.rb | 1 | ||||
-rw-r--r-- | lib/rainbows/http_server.rb | 6 | ||||
-rw-r--r-- | lib/rainbows/process_client.rb | 3 | ||||
-rw-r--r-- | lib/rainbows/xepoll_thread_spawn/client.rb | 5 | ||||
-rw-r--r-- | t/client_header_buffer_size.ru | 3 | ||||
-rw-r--r-- | t/t0042-client_header_buffer_size.sh | 65 |
11 files changed, 92 insertions, 9 deletions
diff --git a/lib/rainbows.rb b/lib/rainbows.rb index 4b8d552..0e6ca39 100644 --- a/lib/rainbows.rb +++ b/lib/rainbows.rb @@ -67,6 +67,7 @@ module Rainbows # :stopdoc: class << self + attr_accessor :client_header_buffer_size attr_accessor :max_bytes, :keepalive_timeout attr_accessor :server attr_accessor :cur # may not always be used @@ -81,6 +82,10 @@ module Rainbows # the default keepalive_timeout is 5 seconds @keepalive_timeout = 5 + # 1024 bytes matches nginx, though Rails session cookies will typically + # need >= 1500... + @client_header_buffer_size = 1024 + # :stopdoc: @alive = true @cur = 0 diff --git a/lib/rainbows/client.rb b/lib/rainbows/client.rb index 7387c44..4608f53 100644 --- a/lib/rainbows/client.rb +++ b/lib/rainbows/client.rb @@ -4,6 +4,8 @@ require "io/wait" # this class is used for most synchronous concurrency models class Rainbows::Client < Kgio::Socket + include Rainbows::ProcessClient + def read_expire Time.now + Rainbows.keepalive_timeout end @@ -16,7 +18,7 @@ class Rainbows::Client < Kgio::Socket def timed_read(buf) expire = nil begin - case rv = kgio_tryread(0x1000, buf) + case rv = kgio_tryread(HBUFSIZ, buf) when :wait_readable return if expire && expire < Time.now expire ||= read_expire @@ -26,6 +28,4 @@ class Rainbows::Client < Kgio::Socket end end while true end - - include Rainbows::ProcessClient end diff --git a/lib/rainbows/configurator.rb b/lib/rainbows/configurator.rb index 3203c5a..b596b0b 100644 --- a/lib/rainbows/configurator.rb +++ b/lib/rainbows/configurator.rb @@ -14,6 +14,7 @@ module Rainbows::Configurator # keepalive_timeout 0 # zero disables keepalives entirely # client_max_body_size 5*1024*1024 # 5 megabytes # keepalive_requests 666 # default:100 + # client_header_buffer_size 16 * 1024 # 16 kilobytes # end # # # the rest of the Unicorn configuration diff --git a/lib/rainbows/coolio/client.rb b/lib/rainbows/coolio/client.rb index 2de421a..5688730 100644 --- a/lib/rainbows/coolio/client.rb +++ b/lib/rainbows/coolio/client.rb @@ -45,7 +45,7 @@ class Rainbows::Coolio::Client < Coolio::IO end def on_readable - buf = @_io.kgio_tryread(16384, RBUF) + buf = @_io.kgio_tryread(HBUFSIZ, RBUF) case buf when :wait_readable when nil # eof @@ -134,7 +134,7 @@ class Rainbows::Coolio::Client < Coolio::IO close if @_write_buffer.empty? when :headers if @buf.empty? - buf = @_io.kgio_tryread(16384, RBUF) or return close + buf = @_io.kgio_tryread(HBUFSIZ, RBUF) or return close String === buf and return on_read(buf) # buf == :wait_readable unless enabled? diff --git a/lib/rainbows/epoll/client.rb b/lib/rainbows/epoll/client.rb index 924d32f..3fbd386 100644 --- a/lib/rainbows/epoll/client.rb +++ b/lib/rainbows/epoll/client.rb @@ -33,7 +33,7 @@ module Rainbows::Epoll::Client end def on_readable - case rv = kgio_tryread(16384, RBUF) + case rv = kgio_tryread(HBUFSIZ, RBUF) when String on_read(rv) return if @wr_queue[0] || closed? diff --git a/lib/rainbows/ev_core.rb b/lib/rainbows/ev_core.rb index 61853ab..24254dc 100644 --- a/lib/rainbows/ev_core.rb +++ b/lib/rainbows/ev_core.rb @@ -9,6 +9,7 @@ module Rainbows::EvCore autoload :CapInput, 'rainbows/ev_core/cap_input' RBUF = "" Z = "".freeze + HBUFSIZ = Rainbows.client_header_buffer_size # Apps may return this Rack response: AsyncResponse = [ -1, {}, [] ] ASYNC_CALLBACK = "async.callback".freeze diff --git a/lib/rainbows/http_server.rb b/lib/rainbows/http_server.rb index 4e1d7d9..c36b7bf 100644 --- a/lib/rainbows/http_server.rb +++ b/lib/rainbows/http_server.rb @@ -141,4 +141,10 @@ class Rainbows::HttpServer < Unicorn::HttpServer end Rainbows.max_bytes = nr end + + def client_header_buffer_size(bytes) + Integer === bytes && bytes > 0 or raise ArgumentError, + "client_header_buffer_size must be a positive Integer" + Rainbows.client_header_buffer_size = bytes + end end diff --git a/lib/rainbows/process_client.rb b/lib/rainbows/process_client.rb index 6201064..f30aa5d 100644 --- a/lib/rainbows/process_client.rb +++ b/lib/rainbows/process_client.rb @@ -7,10 +7,11 @@ module Rainbows::ProcessClient NULL_IO = Unicorn::HttpRequest::NULL_IO RACK_INPUT = Unicorn::HttpRequest::RACK_INPUT IC = Unicorn::HttpRequest.input_class + HBUFSIZ = Rainbows.client_header_buffer_size def process_loop @hp = hp = Rainbows::HttpParser.new - kgio_read!(0x1000, buf = hp.buf) or return + kgio_read!(HBUFSIZ, buf = hp.buf) or return begin # loop until env = hp.parse diff --git a/lib/rainbows/xepoll_thread_spawn/client.rb b/lib/rainbows/xepoll_thread_spawn/client.rb index 9bee1d1..4111f27 100644 --- a/lib/rainbows/xepoll_thread_spawn/client.rb +++ b/lib/rainbows/xepoll_thread_spawn/client.rb @@ -4,6 +4,7 @@ require "sleepy_penguin" require "raindrops" module Rainbows::XEpollThreadSpawn::Client + HBUFSIZ = Rainbows.client_header_buffer_size N = Raindrops.new(1) max = Rainbows.server.worker_connections ACCEPTORS = Rainbows::HttpServer::LISTENERS.map do |sock| @@ -88,7 +89,7 @@ module Rainbows::XEpollThreadSpawn::Client end def epoll_run(buf) - case kgio_tryread(0x1000, buf) + case kgio_tryread(HBUFSIZ, buf) when :wait_readable return kato_set when String @@ -108,7 +109,7 @@ module Rainbows::XEpollThreadSpawn::Client def pipeline_ready(hp) env = hp.parse and return env - case buf = kgio_tryread(0x1000) + case buf = kgio_tryread(HBUFSIZ) when :wait_readable kato_set return false diff --git a/t/client_header_buffer_size.ru b/t/client_header_buffer_size.ru new file mode 100644 index 0000000..0831944 --- /dev/null +++ b/t/client_header_buffer_size.ru @@ -0,0 +1,3 @@ +use Rack::ContentLength +use Rack::ContentType, "text/plain" +run lambda { |env| [ 200, {}, [ "#{Rainbows.client_header_buffer_size}\n" ] ] } diff --git a/t/t0042-client_header_buffer_size.sh b/t/t0042-client_header_buffer_size.sh new file mode 100644 index 0000000..0e19361 --- /dev/null +++ b/t/t0042-client_header_buffer_size.sh @@ -0,0 +1,65 @@ +#!/bin/sh +. ./test-lib.sh + +t_plan 8 "client_header_buffer_size tests for $model" + +t_begin "setup and startup" && { + rainbows_setup $model +} + +t_begin "fails with zero buffer size" && { + ed -s $unicorn_config <<EOF +,s/^ client_max_body_size.*/ client_header_buffer_size 0/ +w +EOF + grep "client_header_buffer_size 0" $unicorn_config + rainbows -D client_header_buffer_size.ru -c $unicorn_config || \ + echo err=$? > $ok + test x"$(cat $ok)" = "xerr=1" +} + +t_begin "fails with negative value" && { + ed -s $unicorn_config <<EOF +,s/^ client_header_buffer_size.*/ client_header_buffer_size -1/ +w +EOF + grep "client_header_buffer_size -1" $unicorn_config + rainbows -D client_header_buffer_size.ru -c $unicorn_config || \ + echo err=$? > $ok + test x"$(cat $ok)" = "xerr=1" +} + +t_begin "fails with negative value" && { + ed -s $unicorn_config <<EOF +,s/^ client_header_buffer_size.*/ client_header_buffer_size -1/ +w +EOF + grep "client_header_buffer_size -1" $unicorn_config + rainbows -D client_header_buffer_size.ru -c $unicorn_config || \ + echo err=$? > $ok + test x"$(cat $ok)" = "xerr=1" +} + +t_begin "starts with correct value" && { + ed -s $unicorn_config <<EOF +,s/^ client_header_buffer_size.*/ client_header_buffer_size 16399/ +w +EOF + grep "client_header_buffer_size 16399" $unicorn_config + rainbows -D client_header_buffer_size.ru -c $unicorn_config + rainbows_wait_start +} + +t_begin "regular TCP request works right" && { + test x$(curl -sSfv http://$listen/) = x16399 +} + +t_begin "no errors in stderr" && { + check_stderr +} + +t_begin "shutdown" && { + kill $rainbows_pid +} + +t_done |