Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changes/next-release/enhancement-S3redirect-2339.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
{
"type": "enhancement",
"category": "S3 redirect",
"description": "Validate new region name when redirecting."
}
26 changes: 12 additions & 14 deletions awscli/botocore/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -1718,21 +1718,19 @@ def get_bucket_region(self, bucket, response):
service_response = response[1]
response_headers = service_response['ResponseMetadata']['HTTPHeaders']
if 'x-amz-bucket-region' in response_headers:
return response_headers['x-amz-bucket-region']

region = response_headers['x-amz-bucket-region']
# Next, check the error body
region = service_response.get('Error', {}).get('Region', None)
if region is not None:
return region

# Finally, HEAD the bucket. No other choice sadly.
try:
response = self._client.head_bucket(Bucket=bucket)
headers = response['ResponseMetadata']['HTTPHeaders']
except ClientError as e:
headers = e.response['ResponseMetadata']['HTTPHeaders']

region = headers.get('x-amz-bucket-region', None)
elif r := service_response.get('Error', {}).get('Region', None):
region = r
else:
# Finally, HEAD the bucket. No other choice sadly.
try:
response = self._client.head_bucket(Bucket=bucket)
headers = response['ResponseMetadata']['HTTPHeaders']
except ClientError as e:
headers = e.response['ResponseMetadata']['HTTPHeaders']
region = headers.get('x-amz-bucket-region', None)
validate_region_name(region)
return region

def set_request_url(self, old_url, new_endpoint, **kwargs):
Expand Down
42 changes: 42 additions & 0 deletions tests/unit/botocore/test_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@
IMDSFetcher,
InstanceMetadataFetcher,
InvalidArnException,
InvalidRegionError,
S3ArnParamHandler,
S3EndpointSetter,
S3RegionRedirectorv2,
Expand Down Expand Up @@ -2116,6 +2117,47 @@ def test_no_redirect_from_error_for_mrap_accesspoint(self):
)
self.assertEqual(redirect_response, None)

def test_get_region_validates_region_from_header(self):
response = (
None,
{
'Error': {'Code': 'PermanentRedirect'},
'ResponseMetadata': {
'HTTPHeaders': {'x-amz-bucket-region': 'invalid region!'}
},
},
)
with self.assertRaises(InvalidRegionError):
self.redirector.get_bucket_region('foo', response)

def test_get_region_validates_region_from_error_body(self):
response = (
None,
{
'Error': {
'Code': 'PermanentRedirect',
'Region': 'invalid region!',
},
'ResponseMetadata': {'HTTPHeaders': {}},
},
)
with self.assertRaises(InvalidRegionError):
self.redirector.get_bucket_region('foo', response)

def test_get_region_validates_region_from_head_bucket(self):
self.set_client_response_headers(
{'x-amz-bucket-region': 'invalid region!'}
)
response = (
None,
{
'Error': {'Code': 'PermanentRedirect'},
'ResponseMetadata': {'HTTPHeaders': {}},
},
)
with self.assertRaises(InvalidRegionError):
self.redirector.get_bucket_region('foo', response)


class TestArnParser(unittest.TestCase):
def setUp(self):
Expand Down
Loading