S3 - key_name url encoding for listing (#5181)
This commit is contained in:
parent
18ec060edc
commit
34a98d2c20
@ -14,6 +14,7 @@ import pytz
|
|||||||
import sys
|
import sys
|
||||||
import time
|
import time
|
||||||
import uuid
|
import uuid
|
||||||
|
import urllib.parse
|
||||||
|
|
||||||
from bisect import insort
|
from bisect import insort
|
||||||
from importlib import reload
|
from importlib import reload
|
||||||
@ -153,6 +154,10 @@ class FakeKey(BaseModel):
|
|||||||
|
|
||||||
self.s3_backend = s3_backend
|
self.s3_backend = s3_backend
|
||||||
|
|
||||||
|
@property
|
||||||
|
def safe_name(self):
|
||||||
|
return urllib.parse.quote(self.name, safe="")
|
||||||
|
|
||||||
@property
|
@property
|
||||||
def version_id(self):
|
def version_id(self):
|
||||||
return self._version_id
|
return self._version_id
|
||||||
|
@ -590,6 +590,7 @@ class ResponseObject(_TemplateEnvironmentMixin, ActionAuthenticatorMixin):
|
|||||||
result_keys, result_folders = self.backend.list_objects(
|
result_keys, result_folders = self.backend.list_objects(
|
||||||
bucket, prefix, delimiter
|
bucket, prefix, delimiter
|
||||||
)
|
)
|
||||||
|
encoding_type = querystring.get("encoding-type", [None])[0]
|
||||||
|
|
||||||
if marker:
|
if marker:
|
||||||
result_keys = self._get_results_from_token(result_keys, marker)
|
result_keys = self._get_results_from_token(result_keys, marker)
|
||||||
@ -611,6 +612,7 @@ class ResponseObject(_TemplateEnvironmentMixin, ActionAuthenticatorMixin):
|
|||||||
is_truncated=is_truncated,
|
is_truncated=is_truncated,
|
||||||
next_marker=next_marker,
|
next_marker=next_marker,
|
||||||
max_keys=max_keys,
|
max_keys=max_keys,
|
||||||
|
encoding_type=encoding_type,
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -642,6 +644,7 @@ class ResponseObject(_TemplateEnvironmentMixin, ActionAuthenticatorMixin):
|
|||||||
fetch_owner = querystring.get("fetch-owner", [False])[0]
|
fetch_owner = querystring.get("fetch-owner", [False])[0]
|
||||||
max_keys = int(querystring.get("max-keys", [1000])[0])
|
max_keys = int(querystring.get("max-keys", [1000])[0])
|
||||||
start_after = querystring.get("start-after", [None])[0]
|
start_after = querystring.get("start-after", [None])[0]
|
||||||
|
encoding_type = querystring.get("encoding-type", [None])[0]
|
||||||
|
|
||||||
if continuation_token or start_after:
|
if continuation_token or start_after:
|
||||||
limit = continuation_token or start_after
|
limit = continuation_token or start_after
|
||||||
@ -666,6 +669,7 @@ class ResponseObject(_TemplateEnvironmentMixin, ActionAuthenticatorMixin):
|
|||||||
is_truncated=is_truncated,
|
is_truncated=is_truncated,
|
||||||
next_continuation_token=next_continuation_token,
|
next_continuation_token=next_continuation_token,
|
||||||
start_after=None if continuation_token else start_after,
|
start_after=None if continuation_token else start_after,
|
||||||
|
encoding_type=encoding_type,
|
||||||
)
|
)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
@ -2051,13 +2055,16 @@ S3_BUCKET_GET_RESPONSE = """<?xml version="1.0" encoding="UTF-8"?>
|
|||||||
{% if delimiter %}
|
{% if delimiter %}
|
||||||
<Delimiter>{{ delimiter }}</Delimiter>
|
<Delimiter>{{ delimiter }}</Delimiter>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
|
{% if encoding_type %}
|
||||||
|
<EncodingType>{{ encoding_type }}</EncodingType>
|
||||||
|
{% endif %}
|
||||||
<IsTruncated>{{ is_truncated }}</IsTruncated>
|
<IsTruncated>{{ is_truncated }}</IsTruncated>
|
||||||
{% if next_marker %}
|
{% if next_marker %}
|
||||||
<NextMarker>{{ next_marker }}</NextMarker>
|
<NextMarker>{{ next_marker }}</NextMarker>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
{% for key in result_keys %}
|
{% for key in result_keys %}
|
||||||
<Contents>
|
<Contents>
|
||||||
<Key>{{ key.name }}</Key>
|
<Key>{{ key.safe_name }}</Key>
|
||||||
<LastModified>{{ key.last_modified_ISO8601 }}</LastModified>
|
<LastModified>{{ key.last_modified_ISO8601 }}</LastModified>
|
||||||
<ETag>{{ key.etag }}</ETag>
|
<ETag>{{ key.etag }}</ETag>
|
||||||
<Size>{{ key.size }}</Size>
|
<Size>{{ key.size }}</Size>
|
||||||
@ -2087,6 +2094,9 @@ S3_BUCKET_GET_RESPONSE_V2 = """<?xml version="1.0" encoding="UTF-8"?>
|
|||||||
<KeyCount>{{ key_count }}</KeyCount>
|
<KeyCount>{{ key_count }}</KeyCount>
|
||||||
{% if delimiter %}
|
{% if delimiter %}
|
||||||
<Delimiter>{{ delimiter }}</Delimiter>
|
<Delimiter>{{ delimiter }}</Delimiter>
|
||||||
|
{% endif %}
|
||||||
|
{% if encoding_type %}
|
||||||
|
<EncodingType>{{ encoding_type }}</EncodingType>
|
||||||
{% endif %}
|
{% endif %}
|
||||||
<IsTruncated>{{ is_truncated }}</IsTruncated>
|
<IsTruncated>{{ is_truncated }}</IsTruncated>
|
||||||
{% if next_continuation_token %}
|
{% if next_continuation_token %}
|
||||||
@ -2097,7 +2107,7 @@ S3_BUCKET_GET_RESPONSE_V2 = """<?xml version="1.0" encoding="UTF-8"?>
|
|||||||
{% endif %}
|
{% endif %}
|
||||||
{% for key in result_keys %}
|
{% for key in result_keys %}
|
||||||
<Contents>
|
<Contents>
|
||||||
<Key>{{ key.name }}</Key>
|
<Key>{{ key.safe_name }}</Key>
|
||||||
<LastModified>{{ key.last_modified_ISO8601 }}</LastModified>
|
<LastModified>{{ key.last_modified_ISO8601 }}</LastModified>
|
||||||
<ETag>{{ key.etag }}</ETag>
|
<ETag>{{ key.etag }}</ETag>
|
||||||
<Size>{{ key.size }}</Size>
|
<Size>{{ key.size }}</Size>
|
||||||
|
@ -134,6 +134,24 @@ def test_empty_key():
|
|||||||
resp["Body"].read().should.equal(b"")
|
resp["Body"].read().should.equal(b"")
|
||||||
|
|
||||||
|
|
||||||
|
@mock_s3
|
||||||
|
def test_key_name_encoding_in_listing():
|
||||||
|
s3 = boto3.resource("s3", region_name=DEFAULT_REGION_NAME)
|
||||||
|
client = boto3.client("s3", region_name=DEFAULT_REGION_NAME)
|
||||||
|
s3.create_bucket(Bucket="foobar")
|
||||||
|
|
||||||
|
name = "6T7\x159\x12\r\x08.txt"
|
||||||
|
|
||||||
|
key = s3.Object("foobar", name)
|
||||||
|
key.put(Body=b"")
|
||||||
|
|
||||||
|
key_received = client.list_objects(Bucket="foobar")["Contents"][0]["Key"]
|
||||||
|
key_received.should.equal(name)
|
||||||
|
|
||||||
|
key_received = client.list_objects_v2(Bucket="foobar")["Contents"][0]["Key"]
|
||||||
|
key_received.should.equal(name)
|
||||||
|
|
||||||
|
|
||||||
@mock_s3
|
@mock_s3
|
||||||
def test_empty_key_set_on_existing_key():
|
def test_empty_key_set_on_existing_key():
|
||||||
s3 = boto3.resource("s3", region_name=DEFAULT_REGION_NAME)
|
s3 = boto3.resource("s3", region_name=DEFAULT_REGION_NAME)
|
||||||
|
Loading…
Reference in New Issue
Block a user