Skip to content

Commit 543e57e

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 69b2bbc commit 543e57e

File tree

3 files changed

+41
-1
lines changed

3 files changed

+41
-1
lines changed

lib/net/http.rb

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -690,6 +690,7 @@ def initialize(address, port = nil)
690690
@continue_timeout = nil
691691
@max_retries = 1
692692
@debug_output = nil
693+
@ignore_eof = true
693694

694695
@proxy_from_env = false
695696
@proxy_uri = nil
@@ -818,6 +819,10 @@ def continue_timeout=(sec)
818819
# The default value is 2 seconds.
819820
attr_accessor :keep_alive_timeout
820821

822+
# Whether to ignore EOF when reading response bodies with defined
823+
# Content-Length headers. For backwards compatibility, the default is true.
824+
attr_accessor :ignore_eof
825+
821826
# Returns true if the HTTP session has been started.
822827
def started?
823828
@started
@@ -1559,6 +1564,7 @@ def transport_request(req)
15591564
begin
15601565
res = HTTPResponse.read_new(@socket)
15611566
res.decode_content = req.decode_content
1567+
res.ignore_eof = @ignore_eof
15621568
end while res.kind_of?(HTTPInformation)
15631569

15641570
res.uri = req.uri

lib/net/http/response.rb

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

8990
# The HTTP version supported by the server.
@@ -106,6 +107,10 @@ def initialize(httpv, code, msg) #:nodoc: internal use only
106107
# Accept-Encoding header from the user.
107108
attr_accessor :decode_content
108109

110+
# Whether to ignore EOF when reading bodies with a specified Content-Length
111+
# header.
112+
attr_accessor :ignore_eof
113+
109114
def inspect
110115
"#<#{self.class} #{@code} #{@message} readbody=#{@read}>"
111116
end
@@ -297,7 +302,7 @@ def read_body_0(dest)
297302

298303
clen = content_length()
299304
if clen
300-
@socket.read clen, dest, true # ignore EOF
305+
@socket.read clen, dest, @ignore_eof
301306
return
302307
end
303308
clen = range_length()

test/net/http/test_http.rb

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1226,3 +1226,32 @@ def test_bind_to_local_port
12261226
end
12271227
end
12281228

1229+
class TestNetHTTPPartialResponse < Test::Unit::TestCase
1230+
CONFIG = {
1231+
'host' => '127.0.0.1',
1232+
'proxy_host' => nil,
1233+
'proxy_port' => nil,
1234+
}
1235+
1236+
include TestNetHTTPUtils
1237+
1238+
def test_partial_response
1239+
str = "0123456789"
1240+
@server.mount_proc('/') do |req, res|
1241+
res.status = 200
1242+
res['Content-Type'] = 'text/plain'
1243+
1244+
res.body = str
1245+
res['Content-Length'] = str.length + 1
1246+
end
1247+
@server.mount_proc('/show_ip') { |req, res| res.body = req.remote_ip }
1248+
1249+
http = Net::HTTP.new(config('host'), config('port'))
1250+
res = http.get('/')
1251+
assert_equal(str, res.body)
1252+
1253+
http = Net::HTTP.new(config('host'), config('port'))
1254+
http.ignore_eof = false
1255+
assert_raise(EOFError) {http.get('/')}
1256+
end
1257+
end

0 commit comments

Comments
 (0)