Skip to content

Commit ccb57d7

Browse files
committed
fix for leftover data with interrupted persistent connections
Thanks to @pje for disclosure, initial patch, and input
1 parent f8de8cf commit ccb57d7

File tree

3 files changed

+39
-0
lines changed

3 files changed

+39
-0
lines changed

lib/excon/connection.rb

+8
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,11 @@ def request(params={}, &block)
262262

263263
datum[:connection] = self
264264

265+
# cleanup data left behind on persistent connection after interrupt
266+
if datum[:persistent] && !@persistent_socket_reusable
267+
reset
268+
end
269+
265270
datum[:stack] = datum[:middlewares].map do |middleware|
266271
lambda {|stack| middleware.new(stack)}
267272
end.reverse.inject(self) do |middlewares, middleware|
@@ -270,7 +275,9 @@ def request(params={}, &block)
270275
datum = datum[:stack].request_call(datum)
271276

272277
unless datum[:pipeline]
278+
@persistent_socket_reusable = false
273279
datum = response(datum)
280+
@persistent_socket_reusable = true
274281

275282
if datum[:persistent]
276283
if key = datum[:response][:headers].keys.detect {|k| k.casecmp('Connection') == 0 }
@@ -344,6 +351,7 @@ def reset
344351
if old_socket = sockets.delete(@socket_key)
345352
old_socket.close rescue nil
346353
end
354+
@persistent_socket_reusable = true
347355
end
348356

349357
# Generate HTTP request verb methods

tests/connection_tests.rb

+23
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,29 @@
1414
connection.send(:socket) # creates/connects socket
1515
connection.data[:remote_ip]
1616
end
17+
18+
tests("persistent connections") do
19+
connection = Excon.new('http://127.0.0.1:9292', persistent: true)
20+
21+
response_body = connection.request(path: '/foo', method: 'get').body
22+
test("successful uninterrupted request") do
23+
connection.request(path: '/foo', method: 'get').body == 'foo'
24+
end
25+
26+
begin
27+
# simulate an interrupted connection which leaves data behind
28+
Timeout::timeout(0.0000000001) do
29+
connection.request(path: '/foo', method: 'get')
30+
end
31+
rescue Timeout::Error
32+
nil
33+
end
34+
35+
test("resets connection after interrupt") do
36+
response = connection.request(path: '/bar', method: 'get')
37+
response.body == 'bar'
38+
end
39+
end
1740
end
1841

1942
tests("inspect redaction") do

tests/rackups/basic.rb

+8
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,14 @@ class Basic < Sinatra::Base
3232
echo
3333
end
3434

35+
get('/foo') do
36+
'foo'
37+
end
38+
39+
get('/bar') do
40+
'bar'
41+
end
42+
3543
private
3644

3745
def echo

0 commit comments

Comments
 (0)