summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJenkins <jenkins@review.openstack.org>2016-05-11 07:52:47 +0000
committerGerrit Code Review <review@openstack.org>2016-05-11 07:52:47 +0000
commit3a6c14981dbd26e12b7d77ebfbb501607557b97c (patch)
tree7c6ca10e50cbcba9df942bf0780940f12c3cdb15
parent3faa99bac13e6bd5224f8a984d1827bcedefc80d (diff)
parentfd5579a154694418c66075d97f43e5d9d741058b (diff)
downloadpython-swiftclient-3a6c14981dbd26e12b7d77ebfbb501607557b97c.tar.gz
Merge "Check responses when retrying bodies"
-rw-r--r--swiftclient/client.py17
-rw-r--r--tests/unit/test_swiftclient.py70
2 files changed, 85 insertions, 2 deletions
diff --git a/swiftclient/client.py b/swiftclient/client.py
index 4dbbd49..807cb3d 100644
--- a/swiftclient/client.py
+++ b/swiftclient/client.py
@@ -315,6 +315,23 @@ class _RetryBody(_ObjectBody):
response_dict=self.response_dict,
headers=self.headers,
attempts=self.conn.attempts)
+ expected_range = 'bytes %d-%d/%d' % (
+ self.bytes_read,
+ self.expected_length - 1,
+ self.expected_length)
+ if 'content-range' not in hdrs:
+ # Server didn't respond with partial content; manually seek
+ logger.warning('Received 200 while retrying %s/%s; seeking...',
+ self.container, self.obj)
+ to_read = self.bytes_read
+ while to_read > 0:
+ buf = body.resp.read(min(to_read, self.chunk_size))
+ to_read -= len(buf)
+ elif hdrs['content-range'] != expected_range:
+ msg = ('Expected range "%s" while retrying %s/%s '
+ 'but got "%s"' % (expected_range, self.container,
+ self.obj, hdrs['content-range']))
+ raise ClientException(msg)
self.resp = body.resp
buf = self.read(length)
return buf
diff --git a/tests/unit/test_swiftclient.py b/tests/unit/test_swiftclient.py
index f3bee3b..a51fe1a 100644
--- a/tests/unit/test_swiftclient.py
+++ b/tests/unit/test_swiftclient.py
@@ -926,9 +926,11 @@ class TestGetObject(MockHttpTest):
StubResponse(200, 'abcdef', {'etag': 'some etag',
'content-length': '6'}),
StubResponse(206, 'cdef', {'etag': 'some etag',
- 'content-length': '4'}),
+ 'content-length': '4',
+ 'content-range': 'bytes 2-5/6'}),
StubResponse(206, 'ef', {'etag': 'some etag',
- 'content-length': '2'}),
+ 'content-length': '2',
+ 'content-range': 'bytes 4-5/6'}),
)
__, resp = conn.get_object('asdf', 'asdf', resp_chunk_size=2)
self.assertEqual(next(resp), 'ab')
@@ -958,6 +960,70 @@ class TestGetObject(MockHttpTest):
}),
])
+ def test_chunk_size_iter_retry_no_range_support(self):
+ conn = c.Connection('http://auth.url/', 'some_user', 'some_key')
+ with mock.patch('swiftclient.client.get_auth_1_0') as mock_get_auth:
+ mock_get_auth.return_value = ('http://auth.url', 'tToken')
+ c.http_connection = self.fake_http_connection(*[
+ StubResponse(200, 'abcdef', {'etag': 'some etag',
+ 'content-length': '6'})
+ ] * 3)
+ __, resp = conn.get_object('asdf', 'asdf', resp_chunk_size=2)
+ self.assertEqual(next(resp), 'ab')
+ self.assertEqual(1, conn.attempts)
+ # simulate a dropped connection
+ resp.resp.read()
+ self.assertEqual(next(resp), 'cd')
+ self.assertEqual(2, conn.attempts)
+ # simulate a dropped connection
+ resp.resp.read()
+ self.assertEqual(next(resp), 'ef')
+ self.assertEqual(3, conn.attempts)
+ self.assertRaises(StopIteration, next, resp)
+ self.assertRequests([
+ ('GET', '/asdf/asdf', '', {
+ 'x-auth-token': 'tToken',
+ }),
+ ('GET', '/asdf/asdf', '', {
+ 'range': 'bytes=2-',
+ 'if-match': 'some etag',
+ 'x-auth-token': 'tToken',
+ }),
+ ('GET', '/asdf/asdf', '', {
+ 'range': 'bytes=4-',
+ 'if-match': 'some etag',
+ 'x-auth-token': 'tToken',
+ }),
+ ])
+
+ def test_chunk_size_iter_retry_bad_range_response(self):
+ conn = c.Connection('http://auth.url/', 'some_user', 'some_key')
+ with mock.patch('swiftclient.client.get_auth_1_0') as mock_get_auth:
+ mock_get_auth.return_value = ('http://auth.url', 'tToken')
+ c.http_connection = self.fake_http_connection(
+ StubResponse(200, 'abcdef', {'etag': 'some etag',
+ 'content-length': '6'}),
+ StubResponse(206, 'abcdef', {'etag': 'some etag',
+ 'content-length': '6',
+ 'content-range': 'chunk 1-2/3'})
+ )
+ __, resp = conn.get_object('asdf', 'asdf', resp_chunk_size=2)
+ self.assertEqual(next(resp), 'ab')
+ self.assertEqual(1, conn.attempts)
+ # simulate a dropped connection
+ resp.resp.read()
+ self.assertRaises(c.ClientException, next, resp)
+ self.assertRequests([
+ ('GET', '/asdf/asdf', '', {
+ 'x-auth-token': 'tToken',
+ }),
+ ('GET', '/asdf/asdf', '', {
+ 'range': 'bytes=2-',
+ 'if-match': 'some etag',
+ 'x-auth-token': 'tToken',
+ }),
+ ])
+
def test_get_object_with_resp_chunk_size_zero(self):
def get_connection(self):
def get_auth():