S3 - key_name url encoding for listing (#5181)

This commit is contained in:
Cristopher Pinzón 2022-06-01 06:03:40 -05:00 committed by GitHub
parent 18ec060edc
commit 34a98d2c20
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 35 additions and 2 deletions

View File

@ -14,6 +14,7 @@ import pytz
import sys
import time
import uuid
import urllib.parse
from bisect import insort
from importlib import reload
@ -153,6 +154,10 @@ class FakeKey(BaseModel):
self.s3_backend = s3_backend
@property
def safe_name(self):
return urllib.parse.quote(self.name, safe="")
@property
def version_id(self):
return self._version_id

View File

@ -590,6 +590,7 @@ class ResponseObject(_TemplateEnvironmentMixin, ActionAuthenticatorMixin):
result_keys, result_folders = self.backend.list_objects(
bucket, prefix, delimiter
)
encoding_type = querystring.get("encoding-type", [None])[0]
if marker:
result_keys = self._get_results_from_token(result_keys, marker)
@ -611,6 +612,7 @@ class ResponseObject(_TemplateEnvironmentMixin, ActionAuthenticatorMixin):
is_truncated=is_truncated,
next_marker=next_marker,
max_keys=max_keys,
encoding_type=encoding_type,
),
)
@ -642,6 +644,7 @@ class ResponseObject(_TemplateEnvironmentMixin, ActionAuthenticatorMixin):
fetch_owner = querystring.get("fetch-owner", [False])[0]
max_keys = int(querystring.get("max-keys", [1000])[0])
start_after = querystring.get("start-after", [None])[0]
encoding_type = querystring.get("encoding-type", [None])[0]
if continuation_token or start_after:
limit = continuation_token or start_after
@ -666,6 +669,7 @@ class ResponseObject(_TemplateEnvironmentMixin, ActionAuthenticatorMixin):
is_truncated=is_truncated,
next_continuation_token=next_continuation_token,
start_after=None if continuation_token else start_after,
encoding_type=encoding_type,
)
@staticmethod
@ -2051,13 +2055,16 @@ S3_BUCKET_GET_RESPONSE = """<?xml version="1.0" encoding="UTF-8"?>
{% if delimiter %}
<Delimiter>{{ delimiter }}</Delimiter>
{% endif %}
{% if encoding_type %}
<EncodingType>{{ encoding_type }}</EncodingType>
{% endif %}
<IsTruncated>{{ is_truncated }}</IsTruncated>
{% if next_marker %}
<NextMarker>{{ next_marker }}</NextMarker>
{% endif %}
{% for key in result_keys %}
<Contents>
<Key>{{ key.name }}</Key>
<Key>{{ key.safe_name }}</Key>
<LastModified>{{ key.last_modified_ISO8601 }}</LastModified>
<ETag>{{ key.etag }}</ETag>
<Size>{{ key.size }}</Size>
@ -2087,6 +2094,9 @@ S3_BUCKET_GET_RESPONSE_V2 = """<?xml version="1.0" encoding="UTF-8"?>
<KeyCount>{{ key_count }}</KeyCount>
{% if delimiter %}
<Delimiter>{{ delimiter }}</Delimiter>
{% endif %}
{% if encoding_type %}
<EncodingType>{{ encoding_type }}</EncodingType>
{% endif %}
<IsTruncated>{{ is_truncated }}</IsTruncated>
{% if next_continuation_token %}
@ -2097,7 +2107,7 @@ S3_BUCKET_GET_RESPONSE_V2 = """<?xml version="1.0" encoding="UTF-8"?>
{% endif %}
{% for key in result_keys %}
<Contents>
<Key>{{ key.name }}</Key>
<Key>{{ key.safe_name }}</Key>
<LastModified>{{ key.last_modified_ISO8601 }}</LastModified>
<ETag>{{ key.etag }}</ETag>
<Size>{{ key.size }}</Size>

View File

@ -134,6 +134,24 @@ def test_empty_key():
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
def test_empty_key_set_on_existing_key():
s3 = boto3.resource("s3", region_name=DEFAULT_REGION_NAME)