Merge "Fix response of PUT Object Copy requests"

This commit is contained in:
Jenkins
2015-01-15 02:26:57 +00:00
committed by Gerrit Code Review
2 changed files with 51 additions and 31 deletions

View File

@@ -17,8 +17,7 @@ from swift.common.http import HTTP_OK
from swift.common.swob import Range, content_range_header_value from swift.common.swob import Range, content_range_header_value
from swift3.controllers.base import Controller from swift3.controllers.base import Controller
from swift3.response import HTTPOk, S3NotImplemented, InvalidRange,\ from swift3.response import S3NotImplemented, InvalidRange, HTTPPartialContent
HTTPPartialContent
from swift3.etree import Element, SubElement, tostring from swift3.etree import Element, SubElement, tostring
@@ -99,9 +98,12 @@ class ObjectController(Controller):
if 'X-Amz-Copy-Source' in req.headers: if 'X-Amz-Copy-Source' in req.headers:
elem = Element('CopyObjectResult') elem = Element('CopyObjectResult')
SubElement(elem, 'LastModified').text = \
resp.last_modified.isoformat()[:-6] + '.000Z'
SubElement(elem, 'ETag').text = '"%s"' % resp.etag SubElement(elem, 'ETag').text = '"%s"' % resp.etag
body = tostring(elem, use_s3ns=False) resp.body = tostring(elem)
return HTTPOk(body=body, headers=resp.headers) resp.headers['Content-Type'] = 'application/xml'
resp.etag = None
resp.status = HTTP_OK resp.status = HTTP_OK
return resp return resp

View File

