1
15
16 package software.amazon.awssdk.core.internal.handler;
17
18 import java.net.URI;
19 import java.util.function.BiFunction;
20 import software.amazon.awssdk.annotations.SdkInternalApi;
21 import software.amazon.awssdk.core.Response;
22 import software.amazon.awssdk.core.SdkRequest;
23 import software.amazon.awssdk.core.SdkResponse;
24 import software.amazon.awssdk.core.client.config.SdkAdvancedClientOption;
25 import software.amazon.awssdk.core.client.config.SdkClientConfiguration;
26 import software.amazon.awssdk.core.client.config.SdkClientOption;
27 import software.amazon.awssdk.core.client.handler.ClientExecutionParams;
28 import software.amazon.awssdk.core.http.ExecutionContext;
29 import software.amazon.awssdk.core.http.HttpResponseHandler;
30 import software.amazon.awssdk.core.interceptor.ExecutionAttributes;
31 import software.amazon.awssdk.core.interceptor.ExecutionInterceptorChain;
32 import software.amazon.awssdk.core.interceptor.InterceptorContext;
33 import software.amazon.awssdk.core.interceptor.SdkExecutionAttribute;
34 import software.amazon.awssdk.core.internal.InternalCoreExecutionAttribute;
35 import software.amazon.awssdk.http.SdkHttpFullRequest;
36 import software.amazon.awssdk.http.SdkHttpFullResponse;
37 import software.amazon.awssdk.utils.StringUtils;
38
39 @SdkInternalApi
40 public abstract class BaseClientHandler {
41 private SdkClientConfiguration clientConfiguration;
42
43 protected BaseClientHandler(SdkClientConfiguration clientConfiguration) {
44 this.clientConfiguration = clientConfiguration;
45 }
46
47
53 static InterceptorContext finalizeSdkRequest(ExecutionContext executionContext) {
54 runBeforeExecutionInterceptors(executionContext);
55 return runModifyRequestInterceptors(executionContext);
56 }
57
58
62 static <InputT extends SdkRequest, OutputT> InterceptorContext finalizeSdkHttpFullRequest(
63 ClientExecutionParams<InputT, OutputT> executionParams,
64 ExecutionContext executionContext, InputT inputT,
65 SdkClientConfiguration clientConfiguration) {
66
67 runBeforeMarshallingInterceptors(executionContext);
68 SdkHttpFullRequest request = executionParams.getMarshaller().marshall(inputT);
69 request = modifyEndpointHostIfNeeded(request, clientConfiguration, executionParams);
70
71 addHttpRequest(executionContext, request);
72 runAfterMarshallingInterceptors(executionContext);
73 return runModifyHttpRequestAndHttpContentInterceptors(executionContext);
74 }
75
76 private static void runBeforeExecutionInterceptors(ExecutionContext executionContext) {
77 executionContext.interceptorChain().beforeExecution(executionContext.interceptorContext(),
78 executionContext.executionAttributes());
79 }
80
81 private static InterceptorContext runModifyRequestInterceptors(ExecutionContext executionContext) {
82 InterceptorContext interceptorContext =
83 executionContext.interceptorChain().modifyRequest(executionContext.interceptorContext(),
84 executionContext.executionAttributes());
85 executionContext.interceptorContext(interceptorContext);
86 return interceptorContext;
87 }
88
89 private static void runBeforeMarshallingInterceptors(ExecutionContext executionContext) {
90 executionContext.interceptorChain().beforeMarshalling(executionContext.interceptorContext(),
91 executionContext.executionAttributes());
92 }
93
94
97 private static SdkHttpFullRequest modifyEndpointHostIfNeeded(SdkHttpFullRequest originalRequest,
98 SdkClientConfiguration clientConfiguration,
99 ClientExecutionParams executionParams) {
100 if (executionParams.discoveredEndpoint() != null) {
101 URI discoveredEndpoint = executionParams.discoveredEndpoint();
102 return originalRequest.toBuilder().host(discoveredEndpoint.getHost()).port(discoveredEndpoint.getPort()).build();
103 }
104
105 Boolean disableHostPrefixInjection = clientConfiguration.option(SdkAdvancedClientOption.DISABLE_HOST_PREFIX_INJECTION);
106 if ((disableHostPrefixInjection != null && disableHostPrefixInjection.equals(Boolean.TRUE)) ||
107 StringUtils.isEmpty(executionParams.hostPrefixExpression())) {
108 return originalRequest;
109 }
110
111 return originalRequest.toBuilder()
112 .host(executionParams.hostPrefixExpression() + originalRequest.host())
113 .build();
114 }
115
116 private static void addHttpRequest(ExecutionContext executionContext, SdkHttpFullRequest request) {
117 InterceptorContext interceptorContext = executionContext.interceptorContext().copy(b -> b.httpRequest(request));
118 executionContext.interceptorContext(interceptorContext);
119 }
120
121 private static void runAfterMarshallingInterceptors(ExecutionContext executionContext) {
122 executionContext.interceptorChain().afterMarshalling(executionContext.interceptorContext(),
123 executionContext.executionAttributes());
124 }
125
126 private static InterceptorContext runModifyHttpRequestAndHttpContentInterceptors(ExecutionContext executionContext) {
127 InterceptorContext interceptorContext =
128 executionContext.interceptorChain().modifyHttpRequestAndHttpContent(executionContext.interceptorContext(),
129 executionContext.executionAttributes());
130 executionContext.interceptorContext(interceptorContext);
131 return interceptorContext;
132 }
133
134
137 private static <OutputT extends SdkResponse> BiFunction<OutputT, SdkHttpFullResponse, OutputT>
138 runAfterUnmarshallingInterceptors(ExecutionContext context) {
139
140 return (input, httpFullResponse) -> {
141
142 InterceptorContext interceptorContext =
143 context.interceptorContext().copy(b -> b.response(input));
144
145 context.interceptorChain().afterUnmarshalling(interceptorContext, context.executionAttributes());
146
147 interceptorContext = context.interceptorChain().modifyResponse(interceptorContext, context.executionAttributes());
148
149
150 context.interceptorContext(interceptorContext);
151
152 return (OutputT) interceptorContext.response();
153 };
154 }
155
156 private static <OutputT extends SdkResponse> BiFunction<OutputT, SdkHttpFullResponse, OutputT>
157 attachHttpResponseToResult() {
158
159 return ((response, httpFullResponse) ->
160 (OutputT) response.toBuilder().sdkHttpResponse(httpFullResponse).build());
161 }
162
163 static ExecutionAttributes createInitialExecutionAttributes() {
164 return new ExecutionAttributes().putAttribute(InternalCoreExecutionAttribute.EXECUTION_ATTEMPT, 1);
165 }
166
167 protected <InputT extends SdkRequest, OutputT extends SdkResponse> ExecutionContext createExecutionContext(
168 ClientExecutionParams<InputT, OutputT> params, ExecutionAttributes executionAttributes) {
169
170 SdkRequest originalRequest = params.getInput();
171
172 executionAttributes
173 .putAttribute(SdkExecutionAttribute.SERVICE_CONFIG,
174 clientConfiguration.option(SdkClientOption.SERVICE_CONFIGURATION))
175 .putAttribute(SdkExecutionAttribute.SERVICE_NAME, clientConfiguration.option(SdkClientOption.SERVICE_NAME));
176
177 ExecutionInterceptorChain interceptorChain =
178 new ExecutionInterceptorChain(clientConfiguration.option(SdkClientOption.EXECUTION_INTERCEPTORS));
179
180 return ExecutionContext.builder()
181 .interceptorChain(interceptorChain)
182 .interceptorContext(InterceptorContext.builder()
183 .request(originalRequest)
184 .build())
185 .executionAttributes(executionAttributes)
186 .signer(clientConfiguration.option(SdkAdvancedClientOption.SIGNER))
187 .build();
188 }
189
190 protected boolean isCalculateCrc32FromCompressedData() {
191 return clientConfiguration.option(SdkClientOption.CRC32_FROM_COMPRESSED_DATA_ENABLED);
192 }
193
194
197 <OutputT extends SdkResponse> HttpResponseHandler<OutputT> decorateResponseHandlers(
198 HttpResponseHandler<OutputT> delegate, ExecutionContext executionContext) {
199
200 return resultTransformationResponseHandler(delegate, responseTransformations(executionContext));
201 }
202
203 <OutputT extends SdkResponse> HttpResponseHandler<Response<OutputT>> decorateSuccessResponseHandlers(
204 HttpResponseHandler<Response<OutputT>> delegate, ExecutionContext executionContext) {
205
206 return successTransformationResponseHandler(delegate, responseTransformations(executionContext));
207 }
208
209 <OutputT extends SdkResponse> HttpResponseHandler<Response<OutputT>> successTransformationResponseHandler(
210 HttpResponseHandler<Response<OutputT>> responseHandler,
211 BiFunction<OutputT, SdkHttpFullResponse, OutputT> successTransformer) {
212
213 return (response, executionAttributes) -> {
214 Response<OutputT> delegateResponse = responseHandler.handle(response, executionAttributes);
215
216 if (delegateResponse.isSuccess()) {
217 return delegateResponse.toBuilder()
218 .response(successTransformer.apply(delegateResponse.response(), response))
219 .build();
220 } else {
221 return delegateResponse;
222 }
223 };
224 }
225
226 <OutputT extends SdkResponse> HttpResponseHandler<OutputT> resultTransformationResponseHandler(
227 HttpResponseHandler<OutputT> responseHandler,
228 BiFunction<OutputT, SdkHttpFullResponse, OutputT> successTransformer) {
229
230 return (response, executionAttributes) -> {
231 OutputT delegateResponse = responseHandler.handle(response, executionAttributes);
232 return successTransformer.apply(delegateResponse, response);
233 };
234 }
235
236 static void validateExecutionParams(ClientExecutionParams<?, ?> executionParams) {
237 if (executionParams.getCombinedResponseHandler() != null) {
238 if (executionParams.getResponseHandler() != null) {
239 throw new IllegalArgumentException("Only one of 'combinedResponseHandler' and 'responseHandler' may "
240 + "be specified in a ClientExecutionParams object");
241 }
242
243 if (executionParams.getErrorResponseHandler() != null) {
244 throw new IllegalArgumentException("Only one of 'combinedResponseHandler' and 'errorResponseHandler' "
245 + "may be specified in a ClientExecutionParams object");
246 }
247 }
248 }
249
250
254 private static <T extends SdkResponse> BiFunction<T, SdkHttpFullResponse, T>
255 responseTransformations(ExecutionContext executionContext) {
256
257 return composeResponseFunctions(runAfterUnmarshallingInterceptors(executionContext),
258 attachHttpResponseToResult());
259 }
260
261
270 private static <T, R> BiFunction<T, R, T> composeResponseFunctions(BiFunction<T, R, T> function1,
271 BiFunction<T, R, T> function2) {
272 return (x, y) -> function2.apply(function1.apply(x, y), y);
273 }
274 }
275