Skip to content

Commit 4d47e34

Browse files
committed
Add ignore_eof access to HTTP and HTTPResponse
The ignore_eof setting on HTTPResponse makes it so an EOFError is raised when reading bodies with a defined Content-Length, if the body read was truncated due to the socket be closed. The ignore_eof setting on HTTP sets the values used in responses that are created by the object. For backwards compatibility, the default is for both settings is true. However, unless you are specifically tested for and handling truncated responses, it's a good idea to set ignore_eof to false so that errors are raised for truncated responses, instead of those errors silently being ignored. Fixes [Bug #14972]
1 parent 58284e9 commit 4d47e34

File tree

3 files changed

+42
-1
lines changed

3 files changed

+42
-1
lines changed

lib/net/http.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -699,6 +699,7 @@ def initialize(address, port = nil)
699699
@max_retries = 1
700700
@debug_output = nil
701701
@response_body_encoding = false
702+
@ignore_eof = true
702703

703704
@proxy_from_env = false
704705
@proxy_uri = nil
@@ -839,6 +840,10 @@ def continue_timeout=(sec)
839840
# The default value is 2 seconds.
840841
attr_accessor :keep_alive_timeout
841842

843+
# Whether to ignore EOF when reading response bodies with defined
844+
# Content-Length headers. For backwards compatibility, the default is true.
845+
attr_accessor :ignore_eof
846+
842847
# Returns true if the HTTP session has been started.
843848
def started?
844849
@started
@@ -1606,6 +1611,7 @@ def transport_request(req)
16061611
res = HTTPResponse.read_new(@socket)
16071612
res.decode_content = req.decode_content
16081613
res.body_encoding = @response_body_encoding
1614+
res.ignore_eof = @ignore_eof
16091615
end while res.kind_of?(HTTPInformation)
16101616

16111617
res.uri = req.uri

lib/net/http/response.rb

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,7 @@ def initialize(httpv, code, msg) #:nodoc: internal use only
8585
@uri = nil
8686
@decode_content = false
8787
@body_encoding = false
88+
@ignore_eof = true
8889
end
8990

9091
# The HTTP version supported by the server.
@@ -119,6 +120,10 @@ def body_encoding=(value)
119120
@body_encoding = value
120121
end
121122

123+
# Whether to ignore EOF when reading bodies with a specified Content-Length
124+
# header.
125+
attr_accessor :ignore_eof
126+
122127
def inspect
123128
"#<#{self.class} #{@code} #{@message} readbody=#{@read}>"
124129
end
@@ -459,7 +464,7 @@ def read_body_0(dest)
459464

460465
clen = content_length()
461466
if clen
462-
@socket.read clen, dest, true # ignore EOF
467+
@socket.read clen, dest, @ignore_eof
463468
return
464469
end
465470
clen = range_length()

test/net/http/test_http.rb

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1348,3 +1348,33 @@ def test_response_body_encoding_encoding_without_content_type
13481348
assert_equal(Encoding::UTF_8, res.body.encoding)
13491349
end
13501350
end
1351+
1352+
class TestNetHTTPPartialResponse < Test::Unit::TestCase
1353+
CONFIG = {
1354+
'host' => '127.0.0.1',
1355+
'proxy_host' => nil,
1356+
'proxy_port' => nil,
1357+
}
1358+
1359+
include TestNetHTTPUtils
1360+
1361+
def test_partial_response
1362+
str = "0123456789"
1363+
@server.mount_proc('/') do |req, res|
1364+
res.status = 200
1365+
res['Content-Type'] = 'text/plain'
1366+
1367+
res.body = str
1368+
res['Content-Length'] = str.length + 1
1369+
end
1370+
@server.mount_proc('/show_ip') { |req, res| res.body = req.remote_ip }
1371+
1372+
http = Net::HTTP.new(config('host'), config('port'))
1373+
res = http.get('/')
1374+
assert_equal(str, res.body)
1375+
1376+
http = Net::HTTP.new(config('host'), config('port'))
1377+
http.ignore_eof = false
1378+
assert_raise(EOFError) {http.get('/')}
1379+
end
1380+
end

0 commit comments

Comments
 (0)