Return correct etag for raw manifest

When client sends a '?multipart-manifest=get&format=raw' request
middleware will change the manifest returned from object server.
This patch makes sure the response etag is updated to reflect
changes to manifest content

Change-Id: I0ac6dd0808fb041ba7663f4a472a06ee3f1d9a71
This commit is contained in:
Thiago da Silva 2020-01-23 19:15:05 +11:00
parent d3916312d3
commit b8c16de023
3 changed files with 24 additions and 13 deletions

View File

@ -901,7 +901,7 @@ class SloGetContext(WSGIContext):
seg_dict['size_bytes'] = seg_dict.pop('bytes', None) seg_dict['size_bytes'] = seg_dict.pop('bytes', None)
seg_dict['etag'] = seg_dict.pop('hash', None) seg_dict['etag'] = seg_dict.pop('hash', None)
json_data = json.dumps(segments) # convert to string json_data = json.dumps(segments, sort_keys=True) # convert to string
if six.PY3: if six.PY3:
json_data = json_data.encode('utf-8') json_data = json_data.encode('utf-8')
@ -909,6 +909,8 @@ class SloGetContext(WSGIContext):
for header, value in resp_headers: for header, value in resp_headers:
if header.lower() == 'content-length': if header.lower() == 'content-length':
new_headers.append(('Content-Length', len(json_data))) new_headers.append(('Content-Length', len(json_data)))
elif header.lower() == 'etag':
new_headers.append(('Etag', md5(json_data).hexdigest()))
else: else:
new_headers.append((header, value)) new_headers.append((header, value))
self._response_headers = new_headers self._response_headers = new_headers

View File

@ -1098,6 +1098,12 @@ class TestSlo(Base):
manifest = self.env.container.file("manifest-db") manifest = self.env.container.file("manifest-db")
got_body = manifest.read(parms={'multipart-manifest': 'get', got_body = manifest.read(parms={'multipart-manifest': 'get',
'format': 'raw'}) 'format': 'raw'})
body_md5 = hashlib.md5(got_body).hexdigest()
headers = dict(
(h.lower(), v)
for h, v in manifest.conn.response.getheaders())
self.assertIn('etag', headers)
self.assertEqual(headers['etag'], body_md5)
# raw format should have the actual manifest object content-type # raw format should have the actual manifest object content-type
self.assertEqual('application/octet-stream', manifest.content_type) self.assertEqual('application/octet-stream', manifest.content_type)

View File

@ -1724,26 +1724,29 @@ class TestSloGetRawManifest(SloTestCase):
'HTTP_ACCEPT': 'application/json'}) 'HTTP_ACCEPT': 'application/json'})
status, headers, body = self.call_slo(req) status, headers, body = self.call_slo(req)
self.assertEqual(status, '200 OK') expected_body = json.dumps([
self.assertTrue(('Etag', self.bc_etag) in headers, headers) {'etag': md5hex('b' * 10), 'size_bytes': '10',
self.assertTrue(('X-Static-Large-Object', 'true') in headers, headers)
# raw format should return the actual manifest object content-type
self.assertIn(('Content-Type', 'text/plain'), headers)
try:
resp_data = json.loads(body)
except ValueError:
self.fail("Invalid JSON in manifest GET: %r" % body)
self.assertEqual(
resp_data,
[{'etag': md5hex('b' * 10), 'size_bytes': '10',
'path': '/gettest/b_10'}, 'path': '/gettest/b_10'},
{'etag': md5hex('c' * 15), 'size_bytes': '15', {'etag': md5hex('c' * 15), 'size_bytes': '15',
'path': '/gettest/c_15'}, 'path': '/gettest/c_15'},
{'etag': md5hex(md5hex("e" * 5) + md5hex("f" * 5)), {'etag': md5hex(md5hex("e" * 5) + md5hex("f" * 5)),
'size_bytes': '10', 'size_bytes': '10',
'path': '/gettest/d_10'}]) 'path': '/gettest/d_10'}], sort_keys=True)
expected_etag = md5hex(expected_body)
if six.PY3:
expected_body = expected_body.encode('utf-8')
self.assertEqual(body, expected_body)
self.assertEqual(status, '200 OK')
self.assertTrue(('Etag', expected_etag) in headers, headers)
self.assertTrue(('X-Static-Large-Object', 'true') in headers, headers)
# raw format should return the actual manifest object content-type
self.assertIn(('Content-Type', 'text/plain'), headers)
try:
json.loads(body)
except ValueError:
self.fail("Invalid JSON in manifest GET: %r" % body)
def test_get_raw_manifest_passthrough_with_ranges(self): def test_get_raw_manifest_passthrough_with_ranges(self):
req = Request.blank( req = Request.blank(