diff options
author | Eric Wong <normalperson@yhbt.net> | 2011-06-11 06:35:12 +0000 |
---|---|---|
committer | Eric Wong <normalperson@yhbt.net> | 2011-06-11 06:35:12 +0000 |
commit | 281ef555c40cf292809ad10d623d0571fafc790e (patch) | |
tree | e13fb2af08c6896b53f244bcf6efb36a9c730051 | |
parent | 1f3e7b1c7ee89aefdcadd4aebd7b0527baa188a3 (diff) | |
download | rainbows-281ef555c40cf292809ad10d623d0571fafc790e.tar.gz |
Lowering this will lower worst-case memory usage and mitigate some denial-of-service attacks. This should be larger than client_header_buffer_size. The default value is carried over from Mongrel and Unicorn.
-rw-r--r-- | lib/rainbows/configurator.rb | 13 | ||||
-rw-r--r-- | lib/rainbows/http_server.rb | 4 | ||||
-rwxr-xr-x | t/t0045-client_max_header_size.sh | 90 |
3 files changed, 107 insertions, 0 deletions
diff --git a/lib/rainbows/configurator.rb b/lib/rainbows/configurator.rb index 1b93fc7..433158b 100644 --- a/lib/rainbows/configurator.rb +++ b/lib/rainbows/configurator.rb @@ -27,6 +27,7 @@ module Rainbows::Configurator :keepalive_requests => 100, :client_max_body_size => 1024 * 1024, :client_header_buffer_size => 1024, + :client_max_header_size => 112 * 1024, :copy_stream => IO.respond_to?(:copy_stream) ? IO : false, }) @@ -147,6 +148,18 @@ module Rainbows::Configurator set[:client_max_body_size] = bytes end + # Limits the maximum size of a request header for all requests. + # + # Default: 112 kilobytes (114688 bytes) + # + # Lowering this will lower worst-case memory usage and mitigate some + # denial-of-service attacks. This should be larger than + # client_header_buffer_size. + def client_max_header_size(bytes) + check! + set_int(:client_max_header_size, bytes, 8) + end + # This governs the amount of memory allocated for an individual read(2) or # recv(2) system call when reading headers. Applications that make minimal # use of cookies should not increase this from the default. diff --git a/lib/rainbows/http_server.rb b/lib/rainbows/http_server.rb index be02630..746d534 100644 --- a/lib/rainbows/http_server.rb +++ b/lib/rainbows/http_server.rb @@ -97,4 +97,8 @@ class Rainbows::HttpServer < Unicorn::HttpServer def keepalive_requests Unicorn::HttpRequest.keepalive_requests end + + def client_max_header_size=(bytes) + Unicorn::HttpParser.max_header_len = bytes + end end diff --git a/t/t0045-client_max_header_size.sh b/t/t0045-client_max_header_size.sh new file mode 100755 index 0000000..17cbc29 --- /dev/null +++ b/t/t0045-client_max_header_size.sh @@ -0,0 +1,90 @@ +#!/bin/sh +. ./test-lib.sh +skip_models StreamResponseEpoll + +t_plan 11 "client_max_header_size tests for $model" + +t_begin "setup Rainbows!" && { + rainbows_setup $model +} + +t_begin "fails with zero size" && { + ed -s $unicorn_config <<EOF +,s/^ client_max_body_size.*/ client_max_header_size 0/ +w +EOF + grep "client_max_header_size 0" $unicorn_config + rainbows -D env.ru -c $unicorn_config && die "should fail" +} + +t_begin "fails with negative value" && { + ed -s $unicorn_config <<EOF +,s/^ client_max_header_size.*/ client_max_header_size -1/ +w +EOF + grep "client_max_header_size -1" $unicorn_config + rainbows -D env.ru -c $unicorn_config && die "should fail" +} + +t_begin "fails with small size" && { + ed -s $unicorn_config <<EOF +,s/^ client_max_header_size.*/ client_max_header_size 7/ +w +EOF + grep "client_max_header_size 7" $unicorn_config + rainbows -D env.ru -c $unicorn_config && die "should fail" +} + +t_begin "starts with minimum value" && { + ed -s $unicorn_config <<EOF +,s/^ client_max_header_size.*/ client_max_header_size 8/ +w +EOF + grep 'client_max_header_size 8$' $unicorn_config + rainbows -D env.ru -c $unicorn_config + rainbows_wait_start +} + +t_begin "smallest HTTP/0.9 request works right" && { + ( + cat $fifo > $tmp & + printf 'GET /\r\n' + wait + echo ok > $ok + ) | socat - TCP:$listen > $fifo + wait + test xok = x"$(cat $ok)" + test 1 -eq $(wc -l < $tmp) + grep HTTP_VERSION $tmp && die "unexpected HTTP_VERSION in HTTP/0.9 request" +} + +t_begin "HTTP/1.1 request fails" && { + curl -vsSf http://$listen/ > $tmp 2>&1 && die "unexpected curl success" + grep '400$' $tmp +} + +t_begin "increase client_max_header_size on reload" && { + ed -s $unicorn_config <<EOF +,s/^ client_max_header_size.*/ client_max_header_size 512/ +w +EOF + grep 'client_max_header_size 512$' $unicorn_config + kill -HUP $rainbows_pid + test xSTART = x"$(cat $fifo)" +} + +t_begin "HTTP/1.1 request succeeds" && { + curl -sSf http://$listen/ > $tmp + test 1 -eq $(wc -l < $tmp) + dbgcat tmp +} + +t_begin "no errors in stderr" && { + check_stderr +} + +t_begin "shutdown" && { + kill $rainbows_pid +} + +t_done |