Skip to content

Commit 5d3cd05

Browse files
hsbtclaude
andcommitted
Handle POST without Content-Length
A POST with no Content-Length header (or an empty value) made CGI.new raise TypeError/ArgumentError from Integer(nil)/Integer(""). Treat a missing or empty length as unspecified: read the body to EOF for url-encoded forms, and raise a clear error for multipart where the length is required. #56 Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
1 parent 2af5afa commit 5d3cd05

2 files changed

Lines changed: 36 additions & 2 deletions

File tree

lib/cgi/core.rb

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -838,13 +838,16 @@ def read_from_cmdline
838838
# Handles multipart forms (in particular, forms that involve file uploads).
839839
# Reads query parameters in the @params field, and cookies into @cookies.
840840
def initialize_query()
841+
content_length = env_table['CONTENT_LENGTH']
842+
content_length = nil if content_length == ''
841843
if ("POST" == env_table['REQUEST_METHOD']) and
842844
%r|\Amultipart/form-data.*boundary=\"?([^\";,]+)\"?| =~ env_table['CONTENT_TYPE']
843845
current_max_multipart_length = @max_multipart_length.respond_to?(:call) ? @max_multipart_length.call : @max_multipart_length
844846
raise StandardError.new("too large multipart data.") if env_table['CONTENT_LENGTH'].to_i > current_max_multipart_length
847+
raise StandardError.new("no content length for multipart data.") if content_length.nil?
845848
boundary = $1.dup
846849
@multipart = true
847-
@params = read_multipart(boundary, Integer(env_table['CONTENT_LENGTH']))
850+
@params = read_multipart(boundary, Integer(content_length))
848851
else
849852
@multipart = false
850853
@params = CGI.parse(
@@ -857,7 +860,11 @@ def initialize_query()
857860
end
858861
when "POST"
859862
stdinput.binmode if defined? stdinput.binmode
860-
stdinput.read(Integer(env_table['CONTENT_LENGTH'])) or ''
863+
if content_length.nil?
864+
stdinput.read or ''
865+
else
866+
stdinput.read(Integer(content_length)) or ''
867+
end
861868
else
862869
read_from_cmdline
863870
end.dup.force_encoding(@accept_charset)

test/cgi/test_cgi_core.rb

Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -92,6 +92,33 @@ def test_cgi_core_params_POST
9292
$stdin = STDIN
9393
end
9494

95+
def test_cgi_core_params_POST_without_content_length
96+
update_env(
97+
'REQUEST_METHOD' => 'POST',
98+
'CONTENT_TYPE' => 'application/x-www-form-urlencoded',
99+
)
100+
$stdin = StringIO.new
101+
cgi = nil
102+
assert_nothing_raised { cgi = CGI.new }
103+
assert_equal({}, cgi.params)
104+
ensure
105+
$stdin = STDIN
106+
end
107+
108+
def test_cgi_core_params_POST_empty_content_length
109+
update_env(
110+
'REQUEST_METHOD' => 'POST',
111+
'CONTENT_TYPE' => 'application/x-www-form-urlencoded',
112+
'CONTENT_LENGTH' => '',
113+
)
114+
$stdin = StringIO.new
115+
cgi = nil
116+
assert_nothing_raised { cgi = CGI.new }
117+
assert_equal({}, cgi.params)
118+
ensure
119+
$stdin = STDIN
120+
end
121+
95122
def test_cgi_core_params_encoding_check
96123
query_str = 'str=%BE%BE%B9%BE'
97124
update_env(

0 commit comments

Comments
 (0)