Merge "s3api: Fix non-ascii MPUs"
This commit is contained in:
commit
6e0ec0ad9c
@ -144,7 +144,7 @@ def _make_complete_body(req, s3_etag, yielded_anything):
|
|||||||
|
|
||||||
SubElement(result_elem, 'Location').text = host_url + req.path
|
SubElement(result_elem, 'Location').text = host_url + req.path
|
||||||
SubElement(result_elem, 'Bucket').text = req.container_name
|
SubElement(result_elem, 'Bucket').text = req.container_name
|
||||||
SubElement(result_elem, 'Key').text = req.object_name
|
SubElement(result_elem, 'Key').text = wsgi_to_str(req.object_name)
|
||||||
SubElement(result_elem, 'ETag').text = '"%s"' % s3_etag
|
SubElement(result_elem, 'ETag').text = '"%s"' % s3_etag
|
||||||
body = tostring(result_elem, xml_declaration=not yielded_anything)
|
body = tostring(result_elem, xml_declaration=not yielded_anything)
|
||||||
if yielded_anything:
|
if yielded_anything:
|
||||||
@ -452,7 +452,7 @@ class UploadsController(Controller):
|
|||||||
|
|
||||||
result_elem = Element('InitiateMultipartUploadResult')
|
result_elem = Element('InitiateMultipartUploadResult')
|
||||||
SubElement(result_elem, 'Bucket').text = req.container_name
|
SubElement(result_elem, 'Bucket').text = req.container_name
|
||||||
SubElement(result_elem, 'Key').text = req.object_name
|
SubElement(result_elem, 'Key').text = wsgi_to_str(req.object_name)
|
||||||
SubElement(result_elem, 'UploadId').text = upload_id
|
SubElement(result_elem, 'UploadId').text = upload_id
|
||||||
|
|
||||||
body = tostring(result_elem)
|
body = tostring(result_elem)
|
||||||
@ -498,9 +498,10 @@ class UploadController(Controller):
|
|||||||
part_num_marker = req.get_validated_param(
|
part_num_marker = req.get_validated_param(
|
||||||
'part-number-marker', 0)
|
'part-number-marker', 0)
|
||||||
|
|
||||||
|
object_name = wsgi_to_str(req.object_name)
|
||||||
query = {
|
query = {
|
||||||
'format': 'json',
|
'format': 'json',
|
||||||
'prefix': '%s/%s/' % (req.object_name, upload_id),
|
'prefix': '%s/%s/' % (object_name, upload_id),
|
||||||
'delimiter': '/',
|
'delimiter': '/',
|
||||||
'marker': '',
|
'marker': '',
|
||||||
}
|
}
|
||||||
@ -516,7 +517,10 @@ class UploadController(Controller):
|
|||||||
if not new_objects:
|
if not new_objects:
|
||||||
break
|
break
|
||||||
objects.extend(new_objects)
|
objects.extend(new_objects)
|
||||||
query['marker'] = new_objects[-1]['name']
|
if six.PY2:
|
||||||
|
query['marker'] = new_objects[-1]['name'].encode('utf-8')
|
||||||
|
else:
|
||||||
|
query['marker'] = new_objects[-1]['name']
|
||||||
|
|
||||||
last_part = 0
|
last_part = 0
|
||||||
|
|
||||||
@ -542,10 +546,9 @@ class UploadController(Controller):
|
|||||||
|
|
||||||
result_elem = Element('ListPartsResult')
|
result_elem = Element('ListPartsResult')
|
||||||
SubElement(result_elem, 'Bucket').text = req.container_name
|
SubElement(result_elem, 'Bucket').text = req.container_name
|
||||||
name = req.object_name
|
|
||||||
if encoding_type == 'url':
|
if encoding_type == 'url':
|
||||||
name = quote(name)
|
object_name = quote(object_name)
|
||||||
SubElement(result_elem, 'Key').text = name
|
SubElement(result_elem, 'Key').text = object_name
|
||||||
SubElement(result_elem, 'UploadId').text = upload_id
|
SubElement(result_elem, 'UploadId').text = upload_id
|
||||||
|
|
||||||
initiator_elem = SubElement(result_elem, 'Initiator')
|
initiator_elem = SubElement(result_elem, 'Initiator')
|
||||||
@ -613,7 +616,10 @@ class UploadController(Controller):
|
|||||||
container = req.container_name + MULTIUPLOAD_SUFFIX
|
container = req.container_name + MULTIUPLOAD_SUFFIX
|
||||||
obj = bytes_to_wsgi(o['name'].encode('utf-8'))
|
obj = bytes_to_wsgi(o['name'].encode('utf-8'))
|
||||||
req.get_response(self.app, container=container, obj=obj)
|
req.get_response(self.app, container=container, obj=obj)
|
||||||
query['marker'] = objects[-1]['name']
|
if six.PY2:
|
||||||
|
query['marker'] = objects[-1]['name'].encode('utf-8')
|
||||||
|
else:
|
||||||
|
query['marker'] = objects[-1]['name']
|
||||||
resp = req.get_response(self.app, 'GET', container, '',
|
resp = req.get_response(self.app, 'GET', container, '',
|
||||||
query=query)
|
query=query)
|
||||||
objects = json.loads(resp.body)
|
objects = json.loads(resp.body)
|
||||||
|
@ -626,6 +626,7 @@ class S3Request(swob.Request):
|
|||||||
return None
|
return None
|
||||||
|
|
||||||
def _parse_uri(self):
|
def _parse_uri(self):
|
||||||
|
# NB: returns WSGI strings
|
||||||
if not check_utf8(swob.wsgi_to_str(self.environ['PATH_INFO'])):
|
if not check_utf8(swob.wsgi_to_str(self.environ['PATH_INFO'])):
|
||||||
raise InvalidURI(self.path)
|
raise InvalidURI(self.path)
|
||||||
|
|
||||||
|
@ -98,6 +98,13 @@ class Connection(object):
|
|||||||
upload.cancel_upload()
|
upload.cancel_upload()
|
||||||
|
|
||||||
for obj in bucket.list_versions():
|
for obj in bucket.list_versions():
|
||||||
|
if six.PY2:
|
||||||
|
if not isinstance(obj.name, bytes):
|
||||||
|
obj.name = obj.name.encode('utf-8')
|
||||||
|
if obj.version_id is not None and \
|
||||||
|
not isinstance(obj.version_id, bytes):
|
||||||
|
obj.version_id = \
|
||||||
|
obj.version_id.encode('utf-8')
|
||||||
bucket.delete_key(
|
bucket.delete_key(
|
||||||
obj.name, version_id=obj.version_id)
|
obj.name, version_id=obj.version_id)
|
||||||
|
|
||||||
|
@ -23,6 +23,7 @@ import boto
|
|||||||
# pylint: disable-msg=E0611,F0401
|
# pylint: disable-msg=E0611,F0401
|
||||||
from distutils.version import StrictVersion
|
from distutils.version import StrictVersion
|
||||||
|
|
||||||
|
import six
|
||||||
from six.moves import zip, zip_longest
|
from six.moves import zip, zip_longest
|
||||||
|
|
||||||
import test.functional as tf
|
import test.functional as tf
|
||||||
@ -111,7 +112,7 @@ class TestS3ApiMultiUpload(S3ApiBase):
|
|||||||
|
|
||||||
def test_object_multi_upload(self):
|
def test_object_multi_upload(self):
|
||||||
bucket = 'bucket'
|
bucket = 'bucket'
|
||||||
keys = ['obj1', 'obj2', 'obj3']
|
keys = [u'obj1\N{SNOWMAN}', 'obj2', 'obj3']
|
||||||
bad_content_md5 = base64.b64encode(b'a' * 16).strip().decode('ascii')
|
bad_content_md5 = base64.b64encode(b'a' * 16).strip().decode('ascii')
|
||||||
headers = [{'Content-Type': 'foo/bar', 'x-amz-meta-baz': 'quux'},
|
headers = [{'Content-Type': 'foo/bar', 'x-amz-meta-baz': 'quux'},
|
||||||
{'Content-MD5': bad_content_md5},
|
{'Content-MD5': bad_content_md5},
|
||||||
@ -133,6 +134,8 @@ class TestS3ApiMultiUpload(S3ApiBase):
|
|||||||
elem = fromstring(body, 'InitiateMultipartUploadResult')
|
elem = fromstring(body, 'InitiateMultipartUploadResult')
|
||||||
self.assertEqual(elem.find('Bucket').text, bucket)
|
self.assertEqual(elem.find('Bucket').text, bucket)
|
||||||
key = elem.find('Key').text
|
key = elem.find('Key').text
|
||||||
|
if six.PY2:
|
||||||
|
expected_key = expected_key.encode('utf-8')
|
||||||
self.assertEqual(expected_key, key)
|
self.assertEqual(expected_key, key)
|
||||||
upload_id = elem.find('UploadId').text
|
upload_id = elem.find('UploadId').text
|
||||||
self.assertIsNotNone(upload_id)
|
self.assertIsNotNone(upload_id)
|
||||||
@ -200,7 +203,9 @@ class TestS3ApiMultiUpload(S3ApiBase):
|
|||||||
|
|
||||||
# prepare src obj
|
# prepare src obj
|
||||||
self.conn.make_request('PUT', src_bucket)
|
self.conn.make_request('PUT', src_bucket)
|
||||||
self.conn.make_request('PUT', src_bucket, src_obj, body=src_content)
|
with self.quiet_boto_logging():
|
||||||
|
self.conn.make_request('PUT', src_bucket, src_obj,
|
||||||
|
body=src_content)
|
||||||
_, headers, _ = self.conn.make_request('HEAD', src_bucket, src_obj)
|
_, headers, _ = self.conn.make_request('HEAD', src_bucket, src_obj)
|
||||||
self.assertCommonResponseHeaders(headers)
|
self.assertCommonResponseHeaders(headers)
|
||||||
|
|
||||||
@ -305,7 +310,8 @@ class TestS3ApiMultiUpload(S3ApiBase):
|
|||||||
self.assertTrue(lines[0].endswith(b'?>'), body)
|
self.assertTrue(lines[0].endswith(b'?>'), body)
|
||||||
elem = fromstring(body, 'CompleteMultipartUploadResult')
|
elem = fromstring(body, 'CompleteMultipartUploadResult')
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
'%s/bucket/obj1' % tf.config['s3_storage_url'].rstrip('/'),
|
'%s/bucket/obj1%%E2%%98%%83' %
|
||||||
|
tf.config['s3_storage_url'].rstrip('/'),
|
||||||
elem.find('Location').text)
|
elem.find('Location').text)
|
||||||
self.assertEqual(elem.find('Bucket').text, bucket)
|
self.assertEqual(elem.find('Bucket').text, bucket)
|
||||||
self.assertEqual(elem.find('Key').text, key)
|
self.assertEqual(elem.find('Key').text, key)
|
||||||
@ -346,7 +352,8 @@ class TestS3ApiMultiUpload(S3ApiBase):
|
|||||||
self.assertTrue(lines[0].endswith(b'?>'), body)
|
self.assertTrue(lines[0].endswith(b'?>'), body)
|
||||||
elem = fromstring(body, 'CompleteMultipartUploadResult')
|
elem = fromstring(body, 'CompleteMultipartUploadResult')
|
||||||
self.assertEqual(
|
self.assertEqual(
|
||||||
'%s/bucket/obj1' % tf.config['s3_storage_url'].rstrip('/'),
|
'%s/bucket/obj1%%E2%%98%%83' %
|
||||||
|
tf.config['s3_storage_url'].rstrip('/'),
|
||||||
elem.find('Location').text)
|
elem.find('Location').text)
|
||||||
self.assertEqual(elem.find('Bucket').text, bucket)
|
self.assertEqual(elem.find('Bucket').text, bucket)
|
||||||
self.assertEqual(elem.find('Key').text, key)
|
self.assertEqual(elem.find('Key').text, key)
|
||||||
@ -448,7 +455,11 @@ class TestS3ApiMultiUpload(S3ApiBase):
|
|||||||
resp_objects = list(elem.findall('./Contents'))
|
resp_objects = list(elem.findall('./Contents'))
|
||||||
self.assertEqual(len(resp_objects), 1)
|
self.assertEqual(len(resp_objects), 1)
|
||||||
o = resp_objects[0]
|
o = resp_objects[0]
|
||||||
self.assertEqual(o.find('Key').text, keys[0])
|
if six.PY2:
|
||||||
|
expected_key = keys[0].encode('utf-8')
|
||||||
|
else:
|
||||||
|
expected_key = keys[0]
|
||||||
|
self.assertEqual(o.find('Key').text, expected_key)
|
||||||
self.assertIsNotNone(o.find('LastModified').text)
|
self.assertIsNotNone(o.find('LastModified').text)
|
||||||
self.assertRegexpMatches(
|
self.assertRegexpMatches(
|
||||||
o.find('LastModified').text,
|
o.find('LastModified').text,
|
||||||
|
Loading…
Reference in New Issue
Block a user