diff --git a/swift/common/middleware/dlo.py b/swift/common/middleware/dlo.py index 5ab9d3dad3..d9222273df 100644 --- a/swift/common/middleware/dlo.py +++ b/swift/common/middleware/dlo.py @@ -126,7 +126,7 @@ from hashlib import md5 from swift.common import constraints from swift.common.exceptions import ListingIterError, SegmentError from swift.common.http import is_success -from swift.common.swob import Request, Response, \ +from swift.common.swob import Request, Response, HTTPException, \ HTTPRequestedRangeNotSatisfiable, HTTPBadRequest, HTTPConflict, \ str_to_wsgi, wsgi_to_str, wsgi_quote, wsgi_unquote, normalize_etag from swift.common.utils import get_logger, \ @@ -355,6 +355,8 @@ class GetContext(WSGIContext): try: app_iter.validate_first_segment() + except HTTPException as err_resp: + return err_resp except (SegmentError, ListingIterError): return HTTPConflict(request=req) diff --git a/swift/common/request_helpers.py b/swift/common/request_helpers.py index f79b47f9ca..0bf4196543 100644 --- a/swift/common/request_helpers.py +++ b/swift/common/request_helpers.py @@ -32,7 +32,7 @@ from swift import gettext_ as _ from swift.common.constraints import AUTO_CREATE_ACCOUNT_PREFIX from swift.common.storage_policy import POLICIES from swift.common.exceptions import ListingIterError, SegmentError -from swift.common.http import is_success +from swift.common.http import is_success, is_server_error from swift.common.swob import HTTPBadRequest, \ HTTPServiceUnavailable, Range, is_chunked, multi_range_iterator, \ HTTPPreconditionFailed, wsgi_to_bytes, wsgi_unquote, wsgi_to_str @@ -568,13 +568,16 @@ class SegmentedIterable(object): body = seg_resp.body if not six.PY2: body = body.decode('utf8') - raise SegmentError( - 'While processing manifest %s, ' - 'got %d (%s) while retrieving %s' % - (self.name, seg_resp.status_int, - body if len(body) <= 60 else body[:57] + '...', - seg_req.path)) - + msg = 'While processing manifest %s, got %d (%s) ' \ + 'while retrieving %s' % ( + self.name, seg_resp.status_int, + body if len(body) <= 60 else body[:57] + '...', + seg_req.path) + if is_server_error(seg_resp.status_int): + self.logger.error(msg) + raise HTTPServiceUnavailable( + request=seg_req, content_type='text/plain') + raise SegmentError(msg) elif ((seg_etag and (seg_resp.etag != seg_etag)) or (seg_size and (seg_resp.content_length != seg_size) and not seg_req.range)): diff --git a/test/unit/common/middleware/test_dlo.py b/test/unit/common/middleware/test_dlo.py index 24bdd72bd5..276d887289 100644 --- a/test/unit/common/middleware/test_dlo.py +++ b/test/unit/common/middleware/test_dlo.py @@ -583,7 +583,23 @@ class TestDloGetManifest(DloTestCase): self.assertFalse('If-Modified-Since' in hdrs) self.assertFalse('If-Unmodified-Since' in hdrs) - def test_error_fetching_first_segment(self): + def test_server_error_fetching_first_segment(self): + self.app.register( + 'GET', '/v1/AUTH_test/c/seg_01', + swob.HTTPServiceUnavailable, {}, None) + + req = swob.Request.blank('/v1/AUTH_test/mancon/manifest', + environ={'REQUEST_METHOD': 'GET'}) + status, headers, body = self.call_dlo(req) + self.assertEqual(status, "503 Service Unavailable") + self.assertEqual(self.app.unread_requests, {}) + self.assertEqual(self.dlo.logger.get_lines_for_level('error'), [ + 'While processing manifest /v1/AUTH_test/mancon/manifest, ' + 'got 503 (

Service Unavailable

The server is ' + 'curren...) while retrieving /v1/AUTH_test/c/seg_01', + ]) + + def test_client_error_fetching_first_segment(self): self.app.register( 'GET', '/v1/AUTH_test/c/seg_01', swob.HTTPForbidden, {}, None) diff --git a/test/unit/common/middleware/test_slo.py b/test/unit/common/middleware/test_slo.py index d6b6d1f413..fd499ac927 100644 --- a/test/unit/common/middleware/test_slo.py +++ b/test/unit/common/middleware/test_slo.py @@ -3549,6 +3549,32 @@ class TestSloGetManifest(SloTestCase): 'gettest/not_exists_obj' ]) + def test_first_segment_not_available(self): + self.app.register('GET', '/v1/AUTH_test/gettest/not_avail_obj', + swob.HTTPServiceUnavailable, {}, None) + self.app.register('GET', '/v1/AUTH_test/gettest/manifest-not-avail', + swob.HTTPOk, {'Content-Type': 'application/json', + 'X-Static-Large-Object': 'true'}, + json.dumps([{'name': '/gettest/not_avail_obj', + 'hash': md5hex('not_avail_obj'), + 'content_type': 'text/plain', + 'bytes': '%d' % len('not_avail_obj') + }])) + + req = Request.blank('/v1/AUTH_test/gettest/manifest-not-avail', + environ={'REQUEST_METHOD': 'GET'}) + status, headers, body = self.call_slo(req) + + self.assertEqual('503 Service Unavailable', status) + self.assertEqual(self.app.unread_requests, {}) + self.assertEqual(self.slo.logger.get_lines_for_level('error'), [ + 'While processing manifest /v1/AUTH_test/gettest/' + 'manifest-not-avail, got 503 (

Service Unavailable

' + '

The server is curren...) while retrieving /v1/AUTH_test/' + 'gettest/not_avail_obj' + ]) + self.assertIn(b'Service Unavailable', body) + def test_leading_data_segment(self): slo_etag = md5hex( md5hex('preamble') +