diff --git a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java index d3c37f92a367..413e8ca23d83 100644 --- a/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java +++ b/codegen/src/main/java/software/amazon/awssdk/codegen/poet/builder/BaseClientBuilderClass.java @@ -21,6 +21,7 @@ import static software.amazon.awssdk.codegen.poet.client.traits.HttpChecksumTrait.hasRequestAlgorithmMember; import static software.amazon.awssdk.codegen.poet.client.traits.HttpChecksumTrait.hasResponseAlgorithms; +import java.net.URI; import com.squareup.javapoet.ClassName; import com.squareup.javapoet.CodeBlock; import com.squareup.javapoet.FieldSpec; @@ -46,9 +47,15 @@ import software.amazon.awssdk.awscore.client.builder.AwsDefaultClientBuilder; import software.amazon.awssdk.awscore.client.config.AwsClientOption; import software.amazon.awssdk.awscore.endpoint.AwsClientEndpointProvider; +import software.amazon.awssdk.core.ClientEndpointProvider; +import software.amazon.awssdk.core.exception.SdkClientException; +import software.amazon.awssdk.endpoints.Endpoint; +import software.amazon.awssdk.utils.CompletableFutureUtils; import software.amazon.awssdk.codegen.internal.Utils; import software.amazon.awssdk.codegen.model.intermediate.IntermediateModel; import software.amazon.awssdk.codegen.model.intermediate.OperationModel; +import software.amazon.awssdk.codegen.model.rules.endpoints.BuiltInParameter; +import software.amazon.awssdk.codegen.model.rules.endpoints.ParameterModel; import software.amazon.awssdk.codegen.model.service.ClientContextParam; import software.amazon.awssdk.codegen.poet.ClassSpec; import software.amazon.awssdk.codegen.poet.PoetExtension; @@ -86,7 +93,6 @@ import software.amazon.awssdk.identity.spi.IdentityProviders; import software.amazon.awssdk.identity.spi.TokenIdentity; import software.amazon.awssdk.protocols.json.internal.unmarshall.SdkClientJsonProtocolAdvancedOption; -import software.amazon.awssdk.regions.ServiceMetadataAdvancedOption; import software.amazon.awssdk.utils.AttributeMap; import software.amazon.awssdk.utils.CollectionUtils; import software.amazon.awssdk.utils.StringUtils; @@ -225,6 +231,11 @@ private boolean resolveDefaultEndpointDiscovery() { .orElse(false); } + private boolean hasBuiltInParam(BuiltInParameter builtIn) { + return model.getEndpointRuleSetModel().getParameters().values().stream() + .anyMatch(p -> p.getBuiltInEnum() == builtIn); + } + private MethodSpec signingNameMethod() { return MethodSpec.methodBuilder("signingName") .addAnnotation(Override.class) @@ -514,21 +525,48 @@ private MethodSpec finalizeServiceConfigurationMethod() { String serviceNameForSystemProperty = model.getNamingStrategy().getServiceNameForSystemProperties(); String serviceNameForProfileFile = model.getNamingStrategy().getServiceNameForProfileFile(); - builder.addCode("builder.lazyOptionIfAbsent($T.CLIENT_ENDPOINT_PROVIDER, c ->", SdkClientOption.class) - .addCode(" $T.builder()", AwsClientEndpointProvider.class) - .addCode(" .serviceEndpointOverrideEnvironmentVariable($S)", "AWS_ENDPOINT_URL_" + serviceNameForEnvVar) - .addCode(" .serviceEndpointOverrideSystemProperty($S)", "aws.endpointUrl" + serviceNameForSystemProperty) - .addCode(" .serviceProfileProperty($S)", serviceNameForProfileFile) - .addCode(" .serviceEndpointPrefix(serviceEndpointPrefix())") - .addCode(" .defaultProtocol($S)", "https") - .addCode(" .region(c.get($T.AWS_REGION))", AwsClientOption.class) - .addCode(" .profileFile(c.get($T.PROFILE_FILE_SUPPLIER))", SdkClientOption.class) - .addCode(" .profileName(c.get($T.PROFILE_NAME))", SdkClientOption.class) - .addCode(" .putAdvancedOption($T.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT,", ServiceMetadataAdvancedOption.class) - .addCode(" c.get($T.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT))", ServiceMetadataAdvancedOption.class) - .addCode(" .dualstackEnabled(c.get($T.DUALSTACK_ENDPOINT_ENABLED))", AwsClientOption.class) - .addCode(" .fipsEnabled(c.get($T.FIPS_ENDPOINT_ENABLED))", AwsClientOption.class) - .addCode(" .build());"); + builder.addCode("builder.lazyOptionIfAbsent($T.CLIENT_ENDPOINT_PROVIDER, c -> {\n", SdkClientOption.class) + .addCode(" $T<$T> fromOverrides = $T.builder()\n", + Optional.class, ClientEndpointProvider.class, AwsClientEndpointProvider.class) + .addCode(" .serviceEndpointOverrideEnvironmentVariable($S)\n", "AWS_ENDPOINT_URL_" + serviceNameForEnvVar) + .addCode(" .serviceEndpointOverrideSystemProperty($S)\n", "aws.endpointUrl" + serviceNameForSystemProperty) + .addCode(" .serviceProfileProperty($S)\n", serviceNameForProfileFile) + .addCode(" .profileFile(c.get($T.PROFILE_FILE_SUPPLIER))\n", SdkClientOption.class) + .addCode(" .profileName(c.get($T.PROFILE_NAME))\n", SdkClientOption.class) + .addCode(" .buildOptional();\n") + .addCode(" if (fromOverrides.isPresent()) {\n") + .addCode(" return fromOverrides.get();\n") + .addCode(" }\n") + .addCode(" $T endpointProvider = defaultEndpointProvider();\n", + endpointRulesSpecUtils.providerInterfaceName()) + .addCode(" $T params = $T.builder()\n", + endpointRulesSpecUtils.parametersClassName(), + endpointRulesSpecUtils.parametersClassName()) + .addCode(" .region(c.get($T.AWS_REGION))\n", AwsClientOption.class); + + if (hasBuiltInParam(BuiltInParameter.AWS_USE_FIPS)) { + builder.addCode(" .useFips(c.get($T.FIPS_ENDPOINT_ENABLED))\n", AwsClientOption.class); + } + if (hasBuiltInParam(BuiltInParameter.AWS_USE_DUAL_STACK)) { + builder.addCode(" .useDualStack(c.get($T.DUALSTACK_ENDPOINT_ENABLED))\n", AwsClientOption.class); + } + + builder.addCode(" .build();\n") + .addCode(" try {\n") + .addCode(" $T endpoint = $T.joinLikeSync(endpointProvider.resolveEndpoint(params));\n", + Endpoint.class, CompletableFutureUtils.class) + .addCode(" $T endpointUrl = endpoint.url();\n", URI.class) + .addCode(" if (endpointUrl.getHost() == null) {\n") + .addCode(" throw $T.create(\"Configured region (\" + c.get($T.AWS_REGION) + \") resulted in an invalid\"\n", + SdkClientException.class, AwsClientOption.class) + .addCode(" + \" URI. This is usually caused by an invalid region configuration.\");\n") + .addCode(" }\n") + .addCode(" return $T.create(endpointUrl, false);\n", ClientEndpointProvider.class) + .addCode(" } catch ($T e) {\n", NullPointerException.class) + .addCode(" return $T.create($T.create(\"https://localhost\"), false);\n", + ClientEndpointProvider.class, URI.class) + .addCode(" }\n") + .addCode("});\n"); if (model.getMetadata().isJsonProtocol()) { builder.addStatement("builder.option($1T.ENABLE_FAST_UNMARSHALLER, true)", diff --git a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/client/builder/AwsDefaultClientBuilder.java b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/client/builder/AwsDefaultClientBuilder.java index cf74d712bc26..886190dd4af2 100644 --- a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/client/builder/AwsDefaultClientBuilder.java +++ b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/client/builder/AwsDefaultClientBuilder.java @@ -64,7 +64,6 @@ import software.amazon.awssdk.identity.spi.IdentityProviders; import software.amazon.awssdk.profiles.ProfileFile; import software.amazon.awssdk.regions.Region; -import software.amazon.awssdk.regions.ServiceMetadata; import software.amazon.awssdk.regions.ServiceMetadataAdvancedOption; import software.amazon.awssdk.regions.providers.DefaultAwsRegionProviderChain; import software.amazon.awssdk.retries.api.RetryStrategy; @@ -316,8 +315,30 @@ private AttributeMap mergeSmartHttpDefaults(LazyValueSource config, AttributeMap * Resolve the signing region from the default-applied configuration. */ private Region resolveSigningRegion(LazyValueSource config) { - return ServiceMetadata.of(serviceEndpointPrefix()) - .signingRegion(config.get(AwsClientOption.AWS_REGION)); + Region clientRegion = config.get(AwsClientOption.AWS_REGION); + + if (clientRegion.isGlobalRegion()) { + return Region.of(implicitGlobalRegion(clientRegion)); + } + + return clientRegion; + } + + private String implicitGlobalRegion(Region globalRegion) { + String regionId = globalRegion.id(); + if (regionId.startsWith("aws-cn")) { + return "cn-northwest-1"; + } else if (regionId.startsWith("aws-us-gov")) { + return "us-gov-west-1"; + } else if (regionId.startsWith("aws-iso-b")) { + return "us-isob-east-1"; + } else if (regionId.startsWith("aws-iso-e")) { + return "us-iso-east-1"; + } else if (regionId.startsWith("aws-iso")) { + return "us-iso-east-1"; + } + // Default: aws-global -> us-east-1 + return "us-east-1"; } /** @@ -326,18 +347,10 @@ private Region resolveSigningRegion(LazyValueSource config) { * This is only used for older client versions. Newer clients specify this value themselves. */ private ClientEndpointProvider resolveClientEndpointProvider(LazyValueSource config) { - ServiceMetadataAdvancedOption useGlobalS3EndpointProperty = - ServiceMetadataAdvancedOption.DEFAULT_S3_US_EAST_1_REGIONAL_ENDPOINT; return AwsClientEndpointProvider.builder() - .serviceEndpointPrefix(serviceEndpointPrefix()) - .defaultProtocol(DEFAULT_ENDPOINT_PROTOCOL) - .region(config.get(AwsClientOption.AWS_REGION)) + .clientEndpointOverride(URI.create("https://localhost")) .profileFile(config.get(SdkClientOption.PROFILE_FILE_SUPPLIER)) .profileName(config.get(SdkClientOption.PROFILE_NAME)) - .putAdvancedOption(useGlobalS3EndpointProperty, - config.get(useGlobalS3EndpointProperty)) - .dualstackEnabled(config.get(AwsClientOption.DUALSTACK_ENDPOINT_ENABLED)) - .fipsEnabled(config.get(AwsClientOption.FIPS_ENDPOINT_ENABLED)) .build(); } diff --git a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/endpoint/AwsClientEndpointProvider.java b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/endpoint/AwsClientEndpointProvider.java index 0bb5119b369e..511b23a0ac18 100644 --- a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/endpoint/AwsClientEndpointProvider.java +++ b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/endpoint/AwsClientEndpointProvider.java @@ -17,7 +17,6 @@ import java.net.URI; import java.net.URISyntaxException; -import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -30,10 +29,7 @@ import software.amazon.awssdk.profiles.ProfileFile; import software.amazon.awssdk.profiles.ProfileFileSystemSetting; import software.amazon.awssdk.profiles.ProfileProperty; -import software.amazon.awssdk.regions.EndpointTag; import software.amazon.awssdk.regions.Region; -import software.amazon.awssdk.regions.ServiceEndpointKey; -import software.amazon.awssdk.regions.ServiceMetadata; import software.amazon.awssdk.regions.ServiceMetadataAdvancedOption; import software.amazon.awssdk.utils.Lazy; import software.amazon.awssdk.utils.Logger; @@ -95,10 +91,9 @@ public boolean isEndpointOverridden() { return clientEndpoint.getValue().isEndpointOverridden; } - private ClientEndpoint resolveClientEndpoint(Builder builder) { + private static ClientEndpoint resolveClientEndpoint(Builder builder) { return OptionalUtils.firstPresent(clientEndpointFromClientOverride(builder), - () -> clientEndpointFromEnvironment(builder), - () -> clientEndpointFromServiceMetadata(builder)) + () -> clientEndpointFromEnvironment(builder)) .orElseThrow(AwsClientEndpointProvider::failToLoadEndpointException); } @@ -107,14 +102,14 @@ private static SdkClientException failToLoadEndpointException() { AwsClientEndpointProvider.class.getName() + " for more information."); } - private Optional clientEndpointFromClientOverride(Builder builder) { + private static Optional clientEndpointFromClientOverride(Builder builder) { Optional result = Optional.ofNullable(builder.clientEndpointOverride) .map(uri -> new ClientEndpoint(uri, true)); result.ifPresent(e -> log.trace(() -> "Client was configured with endpoint override: " + e.clientEndpoint)); return result; } - private Optional clientEndpointFromEnvironment(Builder builder) { + private static Optional clientEndpointFromEnvironment(Builder builder) { if (builder.serviceEndpointOverrideEnvironmentVariable == null || builder.serviceEndpointOverrideSystemProperty == null || builder.serviceProfileProperty == null) { @@ -147,19 +142,19 @@ private Optional clientEndpointFromEnvironment(Builder builder) .map(uri -> new ClientEndpoint(uri, true)); } - private Optional systemProperty(String systemProperty) { + private static Optional systemProperty(String systemProperty) { // CHECKSTYLE:OFF - We have to read system properties directly here to match the load order of the other SDKs return createUri("system property " + systemProperty, Optional.ofNullable(System.getProperty(systemProperty))); // CHECKSTYLE:ON } - private Optional environmentVariable(String environmentVariable) { + private static Optional environmentVariable(String environmentVariable) { return createUri("environment variable " + environmentVariable, SystemSettingUtils.resolveEnvironmentVariable(environmentVariable)); } - private Optional profileProperty(Builder builder, String profileProperty) { + private static Optional profileProperty(Builder builder, String profileProperty) { initializeProfileFileDefaults(builder); return createUri("profile property " + profileProperty, Optional.ofNullable(builder.profileFile.get()) @@ -167,7 +162,7 @@ private Optional profileProperty(Builder builder, String profileProperty) { .flatMap(p -> p.property(profileProperty))); } - private Optional servicesProperty(Builder builder) { + private static Optional servicesProperty(Builder builder) { Optional profileFile = Optional.ofNullable(builder.profileFile.get()); Optional servicesSectionName = profileFile .flatMap(pf -> pf.profile(builder.profileName)) @@ -181,84 +176,7 @@ private Optional servicesProperty(Builder builder) { return createUri("services section property", serviceEndpoint); } - private Optional clientEndpointFromServiceMetadata(Builder builder) { - // This value is generally overridden after endpoints 2.0. It seems to exist for backwards-compatibility - // with older client versions or interceptors. - - if (builder.serviceEndpointPrefix == null || - builder.region == null || - builder.protocol == null) { - // Make sure that people didn't set just one value and expect it to be used. - Validate.isTrue(builder.serviceEndpointPrefix == null && - builder.region == null && - builder.protocol == null, - "If any of the service endpoint prefix, region or protocol are configured, they must all " - + "be configured."); - log.trace(() -> "Service metadata was not checked for client endpoint."); - return Optional.empty(); - } - - Validate.paramNotNull(builder.serviceEndpointPrefix, "serviceName"); - Validate.paramNotNull(builder.region, "region"); - Validate.paramNotNull(builder.protocol, "protocol"); - - initializeProfileFileDefaults(builder); - - if (builder.dualstackEnabled == null) { - builder.dualstackEnabled = DualstackEnabledProvider.builder() - .profileFile(builder.profileFile) - .profileName(builder.profileName) - .build() - .isDualstackEnabled() - .orElse(false); - } - - if (builder.fipsEnabled == null) { - builder.fipsEnabled = FipsEnabledProvider.builder() - .profileFile(builder.profileFile) - .profileName(builder.profileName) - .build() - .isFipsEnabled() - .orElse(false); - } - - List endpointTags = new ArrayList<>(); - if (builder.dualstackEnabled) { - endpointTags.add(EndpointTag.DUALSTACK); - } - if (builder.fipsEnabled) { - endpointTags.add(EndpointTag.FIPS); - } - - ServiceMetadata serviceMetadata = ServiceMetadata.of(builder.serviceEndpointPrefix) - .reconfigure(c -> c.profileFile(builder.profileFile) - .profileName(builder.profileName) - .advancedOptions(builder.advancedOptions)); - URI endpointWithoutProtocol = - serviceMetadata.endpointFor(ServiceEndpointKey.builder() - .region(builder.region) - .tags(endpointTags) - .build()); - URI endpoint = SdkUri.getInstance().create(builder.protocol + "://" + endpointWithoutProtocol); - if (endpoint.getHost() == null) { - String error = "Configured region (" + builder.region + ") and tags (" + endpointTags + ") resulted in " - + "an invalid URI: " + endpoint + ". This is usually caused by an invalid region " - + "configuration."; - - List exampleRegions = serviceMetadata.regions(); - if (!exampleRegions.isEmpty()) { - error += " Valid regions: " + exampleRegions; - } - - throw SdkClientException.create(error); - } - - log.trace(() -> "Client endpoint was loaded from service metadata, but this endpoint will likely be overridden " - + "at the request-level by the endpoint resolver: " + endpoint); - return Optional.of(new ClientEndpoint(endpoint, false)); - } - - private Optional createUri(String source, Optional uri) { + private static Optional createUri(String source, Optional uri) { return uri.map(u -> { try { URI parsedUri = SdkUri.getInstance().newUri(uri.get()); @@ -270,7 +188,7 @@ private Optional createUri(String source, Optional uri) { }); } - private void initializeProfileFileDefaults(Builder builder) { + private static void initializeProfileFileDefaults(Builder builder) { if (builder.profileFile == null) { builder.profileFile = new Lazy<>(ProfileFile::defaultProfileFile)::getValue; } @@ -479,6 +397,19 @@ public Builder putAdvancedOption(ServiceMetadataAdvancedOption option, T return this; } + /** + * Build a {@link ClientEndpointProvider} that only checks client overrides and environment configuration. + * Returns {@link Optional#empty()} if no override or environment endpoint is configured, without falling back + * to {@link ServiceMetadata}. + */ + public Optional buildOptional() { + Builder copy = new Builder(this); + initializeProfileFileDefaults(copy); + return OptionalUtils.firstPresent(clientEndpointFromClientOverride(copy), + () -> clientEndpointFromEnvironment(copy)) + .map(e -> ClientEndpointProvider.create(e.clientEndpoint, e.isEndpointOverridden)); + } + public AwsClientEndpointProvider build() { return new AwsClientEndpointProvider(this); } diff --git a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/interceptor/HelpfulUnknownHostExceptionInterceptor.java b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/interceptor/HelpfulUnknownHostExceptionInterceptor.java index 8a4eab2e5673..489cd374a488 100644 --- a/core/aws-core/src/main/java/software/amazon/awssdk/awscore/interceptor/HelpfulUnknownHostExceptionInterceptor.java +++ b/core/aws-core/src/main/java/software/amazon/awssdk/awscore/interceptor/HelpfulUnknownHostExceptionInterceptor.java @@ -16,20 +16,11 @@ package software.amazon.awssdk.awscore.interceptor; import java.net.UnknownHostException; -import java.util.List; -import java.util.Optional; -import java.util.stream.Collectors; import software.amazon.awssdk.annotations.SdkProtectedApi; -import software.amazon.awssdk.awscore.AwsExecutionAttribute; import software.amazon.awssdk.core.exception.SdkClientException; import software.amazon.awssdk.core.interceptor.Context; import software.amazon.awssdk.core.interceptor.ExecutionAttributes; import software.amazon.awssdk.core.interceptor.ExecutionInterceptor; -import software.amazon.awssdk.regions.PartitionMetadata; -import software.amazon.awssdk.regions.Region; -import software.amazon.awssdk.regions.RegionMetadata; -import software.amazon.awssdk.regions.ServiceMetadata; -import software.amazon.awssdk.regions.ServicePartitionMetadata; /** * This interceptor will monitor for {@link UnknownHostException}s and provide the customer with additional information they can @@ -46,88 +37,16 @@ public Throwable modifyException(Context.FailedExecution context, ExecutionAttri StringBuilder error = new StringBuilder(); error.append("Received an UnknownHostException when attempting to interact with a service. See cause for the " + "exact endpoint that is failing to resolve. "); - - Optional globalRegionErrorDetails = getGlobalRegionErrorDetails(executionAttributes); - - if (globalRegionErrorDetails.isPresent()) { - error.append(globalRegionErrorDetails.get()); - } else { - error.append("If this is happening on an endpoint that previously worked, there may be a network connectivity " - + "issue or your DNS cache could be storing endpoints for too long."); - } + error.append("If this is happening on an endpoint that previously worked, there may be a network connectivity " + + "issue or your DNS cache could be storing endpoints for too long."); return SdkClientException.builder().message(error.toString()).cause(context.exception()).build(); } - /** - * If the customer is interacting with a global service (one with a single endpoint/region for an entire partition), this - * will return error details that can instruct the customer on how to configure their client for success. - */ - private Optional getGlobalRegionErrorDetails(ExecutionAttributes executionAttributes) { - Region clientRegion = clientRegion(executionAttributes); - if (clientRegion.isGlobalRegion()) { - return Optional.empty(); - } - - List globalPartitionsForService = globalPartitionsForService(executionAttributes); - if (globalPartitionsForService.isEmpty()) { - return Optional.empty(); - } - - String clientPartition = Optional.ofNullable(clientRegion.metadata()) - .map(RegionMetadata::partition) - .map(PartitionMetadata::id) - .orElse(null); - - Optional globalRegionForClientRegion = - globalPartitionsForService.stream() - .filter(p -> p.partition().id().equals(clientPartition)) - .findAny() - .flatMap(ServicePartitionMetadata::globalRegion); - - if (!globalRegionForClientRegion.isPresent()) { - String globalRegionsForThisService = globalPartitionsForService.stream() - .map(ServicePartitionMetadata::globalRegion) - .filter(Optional::isPresent) - .map(Optional::get) - .filter(Region::isGlobalRegion) - .map(Region::id) - .collect(Collectors.joining("/")); - - return Optional.of("This specific service may be a global service, in which case you should configure a global " - + "region like " + globalRegionsForThisService + " on the client."); - } - - Region globalRegion = globalRegionForClientRegion.get(); - - return Optional.of("This specific service is global in the same partition as the region configured on this client (" - + clientRegion + "). If this is the first time you're trying to talk to this service in this region, " - + "you should try configuring the global region on your client, instead: " + globalRegion); - } - - /** - * Retrieve the region configured on the client. - */ - private Region clientRegion(ExecutionAttributes executionAttributes) { - return executionAttributes.getAttribute(AwsExecutionAttribute.AWS_REGION); - } - - /** - * Retrieve all global partitions for the AWS service that we're interacting with. - */ - private List globalPartitionsForService(ExecutionAttributes executionAttributes) { - return ServiceMetadata.of(executionAttributes.getAttribute(AwsExecutionAttribute.ENDPOINT_PREFIX)) - .servicePartitions() - .stream() - .filter(sp -> sp.globalRegion().isPresent()) - .collect(Collectors.toList()); - } - private boolean hasCause(Throwable thrown, Class cause) { if (thrown == null) { return false; } - if (cause.isAssignableFrom(thrown.getClass())) { return true; } diff --git a/services/docdb/src/main/java/software/amazon/awssdk/services/docdb/internal/RdsPresignInterceptor.java b/services/docdb/src/main/java/software/amazon/awssdk/services/docdb/internal/RdsPresignInterceptor.java index 55b0fd574e64..76cc6ec543cf 100644 --- a/services/docdb/src/main/java/software/amazon/awssdk/services/docdb/internal/RdsPresignInterceptor.java +++ b/services/docdb/src/main/java/software/amazon/awssdk/services/docdb/internal/RdsPresignInterceptor.java @@ -25,10 +25,9 @@ import java.util.concurrent.CompletableFuture; import software.amazon.awssdk.annotations.SdkInternalApi; import software.amazon.awssdk.awscore.AwsExecutionAttribute; -import software.amazon.awssdk.awscore.endpoint.AwsClientEndpointProvider; import software.amazon.awssdk.core.ClientEndpointProvider; -import software.amazon.awssdk.core.Protocol; import software.amazon.awssdk.core.SdkRequest; +import software.amazon.awssdk.endpoints.Endpoint; import software.amazon.awssdk.core.SelectedAuthScheme; import software.amazon.awssdk.core.client.config.SdkClientConfiguration; import software.amazon.awssdk.core.client.config.SdkClientOption; @@ -48,6 +47,8 @@ import software.amazon.awssdk.identity.spi.Identity; import software.amazon.awssdk.protocols.query.AwsQueryProtocolFactory; import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.docdb.endpoints.DocDbEndpointParams; +import software.amazon.awssdk.services.docdb.endpoints.DocDbEndpointProvider; import software.amazon.awssdk.services.docdb.model.DocDbRequest; import software.amazon.awssdk.utils.CompletableFutureUtils; @@ -219,16 +220,15 @@ private SdkHttpFullRequest toSdkHttpFullRequest(SignedRequest signedRequest) { } private URI createEndpoint(String regionName, String serviceName, ExecutionAttributes attributes) { - return AwsClientEndpointProvider.builder() - .serviceEndpointPrefix(SERVICE_NAME) - .defaultProtocol(Protocol.HTTPS.toString()) - .region(Region.of(regionName)) - .profileFile(attributes.getAttribute(SdkExecutionAttribute.PROFILE_FILE_SUPPLIER)) - .profileName(attributes.getAttribute(SdkExecutionAttribute.PROFILE_NAME)) - .dualstackEnabled( - attributes.getAttribute(AwsExecutionAttribute.DUALSTACK_ENDPOINT_ENABLED)) - .fipsEnabled(attributes.getAttribute(AwsExecutionAttribute.FIPS_ENDPOINT_ENABLED)) - .build() - .clientEndpoint(); + DocDbEndpointProvider provider = DocDbEndpointProvider.defaultProvider(); + DocDbEndpointParams params = DocDbEndpointParams.builder() + .region(Region.of(regionName)) + .useFips(attributes.getAttribute( + AwsExecutionAttribute.FIPS_ENDPOINT_ENABLED)) + .useDualStack(attributes.getAttribute( + AwsExecutionAttribute.DUALSTACK_ENDPOINT_ENABLED)) + .build(); + Endpoint endpoint = CompletableFutureUtils.joinLikeSync(provider.resolveEndpoint(params)); + return endpoint.url(); } } diff --git a/services/neptune/src/main/java/software/amazon/awssdk/services/neptune/internal/RdsPresignInterceptor.java b/services/neptune/src/main/java/software/amazon/awssdk/services/neptune/internal/RdsPresignInterceptor.java index 34f8fe30247c..dada110484d7 100644 --- a/services/neptune/src/main/java/software/amazon/awssdk/services/neptune/internal/RdsPresignInterceptor.java +++ b/services/neptune/src/main/java/software/amazon/awssdk/services/neptune/internal/RdsPresignInterceptor.java @@ -25,10 +25,9 @@ import java.util.concurrent.CompletableFuture; import software.amazon.awssdk.annotations.SdkInternalApi; import software.amazon.awssdk.awscore.AwsExecutionAttribute; -import software.amazon.awssdk.awscore.endpoint.AwsClientEndpointProvider; import software.amazon.awssdk.core.ClientEndpointProvider; -import software.amazon.awssdk.core.Protocol; import software.amazon.awssdk.core.SdkRequest; +import software.amazon.awssdk.endpoints.Endpoint; import software.amazon.awssdk.core.SelectedAuthScheme; import software.amazon.awssdk.core.client.config.SdkClientConfiguration; import software.amazon.awssdk.core.client.config.SdkClientOption; @@ -48,6 +47,8 @@ import software.amazon.awssdk.identity.spi.Identity; import software.amazon.awssdk.protocols.query.AwsQueryProtocolFactory; import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.neptune.endpoints.NeptuneEndpointParams; +import software.amazon.awssdk.services.neptune.endpoints.NeptuneEndpointProvider; import software.amazon.awssdk.services.neptune.model.NeptuneRequest; import software.amazon.awssdk.utils.CompletableFutureUtils; @@ -220,16 +221,16 @@ private SdkHttpFullRequest toSdkHttpFullRequest(SignedRequest signedRequest) { } private URI createEndpoint(String regionName, String serviceName, ExecutionAttributes attributes) { - return AwsClientEndpointProvider.builder() - .serviceEndpointPrefix(SERVICE_NAME) - .defaultProtocol(Protocol.HTTPS.toString()) - .region(Region.of(regionName)) - .profileFile(attributes.getAttribute(SdkExecutionAttribute.PROFILE_FILE_SUPPLIER)) - .profileName(attributes.getAttribute(SdkExecutionAttribute.PROFILE_NAME)) - .dualstackEnabled( - attributes.getAttribute(AwsExecutionAttribute.DUALSTACK_ENDPOINT_ENABLED)) - .fipsEnabled(attributes.getAttribute(AwsExecutionAttribute.FIPS_ENDPOINT_ENABLED)) - .build() - .clientEndpoint(); + NeptuneEndpointProvider provider = NeptuneEndpointProvider.defaultProvider(); + NeptuneEndpointParams params = NeptuneEndpointParams.builder() + .region(Region.of(regionName)) + .useFips(attributes.getAttribute( + AwsExecutionAttribute.FIPS_ENDPOINT_ENABLED)) + .useDualStack(attributes.getAttribute( + AwsExecutionAttribute.DUALSTACK_ENDPOINT_ENABLED)) + .build(); + Endpoint endpoint = CompletableFutureUtils.joinLikeSync(provider.resolveEndpoint(params)); + return endpoint.url(); } } +} diff --git a/services/polly/src/main/java/software/amazon/awssdk/services/polly/internal/presigner/DefaultPollyPresigner.java b/services/polly/src/main/java/software/amazon/awssdk/services/polly/internal/presigner/DefaultPollyPresigner.java index 0ed43bf8df63..f06b4a4f5629 100644 --- a/services/polly/src/main/java/software/amazon/awssdk/services/polly/internal/presigner/DefaultPollyPresigner.java +++ b/services/polly/src/main/java/software/amazon/awssdk/services/polly/internal/presigner/DefaultPollyPresigner.java @@ -342,17 +342,14 @@ private void applyEndpoint(SdkHttpFullRequest.Builder httpRequestBuilder) { private URI resolveEndpoint() { return AwsClientEndpointProvider.builder() - .clientEndpointOverride(endpointOverride) + .clientEndpointOverride(endpointOverride != null + ? endpointOverride + : URI.create("https://localhost")) .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_POLLY") .serviceEndpointOverrideSystemProperty("aws.endpointUrlPolly") .serviceProfileProperty("polly") - .serviceEndpointPrefix(SERVICE_NAME) - .defaultProtocol("https") - .region(region) .profileFile(profileFile) .profileName(profileName) - .dualstackEnabled(dualstackEnabled) - .fipsEnabled(fipsEnabled) .build() .clientEndpoint(); } diff --git a/services/rds/src/main/java/software/amazon/awssdk/services/rds/internal/RdsPresignInterceptor.java b/services/rds/src/main/java/software/amazon/awssdk/services/rds/internal/RdsPresignInterceptor.java index 3e55f5ae9f24..8cc5a70636d6 100644 --- a/services/rds/src/main/java/software/amazon/awssdk/services/rds/internal/RdsPresignInterceptor.java +++ b/services/rds/src/main/java/software/amazon/awssdk/services/rds/internal/RdsPresignInterceptor.java @@ -25,9 +25,7 @@ import java.util.concurrent.CompletableFuture; import software.amazon.awssdk.annotations.SdkInternalApi; import software.amazon.awssdk.awscore.AwsExecutionAttribute; -import software.amazon.awssdk.awscore.endpoint.AwsClientEndpointProvider; import software.amazon.awssdk.core.ClientEndpointProvider; -import software.amazon.awssdk.core.Protocol; import software.amazon.awssdk.core.SdkRequest; import software.amazon.awssdk.core.SelectedAuthScheme; import software.amazon.awssdk.core.client.config.SdkClientConfiguration; @@ -35,7 +33,7 @@ import software.amazon.awssdk.core.interceptor.Context; import software.amazon.awssdk.core.interceptor.ExecutionAttributes; import software.amazon.awssdk.core.interceptor.ExecutionInterceptor; -import software.amazon.awssdk.core.interceptor.SdkExecutionAttribute; +import software.amazon.awssdk.endpoints.Endpoint; import software.amazon.awssdk.http.SdkHttpFullRequest; import software.amazon.awssdk.http.SdkHttpMethod; import software.amazon.awssdk.http.SdkHttpRequest; @@ -48,6 +46,8 @@ import software.amazon.awssdk.identity.spi.Identity; import software.amazon.awssdk.protocols.query.AwsQueryProtocolFactory; import software.amazon.awssdk.regions.Region; +import software.amazon.awssdk.services.rds.endpoints.RdsEndpointParams; +import software.amazon.awssdk.services.rds.endpoints.RdsEndpointProvider; import software.amazon.awssdk.services.rds.model.RdsRequest; import software.amazon.awssdk.utils.CompletableFutureUtils; @@ -218,16 +218,14 @@ private SdkHttpFullRequest toSdkHttpFullRequest(SignedRequest signedRequest) { } private URI createEndpoint(String regionName, String serviceName, ExecutionAttributes attributes) { - return AwsClientEndpointProvider.builder() - .serviceEndpointPrefix(SERVICE_NAME) - .defaultProtocol(Protocol.HTTPS.toString()) - .region(Region.of(regionName)) - .profileFile(attributes.getAttribute(SdkExecutionAttribute.PROFILE_FILE_SUPPLIER)) - .profileName(attributes.getAttribute(SdkExecutionAttribute.PROFILE_NAME)) - .dualstackEnabled( - attributes.getAttribute(AwsExecutionAttribute.DUALSTACK_ENDPOINT_ENABLED)) - .fipsEnabled(attributes.getAttribute(AwsExecutionAttribute.FIPS_ENDPOINT_ENABLED)) - .build() - .clientEndpoint(); + RdsEndpointProvider provider = RdsEndpointProvider.defaultProvider(); + RdsEndpointParams params = RdsEndpointParams.builder() + .region(Region.of(regionName)) + .useFips(attributes.getAttribute(AwsExecutionAttribute.FIPS_ENDPOINT_ENABLED)) + .useDualStack( + attributes.getAttribute(AwsExecutionAttribute.DUALSTACK_ENDPOINT_ENABLED)) + .build(); + Endpoint endpoint = CompletableFutureUtils.joinLikeSync(provider.resolveEndpoint(params)); + return endpoint.url(); } } diff --git a/services/s3/src/main/java/software/amazon/awssdk/services/s3/S3Utilities.java b/services/s3/src/main/java/software/amazon/awssdk/services/s3/S3Utilities.java index cb3064798a99..991184a471ba 100644 --- a/services/s3/src/main/java/software/amazon/awssdk/services/s3/S3Utilities.java +++ b/services/s3/src/main/java/software/amazon/awssdk/services/s3/S3Utilities.java @@ -40,6 +40,7 @@ import software.amazon.awssdk.awscore.endpoint.FipsEnabledProvider; import software.amazon.awssdk.awscore.internal.defaultsmode.DefaultsModeConfiguration; import software.amazon.awssdk.core.ClientEndpointProvider; +import software.amazon.awssdk.endpoints.Endpoint; import software.amazon.awssdk.core.ClientType; import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration; import software.amazon.awssdk.core.client.config.SdkClientConfiguration; @@ -62,7 +63,9 @@ import software.amazon.awssdk.regions.Region; import software.amazon.awssdk.regions.ServiceMetadataAdvancedOption; import software.amazon.awssdk.services.s3.endpoints.S3ClientContextParams; +import software.amazon.awssdk.services.s3.endpoints.S3EndpointParams; import software.amazon.awssdk.services.s3.endpoints.S3EndpointProvider; +import software.amazon.awssdk.utils.CompletableFutureUtils; import software.amazon.awssdk.services.s3.endpoints.internal.S3RequestSetEndpointInterceptor; import software.amazon.awssdk.services.s3.endpoints.internal.S3ResolveEndpointInterceptor; import software.amazon.awssdk.services.s3.internal.endpoints.UseGlobalEndpointResolver; @@ -428,19 +431,34 @@ private Region resolveRegionForGetUrl(GetUrlRequest getUrlRequest) { * If endpoint is not present, construct a default endpoint using the region information. */ private ClientEndpointProvider clientEndpointProvider(URI overrideEndpoint, Region region) { - return AwsClientEndpointProvider.builder() - .clientEndpointOverride(overrideEndpoint) + if (overrideEndpoint != null) { + return AwsClientEndpointProvider.builder() + .clientEndpointOverride(overrideEndpoint) + .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_S3") + .serviceEndpointOverrideSystemProperty("aws.endpointUrlS3") + .serviceProfileProperty("s3") + .profileFile(profileFile) + .profileName(profileName) + .build(); + } + Optional fromOverrides = AwsClientEndpointProvider.builder() .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_S3") .serviceEndpointOverrideSystemProperty("aws.endpointUrlS3") .serviceProfileProperty("s3") - .serviceEndpointPrefix(SERVICE_NAME) - .defaultProtocol("https") - .region(region) .profileFile(profileFile) .profileName(profileName) - .dualstackEnabled(s3Configuration.dualstackEnabled()) - .fipsEnabled(fipsEnabled) - .build(); + .buildOptional(); + if (fromOverrides.isPresent()) { + return fromOverrides.get(); + } + S3EndpointProvider provider = S3EndpointProvider.defaultProvider(); + S3EndpointParams params = S3EndpointParams.builder() + .region(region) + .useFips(fipsEnabled) + .useDualStack(s3Configuration.dualstackEnabled()) + .build(); + Endpoint endpoint = CompletableFutureUtils.joinLikeSync(provider.resolveEndpoint(params)); + return ClientEndpointProvider.create(endpoint.url(), false); } private URI getEndpointOverride(GetUrlRequest request) { diff --git a/services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/signing/DefaultS3Presigner.java b/services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/signing/DefaultS3Presigner.java index 48e09c49a6ba..b7dffb9f0c31 100644 --- a/services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/signing/DefaultS3Presigner.java +++ b/services/s3/src/main/java/software/amazon/awssdk/services/s3/internal/signing/DefaultS3Presigner.java @@ -21,6 +21,7 @@ import static software.amazon.awssdk.utils.CollectionUtils.mergeLists; import static software.amazon.awssdk.utils.FunctionalUtils.invokeSafely; +import java.net.URI; import java.time.Clock; import java.time.Duration; import java.time.Instant; @@ -251,20 +252,37 @@ private List initializeInterceptors() { * Copied from {@link AwsDefaultClientBuilder}. */ private SdkClientConfiguration createClientConfiguration() { - AwsClientEndpointProvider endpointProvider = - AwsClientEndpointProvider.builder() - .clientEndpointOverride(endpointOverride()) - .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_S3") - .serviceEndpointOverrideSystemProperty("aws.endpointUrlS3") - .serviceProfileProperty("s3") - .serviceEndpointPrefix(SERVICE_NAME) - .defaultProtocol("https") - .region(region()) - .profileFile(profileFileSupplier()) - .profileName(profileName()) - .dualstackEnabled(serviceConfiguration.dualstackEnabled()) - .fipsEnabled(fipsEnabled()) - .build(); + ClientEndpointProvider endpointProvider; + if (endpointOverride() != null) { + endpointProvider = AwsClientEndpointProvider.builder() + .clientEndpointOverride(endpointOverride()) + .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_S3") + .serviceEndpointOverrideSystemProperty("aws.endpointUrlS3") + .serviceProfileProperty("s3") + .profileFile(profileFileSupplier()) + .profileName(profileName()) + .build(); + } else { + Optional fromOverrides = AwsClientEndpointProvider.builder() + .serviceEndpointOverrideEnvironmentVariable("AWS_ENDPOINT_URL_S3") + .serviceEndpointOverrideSystemProperty("aws.endpointUrlS3") + .serviceProfileProperty("s3") + .profileFile(profileFileSupplier()) + .profileName(profileName()) + .buildOptional(); + if (fromOverrides.isPresent()) { + endpointProvider = fromOverrides.get(); + } else { + S3EndpointProvider s3EndpointProvider = S3EndpointProvider.defaultProvider(); + S3EndpointParams params = S3EndpointParams.builder() + .region(region()) + .useFips(fipsEnabled()) + .useDualStack(serviceConfiguration.dualstackEnabled()) + .build(); + Endpoint endpoint = CompletableFutureUtils.joinLikeSync(s3EndpointProvider.resolveEndpoint(params)); + endpointProvider = ClientEndpointProvider.create(endpoint.url(), false); + } + } // Make sure the endpoint resolver can actually resolve an endpoint, so that we fail now instead of // when a request is made. diff --git a/services/s3/src/test/java/software/amazon/awssdk/services/s3/InvalidRegionTest.java b/services/s3/src/test/java/software/amazon/awssdk/services/s3/InvalidRegionTest.java index 4eef66bf2e22..778d766a7117 100644 --- a/services/s3/src/test/java/software/amazon/awssdk/services/s3/InvalidRegionTest.java +++ b/services/s3/src/test/java/software/amazon/awssdk/services/s3/InvalidRegionTest.java @@ -32,9 +32,8 @@ public void invalidS3UtilitiesRegionAtClientGivesHelpfulMessage() { assertThatThrownBy(() -> utilities.getUrl(r -> r.bucket("foo").key("bar"))) .isInstanceOf(SdkClientException.class) - .hasMessageContaining("US_EAST_1") .hasMessageContaining("region") - .hasMessageContaining("us-east-1"); + .hasMessageContaining("DNS"); } @Test @@ -43,9 +42,8 @@ public void invalidS3UtilitiesRegionAtRequestGivesHelpfulMessage() { assertThatThrownBy(() -> utilities.getUrl(r -> r.bucket("foo").key("bar").region(Region.of("US_WEST_2")))) .isInstanceOf(SdkClientException.class) - .hasMessageContaining("US_WEST_2") .hasMessageContaining("region") - .hasMessageContaining("us-west-2"); + .hasMessageContaining("DNS"); } @Test @@ -77,7 +75,8 @@ public void invalidS3ArnRegionAtRequestGivesHelpfulMessage() { public void invalidS3PresignerRegionAtClientGivesHelpfulMessage() { assertThatThrownBy(() -> S3Presigner.builder().region(Region.of("US_EAST_1")).build()) .isInstanceOf(SdkClientException.class) - .hasMessageContaining("Configured region (US_EAST_1) and tags ([]) resulted in an invalid URI"); + .hasMessageContaining("region") + .hasMessageContaining("DNS"); } @Test