diff --git a/awscli/botocore/regions.py b/awscli/botocore/regions.py index 0c384ac7c009..32367ef8dcc3 100644 --- a/awscli/botocore/regions.py +++ b/awscli/botocore/regions.py @@ -514,7 +514,11 @@ def construct_endpoint( LOG.debug(f'Endpoint provider result: {provider_result.url}') # The endpoint provider does not support non-secure transport. - if not self._use_ssl and provider_result.url.startswith('https://'): + if ( + not self._use_ssl + and provider_result.url.startswith('https://') + and 'Endpoint' not in provider_params + ): provider_result = provider_result._replace( url=f'http://{provider_result.url[8:]}' ) diff --git a/tests/unit/botocore/test_endpoint_provider.py b/tests/unit/botocore/test_endpoint_provider.py index 345c71ebe727..747264aabb8f 100644 --- a/tests/unit/botocore/test_endpoint_provider.py +++ b/tests/unit/botocore/test_endpoint_provider.py @@ -16,6 +16,7 @@ import os import pytest + from botocore.endpoint_provider import ( EndpointProvider, EndpointRule, @@ -23,7 +24,7 @@ RuleCreator, RuleSet, RuleSetStandardLibary, - TreeRule, + TreeRule, RuleSetEndpoint, ) from botocore.exceptions import ( EndpointResolutionError, @@ -32,6 +33,8 @@ from botocore.loaders import Loader from botocore.regions import EndpointRulesetResolver +from unittest.mock import Mock, patch + REGION_TEMPLATE = "{Region}" REGION_REF = {"ref": "Region"} BUCKET_ARN_REF = {"ref": "bucketArn"} @@ -486,3 +489,77 @@ def test_auth_schemes_conversion_first_authtype_unknown( def test_get_attr(rule_lib, value, path, expected_value): result = rule_lib.get_attr(value, path) assert result == expected_value +@pytest.mark.parametrize( + "use_ssl, endpoint_url, provider_params, expected_url", + [ + # use_ssl=True, endpoint_url="http://..." → HTTP + ( + True, + 'http://custom.com', + {'Endpoint': 'http://custom.com'}, + 'http://custom.com', + ), + # use_ssl=True, endpoint_url="https://..." → HTTPS + ( + True, + 'https://custom.com', + {'Endpoint': 'https://custom.com'}, + 'https://custom.com', + ), + # use_ssl=False, endpoint_url="http://..." → HTTP + ( + False, + 'http://custom.com', + {'Endpoint': 'http://custom.com'}, + 'http://custom.com', + ), + # use_ssl=False, endpoint_url="https://..." → HTTPS + ( + False, + 'https://custom.com', + {'Endpoint': 'https://custom.com'}, + 'https://custom.com', + ), + # use_ssl=True, no endpoint → HTTPS + ( + True, + 'https://s3-test-only-domain.amazonaws.com', + {}, + 'https://s3-test-only-domain.amazonaws.com', + ), + # use_ssl=False, no endpoint → HTTP (downgrade) + ( + False, + 'https://s3-test-only-domain.amazonaws.com', + {}, + 'http://s3-test-only-domain.amazonaws.com', + ), + ], +) +def test_construct_endpoint_parametrized( + use_ssl, endpoint_url, provider_params, expected_url +): + resolver = EndpointRulesetResolver( + endpoint_ruleset_data={ + 'version': '1.0', + 'parameters': {}, + 'rules': [], + }, + partition_data={}, + service_model=None, + builtins={}, + client_context=None, + event_emitter=None, + use_ssl=use_ssl, + requested_auth_scheme=None, + ) + + with patch.object(resolver._provider, 'resolve_endpoint') as mock_resolve: + mock_resolve.return_value = RuleSetEndpoint( + url=endpoint_url, properties={}, headers={} + ) + with patch.object( + resolver, '_get_provider_params', return_value=provider_params + ): + result = resolver.construct_endpoint(None, None, None) + assert result.url == expected_url \ No newline at end of file