Rev 3494: Fix infinite busy-loop caused by connection loss during read of in file:///home/pqm/archives/thelove/bzr/%2Btrunk/
Canonical.com Patch Queue Manager
pqm at pqm.ubuntu.com
Wed Jun 11 13:04:01 BST 2008
At file:///home/pqm/archives/thelove/bzr/%2Btrunk/
------------------------------------------------------------
revno: 3494
revision-id:pqm at pqm.ubuntu.com-20080611120348-tqhq37qvfz624jyb
parent: pqm at pqm.ubuntu.com-20080611042056-m5e074q47s9gwwjj
parent: andrew.bennetts at canonical.com-20080611110805-oluknyiukp111t13
committer: Canonical.com Patch Queue Manager <pqm at pqm.ubuntu.com>
branch nick: +trunk
timestamp: Wed 2008-06-11 13:03:48 +0100
message:
Fix infinite busy-loop caused by connection loss during read of
response body in HPSS v1 and v2. (Andrew Bennetts)
modified:
NEWS NEWS-20050323055033-4e00b5db738777ff
bzrlib/smart/protocol.py protocol.py-20061108035435-ot0lstk2590yqhzr-1
bzrlib/tests/test_smart_transport.py test_ssh_transport.py-20060608202016-c25gvf1ob7ypbus6-2
------------------------------------------------------------
revno: 3464.4.2
revision-id:andrew.bennetts at canonical.com-20080611110805-oluknyiukp111t13
parent: andrew.bennetts at canonical.com-20080602011217-91w8f210rc3adv6g
parent: pqm at pqm.ubuntu.com-20080609211646-amc2rr2zi50omr8m
committer: Andrew Bennetts <andrew.bennetts at canonical.com>
branch nick: interrupted-connection-fix
timestamp: Wed 2008-06-11 21:08:05 +1000
message:
Merge from bzr.dev.
added:
bzrlib/tests/blackbox/test_alias.py test_alias.py-20080425112253-fbt0yz1c1834jriz-1
bzrlib/tests/blackbox/test_modified.py test_modified.py-20080424085848-nwqjenan4dq2vq3w-1
bzrlib/tests/per_repository_reference/ repository_external_-20080220025549-nnm2s80it1lvcwnc-1
bzrlib/tests/per_repository_reference/__init__.py __init__.py-20080220025549-nnm2s80it1lvcwnc-2
bzrlib/tests/per_repository_reference/test_add_inventory.py test_add_inventory.p-20080220025549-nnm2s80it1lvcwnc-3
bzrlib/tests/per_repository_reference/test_add_revision.py test_add_revision.py-20080220034108-ao1u8qgakqbo5a08-1
bzrlib/tests/per_repository_reference/test_add_signature_text.py test_add_signature_t-20080220041905-1j2g4lyz3c6h34v4-1
bzrlib/tests/per_repository_reference/test_all_revision_ids.py test_all_revision_id-20080220041905-1j2g4lyz3c6h34v4-2
bzrlib/tests/per_repository_reference/test_break_lock.py test_break_lock.py-20080220042825-1f48qmpnuqqp5wg2-1
bzrlib/tests/per_repository_reference/test_check.py test_check.py-20080220044229-sxxe747gzi6q8fyv-1
renamed:
doc/en/user-guide/revnos.txt => doc/en/user-guide/zen.txt revnos.txt-20080111231928-pbntxea0ynh9ww1t-1
modified:
NEWS NEWS-20050323055033-4e00b5db738777ff
bzrlib/__init__.py __init__.py-20050309040759-33e65acf91bbcd5d
bzrlib/branch.py branch.py-20050309040759-e4baf4e0d046576e
bzrlib/builtins.py builtins.py-20050830033751-fc01482b9ca23183
bzrlib/check.py check.py-20050309040759-f3a679400c06bcc1
bzrlib/config.py config.py-20051011043216-070c74f4e9e338e8
bzrlib/counted_lock.py counted_lock.py-20070502135927-7dk86io3ok7ctx6k-1
bzrlib/dirstate.py dirstate.py-20060728012006-d6mvoihjb3je9peu-1
bzrlib/errors.py errors.py-20050309040759-20512168c4e14fbd
bzrlib/knit.py knit.py-20051212171256-f056ac8f0fbe1bd9
bzrlib/lockdir.py lockdir.py-20060220222025-98258adf27fbdda3
bzrlib/merge_directive.py merge_directive.py-20070228184838-ja62280spt1g7f4x-1
bzrlib/remote.py remote.py-20060720103555-yeeg2x51vn0rbtdp-1
bzrlib/repository.py rev_storage.py-20051111201905-119e9401e46257e3
bzrlib/tag.py tag.py-20070212110532-91cw79inah2cfozx-1
bzrlib/tests/__init__.py selftest.py-20050531073622-8d0e3c8845c97a64
bzrlib/tests/blackbox/__init__.py __init__.py-20051128053524-eba30d8255e08dc3
bzrlib/tests/blackbox/test_added.py test_added.py-20060119085008-6b8b90369d42a26c
bzrlib/tests/blackbox/test_non_ascii.py test_non_ascii.py-20060105214030-68010be784a5d854
bzrlib/tests/blackbox/test_uncommit.py test_uncommit.py-20051027212835-84944b63adae51be
bzrlib/tests/blackbox/test_unknowns.py test_unknowns.py-20070905015344-74tg6s1synijo2oe-1
bzrlib/tests/branch_implementations/test_branch.py testbranch.py-20050711070244-121d632bc37d7253
bzrlib/tests/branch_implementations/test_pull.py test_pull.py-20060410103942-83c35b26657414fc
bzrlib/tests/http_server.py httpserver.py-20061012142527-m1yxdj1xazsf8d7s-1
bzrlib/tests/repository_implementations/__init__.py __init__.py-20060131092037-9564957a7d4a841b
bzrlib/tests/test_branch.py test_branch.py-20060116013032-97819aa07b8ab3b5
bzrlib/tests/test_config.py testconfig.py-20051011041908-742d0c15d8d8c8eb
bzrlib/tests/test_counted_lock.py test_counted_lock.py-20070502135927-7dk86io3ok7ctx6k-2
bzrlib/tests/test_diff.py testdiff.py-20050727164403-d1a3496ebb12e339
bzrlib/tests/test_dirstate.py test_dirstate.py-20060728012006-d6mvoihjb3je9peu-2
bzrlib/tests/test_lockable_files.py test_lockable_files.py-20051225183927-365c7fd99591caf1
bzrlib/tests/test_lockdir.py test_lockdir.py-20060220222025-33d4221569a3d600
bzrlib/tests/test_merge_directive.py test_merge_directive-20070228184838-ja62280spt1g7f4x-2
bzrlib/tests/test_msgeditor.py test_msgeditor.py-20051202041359-920315ec6011ee51
bzrlib/tests/test_selftest.py test_selftest.py-20051202044319-c110a115d8c0456a
bzrlib/tests/test_switch.py test_switch.py-20071116011000-v5lnw7d2wkng9eux-2
bzrlib/tests/test_transform.py test_transaction.py-20060105172520-b3ffb3946550e6c4
bzrlib/tests/test_transport_implementations.py test_transport_implementations.py-20051227111451-f97c5c7d5c49fce7
bzrlib/tests/test_versionedfile.py test_versionedfile.py-20060222045249-db45c9ed14a1c2e5
bzrlib/tests/test_workingtree_4.py test_workingtree_4.p-20070223025758-531n3tznl3zacv2o-1
bzrlib/tests/workingtree_implementations/test_parents.py test_set_parents.py-20060807231740-yicmnlci1mj8smu1-1
bzrlib/transform.py transform.py-20060105172343-dd99e54394d91687
bzrlib/transport/__init__.py transport.py-20050711165921-4978aa7ce1285ad5
bzrlib/versionedfile.py versionedfile.py-20060222045106-5039c71ee3b65490
bzrlib/workingtree.py workingtree.py-20050511021032-29b6ec0a681e02e3
bzrlib/workingtree_4.py workingtree_4.py-20070208044105-5fgpc5j3ljlh5q6c-1
contrib/bzr_access bzr_access-20071210163004-c9lb1renhra2ncg0-1
doc/en/user-guide/core_concepts.txt core_concepts.txt-20071114035000-q36a9h57ps06uvnl-2
doc/en/user-guide/index.txt index.txt-20060622101119-tgwtdci8z769bjb9-2
doc/en/user-guide/zen.txt revnos.txt-20080111231928-pbntxea0ynh9ww1t-1
------------------------------------------------------------
revno: 3464.4.1
revision-id:andrew.bennetts at canonical.com-20080602011217-91w8f210rc3adv6g
parent: pqm at pqm.ubuntu.com-20080601233619-di6or8d3o26n917q
committer: Andrew Bennetts <andrew.bennetts at canonical.com>
branch nick: interrupted-connection-fix
timestamp: Mon 2008-06-02 11:12:17 +1000
message:
Fix infinite busy-loop caused by connection loss during read of response body in HPSS v1 and v2.
modified:
NEWS NEWS-20050323055033-4e00b5db738777ff
bzrlib/smart/protocol.py protocol.py-20061108035435-ot0lstk2590yqhzr-1
bzrlib/tests/test_smart_transport.py test_ssh_transport.py-20060608202016-c25gvf1ob7ypbus6-2
=== modified file 'NEWS'
--- a/NEWS 2008-06-11 04:20:56 +0000
+++ b/NEWS 2008-06-11 12:03:48 +0000
@@ -49,6 +49,10 @@
reading from the repository.)
(Martin Pool, Andrew Bennetts, Robert Collins, #234748)
+ * Fix infinite loop consuming 100% CPU when a connection is lost while
+ reading a response body via the smart protocol v1 or v2.
+ (Andrew Bennetts)
+
* Inserting a bundle which changes the contents of a file with no trailing
end of line, causing a knit snapshot in a 'knits' repository will no longer
cause KnitCorrupt. (Robert Collins)
=== modified file 'bzrlib/smart/protocol.py'
--- a/bzrlib/smart/protocol.py 2008-05-21 02:49:58 +0000
+++ b/bzrlib/smart/protocol.py 2008-06-02 01:12:17 +0000
@@ -704,6 +704,10 @@
while not _body_decoder.finished_reading:
bytes_wanted = min(_body_decoder.next_read_size(), max_read)
bytes = self._request.read_bytes(bytes_wanted)
+ if bytes == '':
+ # end of file encountered reading from server
+ raise errors.ConnectionReset(
+ "Connection lost while reading response body.")
_body_decoder.accept_bytes(bytes)
self._request.finished_reading()
self._body_buffer = StringIO(_body_decoder.read_pending_data())
@@ -805,6 +809,10 @@
while not _body_decoder.finished_reading:
bytes_wanted = min(_body_decoder.next_read_size(), max_read)
bytes = self._request.read_bytes(bytes_wanted)
+ if bytes == '':
+ # end of file encountered reading from server
+ raise errors.ConnectionReset(
+ "Connection lost while reading streamed body.")
_body_decoder.accept_bytes(bytes)
for body_bytes in iter(_body_decoder.read_next_chunk, None):
if 'hpss' in debug.debug_flags and type(body_bytes) is str:
=== modified file 'bzrlib/tests/test_smart_transport.py'
--- a/bzrlib/tests/test_smart_transport.py 2008-05-30 04:33:39 +0000
+++ b/bzrlib/tests/test_smart_transport.py 2008-06-02 01:12:17 +0000
@@ -1803,6 +1803,19 @@
self.assertRaises(
errors.ReadingCompleted, smart_protocol.read_body_bytes)
+ def test_client_read_body_bytes_interrupted_connection(self):
+ server_bytes = "ok\n999\nincomplete body"
+ input = StringIO(server_bytes)
+ output = StringIO()
+ client_medium = medium.SmartSimplePipesClientMedium(
+ input, output, 'base')
+ request = client_medium.get_request()
+ smart_protocol = self.client_protocol_class(request)
+ smart_protocol.call('foo')
+ smart_protocol.read_response_tuple(True)
+ self.assertRaises(
+ errors.ConnectionReset, smart_protocol.read_body_bytes)
+
class TestVersionOneFeaturesInProtocolTwo(
TestSmartProtocol, CommonSmartProtocolTestMixin):
@@ -2029,6 +2042,20 @@
self.assertRaises(
errors.ReadingCompleted, smart_protocol.read_body_bytes)
+ def test_client_read_body_bytes_interrupted_connection(self):
+ server_bytes = (self.response_marker +
+ "success\nok\n999\nincomplete body")
+ input = StringIO(server_bytes)
+ output = StringIO()
+ client_medium = medium.SmartSimplePipesClientMedium(
+ input, output, 'base')
+ request = client_medium.get_request()
+ smart_protocol = self.client_protocol_class(request)
+ smart_protocol.call('foo')
+ smart_protocol.read_response_tuple(True)
+ self.assertRaises(
+ errors.ConnectionReset, smart_protocol.read_body_bytes)
+
class TestSmartProtocolTwoSpecificsMixin(object):
@@ -2154,6 +2181,22 @@
stream = smart_protocol.read_streamed_body()
self.assertEqual(expected_chunks, list(stream))
+ def test_streamed_body_bytes_interrupted_connection(self):
+ body_header = 'chunked\n'
+ incomplete_body_chunk = "9999\nincomplete chunk"
+ server_bytes = (protocol.RESPONSE_VERSION_TWO +
+ "success\nok\n" + body_header + incomplete_body_chunk)
+ input = StringIO(server_bytes)
+ output = StringIO()
+ client_medium = medium.SmartSimplePipesClientMedium(
+ input, output, 'base')
+ request = client_medium.get_request()
+ smart_protocol = protocol.SmartClientRequestProtocolTwo(request)
+ smart_protocol.call('foo')
+ smart_protocol.read_response_tuple(True)
+ stream = smart_protocol.read_streamed_body()
+ self.assertRaises(errors.ConnectionReset, stream.next)
+
def test_client_read_response_tuple_sets_response_status(self):
server_bytes = protocol.RESPONSE_VERSION_TWO + "success\nok\n"
input = StringIO(server_bytes)
@@ -2338,16 +2381,7 @@
class TestConventionalResponseHandler(tests.TestCase):
- def test_interrupted_body_stream(self):
- interrupted_body_stream = (
- 'oS' # successful response
- 's\0\0\0\x02le' # empty args
- 'b\0\0\0\x09chunk one' # first chunk
- 'b\0\0\0\x09chunk two' # second chunk
- 'oE' # error flag
- 's\0\0\0\x0el5:error3:abce' # bencoded error
- 'e' # message end
- )
+ def make_response_handler(self, response_bytes):
from bzrlib.smart.message import ConventionalResponseHandler
response_handler = ConventionalResponseHandler()
protocol_decoder = protocol.ProtocolThreeDecoder(response_handler)
@@ -2355,17 +2389,48 @@
protocol_decoder.state_accept = protocol_decoder._state_accept_expecting_message_part
output = StringIO()
client_medium = medium.SmartSimplePipesClientMedium(
- StringIO(interrupted_body_stream), output, 'base')
+ StringIO(response_bytes), output, 'base')
medium_request = client_medium.get_request()
medium_request.finished_writing()
response_handler.setProtoAndMediumRequest(
protocol_decoder, medium_request)
+ return response_handler
+
+ def test_body_stream_interrupted_by_error(self):
+ interrupted_body_stream = (
+ 'oS' # successful response
+ 's\0\0\0\x02le' # empty args
+ 'b\0\0\0\x09chunk one' # first chunk
+ 'b\0\0\0\x09chunk two' # second chunk
+ 'oE' # error flag
+ 's\0\0\0\x0el5:error3:abce' # bencoded error
+ 'e' # message end
+ )
+ response_handler = self.make_response_handler(interrupted_body_stream)
stream = response_handler.read_streamed_body()
self.assertEqual('chunk one', stream.next())
self.assertEqual('chunk two', stream.next())
exc = self.assertRaises(errors.ErrorFromSmartServer, stream.next)
self.assertEqual(('error', 'abc'), exc.error_tuple)
+ def test_body_stream_interrupted_by_connection_lost(self):
+ interrupted_body_stream = (
+ 'oS' # successful response
+ 's\0\0\0\x02le' # empty args
+ 'b\0\0\xff\xffincomplete chunk')
+ response_handler = self.make_response_handler(interrupted_body_stream)
+ stream = response_handler.read_streamed_body()
+ self.assertRaises(errors.ConnectionReset, stream.next)
+
+ def test_read_body_bytes_interrupted_by_connection_lost(self):
+ interrupted_body_stream = (
+ 'oS' # successful response
+ 's\0\0\0\x02le' # empty args
+ 'b\0\0\xff\xffincomplete chunk')
+ response_handler = self.make_response_handler(interrupted_body_stream)
+ self.assertRaises(
+ errors.ConnectionReset, response_handler.read_body_bytes)
+
class TestMessageHandlerErrors(tests.TestCase):
"""Tests for v3 that unrecognised (but well-formed) requests/responses are
More information about the bazaar-commits
mailing list