1 /*
2  * Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License").
5  * You may not use this file except in compliance with the License.
6  * A copy of the License is located at
7  *
8  *  http://aws.amazon.com/apache2.0
9  *
10  * or in the "license" file accompanying this file. This file is distributed
11  * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either
12  * express or implied. See the License for the specific language governing
13  * permissions and limitations under the License.
14  */

15
16 package software.amazon.awssdk.awscore.client.handler;
17
18 import static software.amazon.awssdk.utils.CollectionUtils.firstIfPresent;
19
20 import java.io.IOException;
21 import java.io.UncheckedIOException;
22 import java.nio.ByteBuffer;
23 import java.util.Map;
24 import java.util.stream.Collectors;
25 import software.amazon.awssdk.annotations.SdkProtectedApi;
26 import software.amazon.awssdk.auth.credentials.AwsCredentials;
27 import software.amazon.awssdk.auth.credentials.AwsCredentialsProvider;
28 import software.amazon.awssdk.auth.signer.AwsSignerExecutionAttribute;
29 import software.amazon.awssdk.awscore.AwsExecutionAttribute;
30 import software.amazon.awssdk.awscore.AwsRequestOverrideConfiguration;
31 import software.amazon.awssdk.awscore.client.config.AwsAdvancedClientOption;
32 import software.amazon.awssdk.awscore.client.config.AwsClientOption;
33 import software.amazon.awssdk.core.RequestOverrideConfiguration;
34 import software.amazon.awssdk.core.SdkRequest;
35 import software.amazon.awssdk.core.SdkResponse;
36 import software.amazon.awssdk.core.client.config.SdkClientConfiguration;
37 import software.amazon.awssdk.core.client.config.SdkClientOption;
38 import software.amazon.awssdk.core.client.handler.ClientExecutionParams;
39 import software.amazon.awssdk.core.http.ExecutionContext;
40 import software.amazon.awssdk.core.interceptor.ExecutionAttributes;
41 import software.amazon.awssdk.core.interceptor.ExecutionInterceptorChain;
42 import software.amazon.awssdk.core.interceptor.InterceptorContext;
43 import software.amazon.awssdk.core.interceptor.SdkExecutionAttribute;
44 import software.amazon.awssdk.core.interceptor.SdkInternalExecutionAttribute;
45 import software.amazon.awssdk.core.signer.Signer;
46 import software.amazon.awssdk.http.SdkHttpFullRequest;
47 import software.amazon.awssdk.utils.IoUtils;
48 import software.amazon.awssdk.utils.Validate;
49 import software.amazon.eventstream.HeaderValue;
50 import software.amazon.eventstream.Message;
51
52 @SdkProtectedApi
53 public final class AwsClientHandlerUtils {
54
55     private AwsClientHandlerUtils() {
56
57     }
58
59     static <InputT extends SdkRequest, OutputT extends SdkResponse> ExecutionContext createExecutionContext(
60         ClientExecutionParams<InputT, OutputT> executionParams,
61         SdkClientConfiguration clientConfig,
62         ExecutionAttributes executionAttributes) {
63
64         SdkRequest originalRequest = executionParams.getInput();
65         AwsCredentialsProvider clientCredentials = clientConfig.option(AwsClientOption.CREDENTIALS_PROVIDER);
66         AwsCredentialsProvider credentialsProvider = originalRequest.overrideConfiguration()
67                                                                     .filter(c -> c instanceof AwsRequestOverrideConfiguration)
68                                                                     .map(c -> (AwsRequestOverrideConfiguration) c)
69                                                                     .flatMap(AwsRequestOverrideConfiguration::credentialsProvider)
70                                                                     .orElse(clientCredentials);
71
72         AwsCredentials credentials = credentialsProvider.resolveCredentials();
73
74         Validate.validState(credentials != null"Credential providers must never return null.");
75
76         executionAttributes
77             .putAttribute(AwsSignerExecutionAttribute.SERVICE_CONFIG, clientConfig.option(SdkClientOption.SERVICE_CONFIGURATION))
78             .putAttribute(AwsSignerExecutionAttribute.AWS_CREDENTIALS, credentials)
79             .putAttribute(AwsSignerExecutionAttribute.SERVICE_SIGNING_NAME,
80                           clientConfig.option(AwsClientOption.SERVICE_SIGNING_NAME))
81             .putAttribute(AwsExecutionAttribute.AWS_REGION, clientConfig.option(AwsClientOption.AWS_REGION))
82             .putAttribute(AwsExecutionAttribute.ENDPOINT_PREFIX, clientConfig.option(AwsClientOption.ENDPOINT_PREFIX))
83             .putAttribute(AwsSignerExecutionAttribute.SIGNING_REGION, clientConfig.option(AwsClientOption.SIGNING_REGION))
84             .putAttribute(SdkInternalExecutionAttribute.IS_FULL_DUPLEX, executionParams.isFullDuplex())
85             .putAttribute(SdkExecutionAttribute.CLIENT_TYPE, clientConfig.option(SdkClientOption.CLIENT_TYPE))
86             .putAttribute(SdkExecutionAttribute.SERVICE_NAME, clientConfig.option(SdkClientOption.SERVICE_NAME))
87             .putAttribute(SdkExecutionAttribute.OPERATION_NAME, executionParams.getOperationName())
88             .putAttribute(SdkExecutionAttribute.ENDPOINT_OVERRIDDEN,
89                           clientConfig.option(SdkClientOption.ENDPOINT_OVERRIDDEN));
90
91         ExecutionInterceptorChain executionInterceptorChain =
92                 new ExecutionInterceptorChain(clientConfig.option(SdkClientOption.EXECUTION_INTERCEPTORS));
93         return ExecutionContext.builder()
94                                .interceptorChain(executionInterceptorChain)
95                                .interceptorContext(InterceptorContext.builder()
96                                                                      .request(originalRequest)
97                                                                      .asyncRequestBody(executionParams.getAsyncRequestBody())
98                                                                      .requestBody(executionParams.getRequestBody())
99                                                                      .build())
100                                .executionAttributes(executionAttributes)
101                                .signer(computeSigner(originalRequest, clientConfig))
102                                .build();
103     }
104
105     /**
106      * Encodes the request into a flow message and then returns bytebuffer from the message.
107      *
108      * @param request The request to encode
109      * @return A bytebuffer representing the given request
110      */

111     public static ByteBuffer encodeEventStreamRequestToByteBuffer(SdkHttpFullRequest request) {
112         Map<String, HeaderValue> headers = request.headers()
113                                                   .entrySet()
114                                                   .stream()
115                                                   .collect(Collectors.toMap(Map.Entry::getKey, e -> HeaderValue.fromString(
116                                                       firstIfPresent(e.getValue()))));
117         byte[] payload = null;
118         if (request.contentStreamProvider().isPresent()) {
119             try {
120                 payload = IoUtils.toByteArray(request.contentStreamProvider().get().newStream());
121             } catch (IOException e) {
122                 throw new UncheckedIOException(e);
123             }
124         }
125
126         return new Message(headers, payload).toByteBuffer();
127     }
128
129     // Signer at request level gets priority over client config signer
130     private static Signer computeSigner(SdkRequest originalRequest,
131                                         SdkClientConfiguration clientConfiguration) {
132         return originalRequest.overrideConfiguration()
133                               .flatMap(RequestOverrideConfiguration::signer)
134                               .orElse(clientConfiguration.option(AwsAdvancedClientOption.SIGNER));
135     }
136 }
137