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.core.interceptor;
17 
18 import java.io.InputStream;
19 import java.nio.ByteBuffer;
20 import java.util.Optional;
21 import org.reactivestreams.Publisher;
22 import software.amazon.awssdk.annotations.SdkPublicApi;
23 import software.amazon.awssdk.core.SdkRequest;
24 import software.amazon.awssdk.core.SdkResponse;
25 import software.amazon.awssdk.core.async.AsyncRequestBody;
26 
27 // CHECKSTYLE:OFF - Avoid "Unused Import" error. If we use the FQCN in the Javadoc, we'll run into line length issues instead.
28 import software.amazon.awssdk.core.client.config.ClientOverrideConfiguration;
29 // CHECKSTYLE:ON
30 import software.amazon.awssdk.core.retry.RetryPolicy;
31 import software.amazon.awssdk.core.sync.RequestBody;
32 import software.amazon.awssdk.http.SdkHttpFullRequest;
33 import software.amazon.awssdk.http.SdkHttpRequest;
34 import software.amazon.awssdk.http.SdkHttpResponse;
35 
36 /**
37  * An interceptor that is invoked during the execution lifecycle of a request/response (execution). This can be used to publish
38  * metrics, modify a request in-flight, debug request processing, view exceptions, etc. This interface exposes different methods
39  * for hooking into different parts of the lifecycle of an execution.
40  *
41  * <p>
42  * <b>Interceptor Hooks</b>
43  * Methods for a given interceptor are executed in a predictable order, each receiving the information that is known about the
44  * message so far as well as a {@link ExecutionAttributes} object for storing data that is specific to a particular execution.
45  * <ol>
46  * <li>{@link #beforeExecution} - Read the request before it is modified by other interceptors.</li>
47  * <li>{@link #modifyRequest} - Modify the request object before it is marshalled into an HTTP request.</li>
48  * <li>{@link #beforeMarshalling} - Read the request that has potentially been modified by other request interceptors before
49  * it is marshalled into an HTTP request.</li>
50  * <li>{@link #afterMarshalling} - Read the HTTP request after it is created and before it can be modified by other
51  * interceptors.</li>
52  * <li>{@link #modifyHttpRequest} - Modify the HTTP request object before it is transmitted.</li>
53  * <li>{@link #beforeTransmission} - Read the HTTP request that has potentially been modified by other request interceptors
54  * before it is sent to the service.</li>
55  * <li>{@link #afterTransmission} - Read the HTTP response after it is received and before it can be modified by other
56  * interceptors.</li>
57  * <li>{@link #modifyHttpResponse} - Modify the HTTP response object before it is unmarshalled.</li>
58  * <li>{@link #beforeUnmarshalling} - Read the HTTP response that has potentially been modified by other request interceptors
59  * before it is unmarshalled.</li>
60  * <li>{@link #afterUnmarshalling} - Read the response after it is created and before it can be modified by other
61  * interceptors.</li>
62  * <li>{@link #modifyResponse} - Modify the response object before before it is returned to the client.</li>
63  * <li>{@link #afterExecution} - Read the response that has potentially been modified by other request interceptors.</li>
64  * </ol>
65  * An additional {@link #onExecutionFailure} method is provided that is invoked if an execution fails at any point during the
66  * lifecycle of a request, including exceptions being thrown from this or other interceptors.
67  * <p>
68  *
69  * <p>
70  * <b>Interceptor Registration</b>
71  * Interceptors can be registered in one of many ways.
72  * <ol>
73  * <li><i>Override Configuration Interceptors</i> are the most common method for SDK users to register an interceptor. These
74  * interceptors are explicitly added to the client builder's override configuration when a client is created using the {@link
75  * ClientOverrideConfiguration.Builder#addExecutionInterceptor(ExecutionInterceptor)}
76  * method.</li>
77  *
78  * <li><i>Global Interceptors</i> are interceptors loaded from the classpath for all clients. When any service client is
79  * created by a client builder, all jars on the classpath (from the perspective of the current thread's classloader) are
80  * checked for a file named '/software/amazon/awssdk/global/handlers/execution.interceptors'. Any interceptors listed in these
81  * files (new line separated) are instantiated using their default constructor and loaded into the client.</li>
82  *
83  * <li><i>Service Interceptors</i> are interceptors loaded from the classpath for a particular service's clients. When a
84  * service client is created by a client builder, all jars on the classpath (from the perspective of the current thread's
85  * classloader) are checked for a file named '/software/amazon/awssdk/services/{service}/execution.interceptors', where
86  * {service} is the package name of the service client. Any interceptors listed in these files (new line separated) are
87  * instantiated using their default constructor and loaded into the client.</li>
88  * </ol>
89  * <p>
90  *
91  * <p>
92  * <b>Interceptor Order</b>
93  * The order in which interceptors are executed is sometimes relevant to the accuracy of the interceptor itself. For example, an
94  * interceptor that adds a field to a message should be executed before an interceptor that reads and modifies that field.
95  * Interceptor's order is determined by their method of registration. The following order is used:
96  * <ol>
97  * <li><i>Global Interceptors</i>. Interceptors earlier in the classpath will be placed earlier in the interceptor order than
98  * interceptors later in the classpath. Interceptors earlier within a specific file on the classpath will be placed earlier in
99  * the order than interceptors later in the file.</li>
100  *
101  * <li><i>Service Interceptors</i>. Interceptors earlier in the classpath will be placed earlier in the interceptor order than
102  * interceptors later in the classpath. Interceptors earlier within a specific file on the classpath will be placed earlier in
103  * the order than interceptors later in the file.</li>
104  *
105  * <li><i>Override Configuration Interceptors</i>. Any interceptors registered using
106  * {@link ClientOverrideConfiguration.Builder#addExecutionInterceptor(ExecutionInterceptor)}
107  * in the order they were added.</li>
108  * </ol>
109  * When a request is being processed (up to and including {@link #beforeTransmission}, interceptors are applied in forward-order,
110  * according to the order described above. When a response is being processed (after and including {@link #afterTransmission},
111  * interceptors are applied in reverse-order from the order described above. This means that the last interceptors to touch the
112  * request are the first interceptors to touch the response.
113  * <p>
114  *
115  * <p>
116  * <b>Execution Attributes</b>
117  * {@link ExecutionAttributes} are unique to an execution (the process of an SDK processing a {@link SdkRequest}). This mutable
118  * collection of attributes is created when a call to a service client is made and can be mutated throughout the course of the
119  * client call. These attributes are made available to every interceptor hook and is available for storing data between method
120  * calls. The SDK provides some attributes automatically, available via {@link SdkExecutionAttribute}.
121  */
122 @SdkPublicApi
123 public interface ExecutionInterceptor {
124     /**
125      * Read a request that has been given to a service client before it is modified by other interceptors.
126      * {@link #beforeMarshalling} should be used in most circumstances for reading the request because it includes modifications
127      * made by other interceptors.
128      *
129      * <p>This method is guaranteed to be executed on the thread that is making the client call. This is true even if a non-
130      * blocking I/O client is used. This is useful for transferring data that may be stored thread-locally into the execution's
131      * {@link ExecutionAttributes}.
132      *
133      * @param context The current state of the execution, including the unmodified SDK request from the service client call.
134      * @param executionAttributes A mutable set of attributes scoped to one specific request/response cycle that can be used to
135      */
beforeExecution(Context.BeforeExecution context, ExecutionAttributes executionAttributes)136     default void beforeExecution(Context.BeforeExecution context, ExecutionAttributes executionAttributes) {
137 
138     }
139 
140     /**
141      * Modify an {@link SdkRequest} given to a service client before it is marshalled into an {@link SdkHttpFullRequest}.
142      *
143      * @param context The current state of the execution, including the current SDK request from the service client call.
144      * @param executionAttributes A mutable set of attributes scoped to one specific request/response cycle that can be used to
145      * give data to future lifecycle methods.
146      * @return The potentially-modified request that should be used for the rest of the execution. Must not be null.
147      */
modifyRequest(Context.ModifyRequest context, ExecutionAttributes executionAttributes)148     default SdkRequest modifyRequest(Context.ModifyRequest context, ExecutionAttributes executionAttributes) {
149         return context.request();
150     }
151 
152     /**
153      * Read the finalized request as it will be given to the marshaller to be converted into an {@link SdkHttpFullRequest}.
154      *
155      * @param context The current state of the execution, including the SDK request (potentially modified by other interceptors)
156      * from the service client call.
157      * @param executionAttributes A mutable set of attributes scoped to one specific request/response cycle that can be used to
158      */
beforeMarshalling(Context.BeforeMarshalling context, ExecutionAttributes executionAttributes)159     default void beforeMarshalling(Context.BeforeMarshalling context, ExecutionAttributes executionAttributes) {
160     }
161 
162     /**
163      * Read the marshalled HTTP request, before it is modified by other interceptors. {@link #beforeTransmission} should be used
164      * in most circumstances for reading the HTTP request because it includes modifications made by other interceptors.
165      *
166      * @param context The current state of the execution, including the SDK and unmodified HTTP request.
167      * @param executionAttributes A mutable set of attributes scoped to one specific request/response cycle that can be used to
168      */
afterMarshalling(Context.AfterMarshalling context, ExecutionAttributes executionAttributes)169     default void afterMarshalling(Context.AfterMarshalling context, ExecutionAttributes executionAttributes) {
170 
171     }
172 
173     /**
174      * Modify the {@link SdkHttpFullRequest} before it is sent to the service.
175      *
176      * @param context The current state of the execution, including the SDK and current HTTP request.
177      * @param executionAttributes A mutable set of attributes scoped to one specific request/response cycle that can be used to
178      * give data to future lifecycle methods.
179      * @return The potentially-modified HTTP request that should be sent to the service. Must not be null.
180      */
modifyHttpRequest(Context.ModifyHttpRequest context, ExecutionAttributes executionAttributes)181     default SdkHttpRequest modifyHttpRequest(Context.ModifyHttpRequest context,
182                                              ExecutionAttributes executionAttributes) {
183         return context.httpRequest();
184     }
185 
modifyHttpContent(Context.ModifyHttpRequest context, ExecutionAttributes executionAttributes)186     default Optional<RequestBody> modifyHttpContent(Context.ModifyHttpRequest context,
187                                           ExecutionAttributes executionAttributes) {
188         return context.requestBody();
189     }
190 
modifyAsyncHttpContent(Context.ModifyHttpRequest context, ExecutionAttributes executionAttributes)191     default Optional<AsyncRequestBody> modifyAsyncHttpContent(Context.ModifyHttpRequest context,
192                                                     ExecutionAttributes executionAttributes) {
193         return context.asyncRequestBody();
194     }
195 
196     /**
197      * Read the finalized HTTP request as it will be sent to the HTTP client. This includes modifications made by other
198      * interceptors and the message signature. It is possible that the HTTP client could further modify the request, so debug-
199      * level wire logging should be trusted over the parameters to this method.
200      *
201      * <p>Note: Unlike many other lifecycle methods, this one may be invoked multiple times. If the {@link RetryPolicy} determines
202      * a request failure is retriable, this will be invoked for each retry attempt.
203      *
204      * @param context The current state of the execution, including the SDK and HTTP request (potentially modified by other
205      * interceptors) to be sent to the downstream service.
206      * @param executionAttributes A mutable set of attributes scoped to one specific request/response cycle that can be used to
207      */
beforeTransmission(Context.BeforeTransmission context, ExecutionAttributes executionAttributes)208     default void beforeTransmission(Context.BeforeTransmission context, ExecutionAttributes executionAttributes) {
209 
210     }
211 
212     /**
213      * Read the HTTP response as it was returned by the HTTP client, before it is modified by other interceptors.
214      * {@link #beforeUnmarshalling} should be used in most circumstances for reading the HTTP response because it includes
215      * modifications made by other interceptors.
216      *
217      * <p>It is possible that the HTTP client could have already modified this response, so debug-level wire logging should be
218      * trusted over the parameters to this method.
219      *
220      * <p>Note: Unlike many other lifecycle methods, this one may be invoked multiple times. If the {@link RetryPolicy} determines
221      * the error code returned by the service is retriable, this will be invoked for each response returned by the service.
222      *
223      * @param context The current state of the execution, including the SDK and HTTP requests and the unmodified HTTP response.
224      * @param executionAttributes A mutable set of attributes scoped to one specific request/response cycle that can be used to
225      */
afterTransmission(Context.AfterTransmission context, ExecutionAttributes executionAttributes)226     default void afterTransmission(Context.AfterTransmission context, ExecutionAttributes executionAttributes) {
227     }
228 
229     /**
230      * Modify the {@link SdkHttpFullRequest} before it is unmarshalled into an {@link SdkResponse}.
231      *
232      * <p>Note: Unlike many other lifecycle methods, this one may be invoked multiple times. If the {@link RetryPolicy} determines
233      * the error code returned by the service is retriable, this will be invoked for each response returned by the service.
234      *
235      * @param context The current state of the execution, including the SDK and HTTP requests and the current HTTP response.
236      * @param executionAttributes A mutable set of attributes scoped to one specific request/response cycle that can be used to
237      * give data to future lifecycle methods.
238      * @return The potentially-modified HTTP response that should be given to the unmarshaller. Must not be null.
239      */
modifyHttpResponse(Context.ModifyHttpResponse context, ExecutionAttributes executionAttributes)240     default SdkHttpResponse modifyHttpResponse(Context.ModifyHttpResponse context,
241                                                ExecutionAttributes executionAttributes) {
242         return context.httpResponse();
243     }
244 
245     /**
246      * Modify the {@link SdkHttpFullRequest} before it is unmarshalled into an {@link SdkResponse}.
247      *
248      * <p>Note: Unlike many other lifecycle methods, this one may be invoked multiple times. If the {@link RetryPolicy} determines
249      * the error code returned by the service is retriable, this will be invoked for each response returned by the service.
250      *
251      * @param context The current state of the execution, including the SDK and HTTP requests and the current HTTP response.
252      * @param executionAttributes A mutable set of attributes scoped to one specific request/response cycle that can be used to
253      * give data to future lifecycle methods.
254      * @return The potentially-modified HTTP response that should be given to the unmarshaller. Must not be null.
255      */
modifyAsyncHttpResponseContent(Context.ModifyHttpResponse context, ExecutionAttributes executionAttributes)256     default Optional<Publisher<ByteBuffer>> modifyAsyncHttpResponseContent(Context.ModifyHttpResponse context,
257                                                                            ExecutionAttributes executionAttributes) {
258 
259         // get headers here
260         return context.responsePublisher();
261     }
262 
263     /**
264      * Modify the {@link SdkHttpFullRequest} before it is unmarshalled into an {@link SdkResponse}.
265      *
266      * <p>Note: Unlike many other lifecycle methods, this one may be invoked multiple times. If the {@link RetryPolicy} determines
267      * the error code returned by the service is retriable, this will be invoked for each response returned by the service.
268      *
269      * @param context The current state of the execution, including the SDK and HTTP requests and the current HTTP response.
270      * @param executionAttributes A mutable set of attributes scoped to one specific request/response cycle that can be used to
271      * give data to future lifecycle methods.
272      * @return The potentially-modified HTTP response that should be given to the unmarshaller. Must not be null.
273      */
modifyHttpResponseContent(Context.ModifyHttpResponse context, ExecutionAttributes executionAttributes)274     default Optional<InputStream> modifyHttpResponseContent(Context.ModifyHttpResponse context,
275                                                             ExecutionAttributes executionAttributes) {
276         return context.responseBody();
277     }
278 
279     /**
280      * Read the finalized HTTP response as it will be given to the unmarshaller to be converted into an {@link SdkResponse}.
281      *
282      * <p>Note: Unlike many other lifecycle methods, this one may be invoked multiple times. If the {@link RetryPolicy} determines
283      * the error code returned by the service is retriable, this will be invoked for each response returned by the service.
284      *
285      * @param context The current state of the execution, including the SDK and HTTP requests as well as the (potentially
286      * modified by other interceptors) HTTP response.
287      * @param executionAttributes A mutable set of attributes scoped to one specific request/response cycle that can be used to
288      * give data to future lifecycle methods.
289      */
beforeUnmarshalling(Context.BeforeUnmarshalling context, ExecutionAttributes executionAttributes)290     default void beforeUnmarshalling(Context.BeforeUnmarshalling context, ExecutionAttributes executionAttributes) {
291 
292     }
293 
294     /**
295      * Read the {@link SdkResponse} as it was returned by the unmarshaller, before it is modified by other interceptors.
296      * {@link #afterExecution} should be used in most circumstances for reading the SDK response because it includes
297      * modifications made by other interceptors.
298      *
299      * @param context The current state of the execution, including the SDK and HTTP requests and the HTTP response.
300      * @param executionAttributes A mutable set of attributes scoped to one specific request/response cycle that can be used to
301      * give data to future lifecycle methods.
302      */
afterUnmarshalling(Context.AfterUnmarshalling context, ExecutionAttributes executionAttributes)303     default void afterUnmarshalling(Context.AfterUnmarshalling context, ExecutionAttributes executionAttributes) {
304 
305     }
306 
307     /**
308      * Modify the {@link SdkResponse} before it is returned by the client.
309      *
310      * @param context The current state of the execution, including the SDK and HTTP requests as well as the SDK and HTTP
311      * response.
312      * @param executionAttributes A mutable set of attributes scoped to one specific request/response cycle that can be used to
313      * give data to future lifecycle methods.
314      * @return The potentially-modified SDK response that should be returned by the client. Must not be null.
315      */
modifyResponse(Context.ModifyResponse context, ExecutionAttributes executionAttributes)316     default SdkResponse modifyResponse(Context.ModifyResponse context, ExecutionAttributes executionAttributes) {
317         return context.response();
318     }
319 
320     /**
321      * Read the finalized {@link SdkResponse} as it will be returned by the client invocation.
322      *
323      * @param context The current state of the execution, including the SDK and HTTP requests as well as the SDK and HTTP
324      * response.
325      * @param executionAttributes A mutable set of attributes scoped to one specific request/response cycle that can be used to
326      * give data to future lifecycle methods.
327      */
afterExecution(Context.AfterExecution context, ExecutionAttributes executionAttributes)328     default void afterExecution(Context.AfterExecution context, ExecutionAttributes executionAttributes) {
329 
330     }
331 
332     /**
333      * Modify the exception before it is thrown.
334      *
335      * <p>This will only be invoked if the entire execution fails. If a retriable error happens (according to the
336      * {@link RetryPolicy}) and a subsequent retry succeeds, this method will not be invoked.
337      *
338      * @param context The context associated with the execution that failed. An SDK request will always be available, but
339      * depending on the time at which the failure happened, the HTTP request, HTTP response and SDK response may
340      * not be available. This also includes the exception that triggered the failure.
341      * @param executionAttributes A mutable set of attributes scoped to one specific request/response cycle that can be used to
342      * give data to future lifecycle methods.
343      * @return the modified Exception
344      */
modifyException(Context.FailedExecution context, ExecutionAttributes executionAttributes)345     default Throwable modifyException(Context.FailedExecution context, ExecutionAttributes executionAttributes) {
346         return context.exception();
347     }
348 
349     /**
350      * Invoked when any error happens during an execution that prevents the request from succeeding. This could be due to an
351      * error returned by a service call, a request timeout or even another interceptor raising an exception. The provided
352      * exception will be thrown by the service client.
353      *
354      * <p>This will only be invoked if the entire execution fails. If a retriable error happens (according to the
355      * {@link RetryPolicy}) and a subsequent retry succeeds, this method will not be invoked.
356      *
357      * @param context The context associated with the execution that failed. An SDK request will always be available, but
358      * depending on the time at which the failure happened, the HTTP request, HTTP response and SDK response may
359      * not be available. This also includes the exception that triggered the failure.
360      * @param executionAttributes A mutable set of attributes scoped to one specific request/response cycle that can be used to
361      * give data to future lifecycle methods.
362      */
onExecutionFailure(Context.FailedExecution context, ExecutionAttributes executionAttributes)363     default void onExecutionFailure(Context.FailedExecution context, ExecutionAttributes executionAttributes) {
364 
365     }
366 }
367