@@ -24,6 +24,7 @@ from swift.common.swob import Request
from swift3.test.unit import Swift3TestCase from swift3.test.unit import Swift3TestCase
from swift3.test.unit.test_s3_acl import s3acl from swift3.test.unit.test_s3_acl import s3acl
from swift3.subresource import ACL, User, encode_acl, Owner, Grant from swift3.subresource import ACL, User, encode_acl, Owner, Grant
from swift3.etree import fromstring
class TestSwift3Obj(Swift3TestCase): class TestSwift3Obj(Swift3TestCase):
@@ -32,17 +33,23 @@ class TestSwift3Obj(Swift3TestCase):
super(TestSwift3Obj, self).setUp() super(TestSwift3Obj, self).setUp()
self.object_body = 'hello' self.object_body = 'hello'
etag = hashlib.md5(self.object_body).hexdigest() self.etag = hashlib.md5(self.object_body).hexdigest()
self.last_modified = 'Fri, 01 Apr 2014 12:00:00 GMT'
self.response_headers = {'Content-Type': 'text/html', self.response_headers = {'Content-Type': 'text/html',
'Content-Length': len(self.object_body), 'Content-Length': len(self.object_body),
'x-object-meta-test': 'swift', 'x-object-meta-test': 'swift',
'etag': etag, 'etag': self.etag,
'last-modified': '2011-01-05T02:19:14.275290'} 'last-modified': self.last_modified}
self.swift.register('GET', '/v1/AUTH_test/bucket/object', self.swift.register('GET', '/v1/AUTH_test/bucket/object',
swob.HTTPOk, self.response_headers, swob.HTTPOk, self.response_headers,
self.object_body) self.object_body)
self.swift.register('PUT', '/v1/AUTH_test/bucket/object',
swob.HTTPCreated,
{'etag': self.etag,
'last-modified': self.last_modified},
None)
def _test_object_GETorHEAD(self, method): def _test_object_GETorHEAD(self, method):
req = Request.blank('/bucket/object', req = Request.blank('/bucket/object',
@@ -332,15 +339,10 @@ class TestSwift3Obj(Swift3TestCase):
self.assertEquals(headers['etag'], etag) self.assertEquals(headers['etag'], etag)
def test_object_PUT_headers(self): def test_object_PUT_headers(self):
etag = '7dfa07a8e59ddbcd1dc84d4c4f82aea1' content_md5 = self.etag.decode('hex').encode('base64').strip()
content_md5 = etag.decode('hex').encode('base64').strip()
self.swift.register('HEAD', '/v1/AUTH_test/some/source', self.swift.register('HEAD', '/v1/AUTH_test/some/source',
swob.HTTPOk, {}, None) swob.HTTPOk, {}, None)
self.swift.register('PUT', '/v1/AUTH_test/bucket/object',
swob.HTTPCreated,
{'etag': etag},
None)
req = Request.blank( req = Request.blank(
'/bucket/object', '/bucket/object',
environ={'REQUEST_METHOD': 'PUT'}, environ={'REQUEST_METHOD': 'PUT'},
@@ -352,17 +354,19 @@ class TestSwift3Obj(Swift3TestCase):
req.date = datetime.now() req.date = datetime.now()
req.content_type = 'text/plain' req.content_type = 'text/plain'
status, headers, body = self.call_swift3(req) status, headers, body = self.call_swift3(req)
# Check that swift3 returns an etag header. # Check that swift3 dones not return an etag header,
self.assertEquals(headers['etag'], '"%s"' % etag) # sepcified copy source.
self.assertTrue(headers.get('etag') is None)
self.assertEquals(headers['last-modified'], self.last_modified)
_, _, headers = self.swift.calls_with_headers[-1] _, _, headers = self.swift.calls_with_headers[-1]
# Check that swift3 converts a Content-MD5 header into an etag. # Check that swift3 converts a Content-MD5 header into an etag.
self.assertEquals(headers['ETag'], etag) self.assertEquals(headers['ETag'], self.etag)
self.assertEquals(headers['X-Object-Meta-Something'], 'oh hai') self.assertEquals(headers['X-Object-Meta-Something'], 'oh hai')
self.assertEquals(headers['X-Copy-From'], '/some/source') self.assertEquals(headers['X-Copy-From'], '/some/source')
self.assertEquals(headers['Content-Length'], '0') self.assertEquals(headers['Content-Length'], '0')
def _test_object_PUT_copy_headers(self, head_resp, put_header): def _test_object_PUT_copy(self, head_resp, put_header={}):
account = 'test:tester' account = 'test:tester'
grants = [Grant(User(account), 'FULL_CONTROL')] grants = [Grant(User(account), 'FULL_CONTROL')]
head_headers = \ head_headers = \
@@ -370,8 +374,6 @@ class TestSwift3Obj(Swift3TestCase):
ACL(Owner(account, account), grants)) ACL(Owner(account, account), grants))
self.swift.register('HEAD', '/v1/AUTH_test/some/source', self.swift.register('HEAD', '/v1/AUTH_test/some/source',
head_resp, head_headers, None) head_resp, head_headers, None)
self.swift.register('PUT', '/v1/AUTH_test/bucket/object',
swob.HTTPCreated, {}, None)
put_headers = {'Authorization': 'AWS test:tester:hmac', put_headers = {'Authorization': 'AWS test:tester:hmac',
'X-Amz-Copy-Source': '/some/source'} 'X-Amz-Copy-Source': '/some/source'}
@@ -385,6 +387,22 @@ class TestSwift3Obj(Swift3TestCase):
req.content_type = 'text/plain' req.content_type = 'text/plain'
return self.call_swift3(req) return self.call_swift3(req)
@s3acl
def test_object_PUT_copy(self):
iso_format = '2014-04-01T12:00:00.000Z'
status, headers, body = \
self._test_object_PUT_copy(swob.HTTPOk)
self.assertEquals(status.split()[0], '200')
self.assertEquals(headers['Content-Type'], 'application/xml')
self.assertTrue(headers.get('etag') is None)
elem = fromstring(body, 'CopyObjectResult')
self.assertEquals(elem.find('LastModified').text, iso_format)
self.assertEquals(elem.find('ETag').text, '"%s"' % self.etag)
_, _, headers = self.swift.calls_with_headers[-1]
self.assertEquals(headers['X-Copy-From'], '/some/source')
self.assertEquals(headers['Content-Length'], '0')
@s3acl @s3acl
def test_object_PUT_copy_headers_error(self): def test_object_PUT_copy_headers_error(self):
etag = '7dfa07a8e59ddbcd1dc84d4c4f82aea1' etag = '7dfa07a8e59ddbcd1dc84d4c4f82aea1'
@@ -392,27 +410,27 @@ class TestSwift3Obj(Swift3TestCase):
header = {'X-Amz-Copy-Source-If-Match': etag} header = {'X-Amz-Copy-Source-If-Match': etag}
status, header, body = \ status, header, body = \
self._test_object_PUT_copy_headers(swob.HTTPPreconditionFailed, self._test_object_PUT_copy(swob.HTTPPreconditionFailed,
header) header)
self.assertEquals(self._get_error_code(body), 'PreconditionFailed') self.assertEquals(self._get_error_code(body), 'PreconditionFailed')
header = {'X-Amz-Copy-Source-If-None-Match': etag} header = {'X-Amz-Copy-Source-If-None-Match': etag}
status, header, body = \ status, header, body = \
self._test_object_PUT_copy_headers(swob.HTTPNotModified, self._test_object_PUT_copy(swob.HTTPNotModified,
header) header)
self.assertEquals(self._get_error_code(body), 'PreconditionFailed') self.assertEquals(self._get_error_code(body), 'PreconditionFailed')
header = {'X-Amz-Copy-Source-If-Modified-Since': last_modified_since} header = {'X-Amz-Copy-Source-If-Modified-Since': last_modified_since}
status, header, body = \ status, header, body = \
self._test_object_PUT_copy_headers(swob.HTTPNotModified, self._test_object_PUT_copy(swob.HTTPNotModified,
header) header)
self.assertEquals(self._get_error_code(body), 'PreconditionFailed') self.assertEquals(self._get_error_code(body), 'PreconditionFailed')
header = \ header = \
{'X-Amz-Copy-Source-If-Unmodified-Since': last_modified_since} {'X-Amz-Copy-Source-If-Unmodified-Since': last_modified_since}
status, header, body = \ status, header, body = \
self._test_object_PUT_copy_headers(swob.HTTPPreconditionFailed, self._test_object_PUT_copy(swob.HTTPPreconditionFailed,
header) header)
self.assertEquals(self._get_error_code(body), 'PreconditionFailed') self.assertEquals(self._get_error_code(body), 'PreconditionFailed')
def test_object_PUT_copy_headers_with_match(self): def test_object_PUT_copy_headers_with_match(self):
@@ -422,7 +440,7 @@ class TestSwift3Obj(Swift3TestCase):
header = {'X-Amz-Copy-Source-If-Match': etag, header = {'X-Amz-Copy-Source-If-Match': etag,
'X-Amz-Copy-Source-If-Modified-Since': last_modified_since} 'X-Amz-Copy-Source-If-Modified-Since': last_modified_since}
status, header, body = \ status, header, body = \
self._test_object_PUT_copy_headers(swob.HTTPOk, header) self._test_object_PUT_copy(swob.HTTPOk, header)
self.assertEquals(status.split()[0], '200') self.assertEquals(status.split()[0], '200')
self.assertEquals(len(self.swift.calls_with_headers), 2) self.assertEquals(len(self.swift.calls_with_headers), 2)
_, _, headers = self.swift.calls_with_headers[-1] _, _, headers = self.swift.calls_with_headers[-1]
@@ -440,7 +458,7 @@ class TestSwift3Obj(Swift3TestCase):
header = {'X-Amz-Copy-Source-If-Match': etag, header = {'X-Amz-Copy-Source-If-Match': etag,
'X-Amz-Copy-Source-If-Modified-Since': last_modified_since} 'X-Amz-Copy-Source-If-Modified-Since': last_modified_since}
status, header, body = \ status, header, body = \
self._test_object_PUT_copy_headers(swob.HTTPOk, header) self._test_object_PUT_copy(swob.HTTPOk, header)
self.assertEquals(status.split()[0], '200') self.assertEquals(status.split()[0], '200')
self.assertEquals(len(self.swift.calls_with_headers), 3) self.assertEquals(len(self.swift.calls_with_headers), 3)
@@ -463,7 +481,7 @@ class TestSwift3Obj(Swift3TestCase):
header = {'X-Amz-Copy-Source-If-None-Match': etag, header = {'X-Amz-Copy-Source-If-None-Match': etag,
'X-Amz-Copy-Source-If-Unmodified-Since': last_modified_since} 'X-Amz-Copy-Source-If-Unmodified-Since': last_modified_since}
status, header, body = \ status, header, body = \
self._test_object_PUT_copy_headers(swob.HTTPOk, header) self._test_object_PUT_copy(swob.HTTPOk, header)
self.assertEquals(status.split()[0], '200') self.assertEquals(status.split()[0], '200')
self.assertEquals(len(self.swift.calls_with_headers), 2) self.assertEquals(len(self.swift.calls_with_headers), 2)
@@ -482,7 +500,7 @@ class TestSwift3Obj(Swift3TestCase):
header = {'X-Amz-Copy-Source-If-None-Match': etag, header = {'X-Amz-Copy-Source-If-None-Match': etag,
'X-Amz-Copy-Source-If-Unmodified-Since': last_modified_since} 'X-Amz-Copy-Source-If-Unmodified-Since': last_modified_since}
status, header, body = \ status, header, body = \
self._test_object_PUT_copy_headers(swob.HTTPOk, header) self._test_object_PUT_copy(swob.HTTPOk, header)
self.assertEquals(status.split()[0], '200') self.assertEquals(status.split()[0], '200')
# After the check of the copy source in the case of s3acl is valid, # After the check of the copy source in the case of s3acl is valid,
# Swift3 check the bucket write permissions of the destination. # Swift3 check the bucket write permissions of the destination.