1 /*
2 * Copyright 2010-2020 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 package com.amazonaws;
16
17 import com.amazonaws.annotation.NotThreadSafe;
18 import com.amazonaws.annotation.SdkInternalApi;
19 import com.amazonaws.auth.AWSCredentials;
20 import com.amazonaws.auth.AWSCredentialsProvider;
21 import com.amazonaws.event.ProgressListener;
22 import com.amazonaws.handlers.HandlerContextKey;
23 import com.amazonaws.internal.StaticCredentialsProvider;
24 import com.amazonaws.metrics.RequestMetricCollector;
25 import java.util.Collections;
26 import java.util.HashMap;
27 import java.util.LinkedList;
28 import java.util.List;
29 import java.util.Map;
30
31 /**
32 * Base class for all user facing web service requests.
33 */
34 @NotThreadSafe
35 public abstract class AmazonWebServiceRequest implements Cloneable, ReadLimitInfo, HandlerContextAware {
36
37 public static final AmazonWebServiceRequest NOOP = new AmazonWebServiceRequest() {
38 };
39
40 /**
41 * The optional progress listener for receiving updates about the progress of the request.
42 */
43 private ProgressListener progressListener = ProgressListener.NOOP;
44
45 /**
46 * Arbitrary options storage for individual {@link AmazonWebServiceRequest}s. This field is not
47 * intended to be used by clients.
48 */
49 private final RequestClientOptions requestClientOptions = new RequestClientOptions();
50
51 /**
52 * A request metric collector used for this specific service request; or null if there is none.
53 * This collector always takes precedence over the ones specified at the http client level and
54 * AWS SDK level.
55 */
56 private RequestMetricCollector requestMetricCollector;
57
58 /**
59 * The optional credentials to use for this request - overrides the default credentials set at
60 * the client level.
61 */
62 private AWSCredentialsProvider credentialsProvider;
63
64 /**
65 * A map of custom header names to header values.
66 */
67 private Map<String, String> customRequestHeaders;
68
69 /**
70 * Custom query parameters for the request.
71 */
72 private Map<String, List<String>> customQueryParameters;
73
74 /**
75 * User-defined context for the request.
76 */
77 private transient Map<HandlerContextKey<?>, Object> handlerContext = new HashMap<HandlerContextKey<?>, Object>();
78
79 /**
80 * The source object from which the current object was cloned; or null if there isn't one.
81 */
82 private AmazonWebServiceRequest cloneSource;
83
84 private Integer sdkRequestTimeout = null;
85
86 private Integer sdkClientExecutionTimeout = null;
87
88 /**
89 * Sets the optional credentials to use for this request, overriding the default credentials set at the client level.
90 *
91 * @param credentials The optional AWS security credentials to use for this request, overriding the default credentials set at
92 * the client level.
93 * @deprecated by {@link #setRequestCredentialsProvider(AWSCredentialsProvider)}. If you must use {@link AWSCredentials} you
94 * can wrap it with a {@link com.amazonaws.auth.AWSStaticCredentialsProvider}.
95 */
96 @Deprecated
97 public void setRequestCredentials(AWSCredentials credentials) {
98 this.credentialsProvider = credentials == null ? null : new StaticCredentialsProvider(credentials);
99 }
100
101 /**
102 * Returns the optional credentials to use to sign this request, overriding the default
103 * credentials set at the client level.
104 *
105 * @return The optional credentials to use to sign this request, overriding the default
106 * credentials set at the client level.
107 *
108 * @deprecated by {@link #getRequestCredentialsProvider()}
109 */
110 @Deprecated
111 public AWSCredentials getRequestCredentials() {
112 return credentialsProvider == null ? null : credentialsProvider.getCredentials();
113 }
114
115 /**
116 * Sets the optional credentials provider to use for this request, overriding the default credentials
117 * provider at the client level.
118 *
119 * @param credentialsProvider
120 * The optional AWS security credentials provider to use for this request, overriding the
121 * default credentials provider at the client level.
122 */
123 public void setRequestCredentialsProvider(AWSCredentialsProvider credentialsProvider) {
124 this.credentialsProvider = credentialsProvider;
125 }
126
127 /**
128 * Returns the optional credentials provider to use to sign this request, overriding the default
129 * credentials provider at the client level.
130 *
131 * @return The optional credentials provider to use to sign this request, overriding the default
132 * credentials provider at the client level.
133 */
134 public AWSCredentialsProvider getRequestCredentialsProvider() {
135 return credentialsProvider;
136 }
137
138 /**
139 * Sets the optional credentials provider to use for this request, overriding the default credentials
140 * provider at the client level.
141 *
142 * @param credentialsProvider
143 * The optional AWS security credentials provider to use for this request, overriding the
144 * default credentials provider at the client level.
145 * @return A reference to this updated object so that method calls can be chained together.
146 */
147 public <T extends AmazonWebServiceRequest> T withRequestCredentialsProvider(final AWSCredentialsProvider credentialsProvider) {
148 setRequestCredentialsProvider(credentialsProvider);
149 @SuppressWarnings("unchecked")
150 T t = (T) this;
151 return t;
152 }
153
154 /**
155 * Gets the options stored with this request object. Intended for internal use only.
156 */
157 public RequestClientOptions getRequestClientOptions() {
158 return requestClientOptions;
159 }
160
161 /**
162 * Returns a request level metric collector; or null if not specified.
163 */
164 public RequestMetricCollector getRequestMetricCollector() {
165 return requestMetricCollector;
166 }
167
168 /**
169 * Sets a request level request metric collector which takes precedence over the ones at the
170 * http client level and AWS SDK level.
171 */
172 public void setRequestMetricCollector(RequestMetricCollector requestMetricCollector) {
173 this.requestMetricCollector = requestMetricCollector;
174 }
175
176 /**
177 * Specifies a request level metric collector which takes precedence over the ones at the http
178 * client level and AWS SDK level.
179 */
180 public <T extends AmazonWebServiceRequest> T withRequestMetricCollector(RequestMetricCollector metricCollector) {
181 setRequestMetricCollector(metricCollector);
182 @SuppressWarnings("unchecked")
183 T t = (T) this;
184 return t;
185 }
186
187 /**
188 * Sets the optional progress listener for receiving updates about the progress of the request.
189 *
190 * @param progressListener
191 * The new progress listener.
192 */
193 public void setGeneralProgressListener(ProgressListener progressListener) {
194 this.progressListener = progressListener == null ? ProgressListener.NOOP : progressListener;
195 }
196
197 /**
198 * Returns the optional progress listener for receiving updates about the progress of the
199 * request.
200 *
201 * @return the optional progress listener for receiving updates about the progress of the
202 * request.
203 */
204 public ProgressListener getGeneralProgressListener() {
205 return progressListener;
206 }
207
208 /**
209 * Sets the optional progress listener for receiving updates about the progress of the request,
210 * and returns a reference to this object so that method calls can be chained together.
211 *
212 * @param progressListener
213 * The new progress listener.
214 * @return A reference to this updated object so that method calls can be chained together.
215 */
216 public <T extends AmazonWebServiceRequest> T withGeneralProgressListener(ProgressListener progressListener) {
217 setGeneralProgressListener(progressListener);
218 @SuppressWarnings("unchecked")
219 T t = (T) this;
220 return t;
221 }
222
223 /**
224 * Returns an immutable map of custom header names to header values.
225 *
226 * @return The immutable map of custom header names to header values.
227 */
228 public Map<String, String> getCustomRequestHeaders() {
229 if (customRequestHeaders == null) {
230 return null;
231 }
232 return Collections.unmodifiableMap(customRequestHeaders);
233 }
234
235 /**
236 * Put a new custom header to the map of custom header names to custom header values, and return
237 * the previous value if the header has already been set in this map.
238 * <p>
239 * Any custom headers that are defined are used in the HTTP request to the AWS service. These
240 * headers will be silently ignored in the event that AWS does not recognize them.
241 * <p>
242 * NOTE: Custom header values set via this method will overwrite any conflicting values coming
243 * from the request parameters.
244 *
245 * @param name
246 * The name of the header to add
247 * @param value
248 * The value of the header to add
249 * @return the previous value for the name if it was set, null otherwise
250 */
251 public String putCustomRequestHeader(String name, String value) {
252 if (customRequestHeaders == null) {
253 customRequestHeaders = new HashMap<String, String>();
254 }
255 return customRequestHeaders.put(name, value);
256 }
257
258 /**
259 * @return the immutable map of custom query parameters. The parameter value is modeled as a
260 * list of strings because multiple values can be specified for the same parameter name.
261 */
262 public Map<String, List<String>> getCustomQueryParameters() {
263 if (customQueryParameters == null) {
264 return null;
265 }
266 return Collections.unmodifiableMap(customQueryParameters);
267 }
268
269 /**
270 * Add a custom query parameter for the request. Since multiple values are allowed for the same
271 * query parameter, this method does NOT overwrite any existing parameter values in the request.
272 * <p>
273 * Any custom query parameters that are defined are used in the HTTP request to the AWS service.
274 *
275 * @param name
276 * The name of the query parameter
277 * @param value
278 * The value of the query parameter. Only the parameter name will be added in the URI
279 * if the value is set to null. For example, putCustomQueryParameter("param", null)
280 * will be serialized to "?param", while putCustomQueryParameter("param", "") will be
281 * serialized to "?param=".
282 */
283 public void putCustomQueryParameter(String name, String value) {
284 if (customQueryParameters == null) {
285 customQueryParameters = new HashMap<String, List<String>>();
286 }
287 List<String> paramList = customQueryParameters.get(name);
288 if (paramList == null) {
289 paramList = new LinkedList<String>();
290 customQueryParameters.put(name, paramList);
291 }
292 paramList.add(value);
293 }
294
295 @Override
296 public final int getReadLimit() {
297 return requestClientOptions.getReadLimit();
298 }
299
300 /**
301 * Copies the internal state of this base class to that of the target request.
302 *
303 * @return the target request
304 */
305 protected final <T extends AmazonWebServiceRequest> T copyBaseTo(T target) {
306 if (customRequestHeaders != null) {
307 for (Map.Entry<String, String> e : customRequestHeaders.entrySet())
308 target.putCustomRequestHeader(e.getKey(), e.getValue());
309 }
310 if (customQueryParameters != null) {
311 for (Map.Entry<String, List<String>> e : customQueryParameters.entrySet()) {
312 if (e.getValue() != null) {
313 for (String value : e.getValue()) {
314 target.putCustomQueryParameter(e.getKey(), value);
315 }
316 }
317 }
318 }
319
320 target.setRequestCredentialsProvider(credentialsProvider);
321 target.setGeneralProgressListener(progressListener);
322 target.setRequestMetricCollector(requestMetricCollector);
323 requestClientOptions.copyTo(target.getRequestClientOptions());
324 return target;
325 }
326
327 /**
328 * Returns the source object from which the current object was cloned; or null if there isn't
329 * one.
330 */
331 public AmazonWebServiceRequest getCloneSource() {
332 return cloneSource;
333 }
334
335 /**
336 * Returns the root object from which the current object was cloned; or null if there isn't one.
337 */
338 public AmazonWebServiceRequest getCloneRoot() {
339 AmazonWebServiceRequest cloneRoot = cloneSource;
340 if (cloneRoot != null) {
341 while (cloneRoot.getCloneSource() != null) {
342 cloneRoot = cloneRoot.getCloneSource();
343 }
344 }
345 return cloneRoot;
346 }
347
348 private void setCloneSource(AmazonWebServiceRequest cloneSource) {
349 this.cloneSource = cloneSource;
350 }
351
352 /**
353 * Returns the amount of time to wait (in milliseconds) for the request to complete before
354 * giving up and timing out. A non-positive value disables this feature.
355 * <p>
356 * This feature requires buffering the entire response (for non-streaming APIs) into memory to
357 * enforce a hard timeout when reading the response. For APIs that return large responses this
358 * could be expensive.
359 * <p>
360 * <p>
361 * The request timeout feature doesn't have strict guarantees on how quickly a request is
362 * aborted when the timeout is breached. The typical case aborts the request within a few
363 * milliseconds but there may occasionally be requests that don't get aborted until several
364 * seconds after the timer has been breached. Because of this the request timeout feature should
365 * not be used when absolute precision is needed.
366 * </p>
367 * <p>
368 * <b>Note:</b> This feature is not compatible with Java 1.6.
369 * </p>
370 *
371 * @return The amount of time to wait (in milliseconds) for the request to complete before
372 * giving up and timing out. A non-positive value disables the timeout for this request.
373 * @see {@link AmazonWebServiceRequest#setSdkClientExecutionTimeout(int)} to enforce a timeout
374 * across all retries
375 */
376 public Integer getSdkRequestTimeout() {
377 return sdkRequestTimeout;
378 }
379
380 /**
381 * Sets the amount of time to wait (in milliseconds) for the request to complete before giving
382 * up and timing out. A non-positive value disables this feature.
383 * <p>
384 * This feature requires buffering the entire response (for non-streaming APIs) into memory to
385 * enforce a hard timeout when reading the response. For APIs that return large responses this
386 * could be expensive.
387 * <p>
388 * <p>
389 * The request timeout feature doesn't have strict guarantees on how quickly a request is
390 * aborted when the timeout is breached. The typical case aborts the request within a few
391 * milliseconds but there may occasionally be requests that don't get aborted until several
392 * seconds after the timer has been breached. Because of this the request timeout feature should
393 * not be used when absolute precision is needed.
394 * </p>
395 * <p>
396 * <b>Note:</b> This feature is not compatible with Java 1.6.
397 * </p>
398 *
399 * @param sdkRequestTimeout
400 * The amount of time to wait (in milliseconds) for the request to complete before
401 * giving up and timing out. A non-positive value disables the timeout for this
402 * request.
403 * @see {@link AmazonWebServiceRequest#setSdkClientExecutionTimeout(int)} to enforce a timeout
404 * across all retries
405 */
406 public void setSdkRequestTimeout(int sdkRequestTimeout) {
407 this.sdkRequestTimeout = sdkRequestTimeout;
408 }
409
410 /**
411 * Sets the amount of time to wait (in milliseconds) for the request to complete before giving
412 * up and timing out. A non-positive value disables this feature. Returns the updated
413 * AmazonWebServiceRequest object so that additional method calls may be chained together.
414 * <p>
415 * This feature requires buffering the entire response (for non-streaming APIs) into memory to
416 * enforce a hard timeout when reading the response. For APIs that return large responses this
417 * could be expensive.
418 * <p>
419 * <p>
420 * The request timeout feature doesn't have strict guarantees on how quickly a request is
421 * aborted when the timeout is breached. The typical case aborts the request within a few
422 * milliseconds but there may occasionally be requests that don't get aborted until several
423 * seconds after the timer has been breached. Because of this the request timeout feature should
424 * not be used when absolute precision is needed.
425 * </p>
426 * <p>
427 * <b>Note:</b> This feature is not compatible with Java 1.6.
428 * </p>
429 *
430 * @param sdkRequestTimeout
431 * The amount of time to wait (in milliseconds) for the request to complete before
432 * giving up and timing out. A non-positive value disables the timeout for this
433 * request.
434 * @return The updated {@link AmazonWebServiceRequest} object.
435 * @see {@link AmazonWebServiceRequest#setSdkClientExecutionTimeout(int)} to enforce a timeout
436 * across all retries
437 */
438 public <T extends AmazonWebServiceRequest> T withSdkRequestTimeout(int sdkRequestTimeout) {
439 setSdkRequestTimeout(sdkRequestTimeout);
440 @SuppressWarnings("unchecked")
441 T t = (T) this;
442 return t;
443 }
444
445 /**
446 * Returns the amount of time (in milliseconds) to allow the client to complete the execution of
447 * an API call. This timeout covers the entire client execution except for marshalling. This
448 * includes request handler execution, all HTTP request including retries, unmarshalling, etc.
449 * <p>
450 * This feature requires buffering the entire response (for non-streaming APIs) into memory to
451 * enforce a hard timeout when reading the response. For APIs that return large responses this
452 * could be expensive.
453 * <p>
454 * <p>
455 * The client execution timeout feature doesn't have strict guarantees on how quickly a request
456 * is aborted when the timeout is breached. The typical case aborts the request within a few
457 * milliseconds but there may occasionally be requests that don't get aborted until several
458 * seconds after the timer has been breached. Because of this the client execution timeout
459 * feature should not be used when absolute precision is needed.
460 * </p>
461 * <p>
462 * This may be used together with {@link AmazonWebServiceRequest#setSdkRequestTimeout(int)} to
463 * enforce both a timeout on each individual HTTP request (i.e. each retry) and the total time
464 * spent on all requests across retries (i.e. the 'client execution' time). A non-positive value
465 * disables this feature.
466 * </p>
467 * <p>
468 * <b>Note:</b> This feature is not compatible with Java 1.6.
469 * </p>
470 *
471 * @return The amount of time (in milliseconds) to allow the client to complete the execution of
472 * an API call. A non-positive value disables the timeout for this request.
473 * @see {@link AmazonWebServiceRequest#setSdkRequestTimeout(int)} to enforce a timeout per HTTP
474 * request
475 */
476 public Integer getSdkClientExecutionTimeout() {
477 return this.sdkClientExecutionTimeout;
478 }
479
480 /**
481 * Sets the amount of time (in milliseconds) to allow the client to complete the execution of
482 * an API call. This timeout covers the entire client execution except for marshalling. This
483 * includes request handler execution, all HTTP request including retries, unmarshalling, etc.
484 * <p>
485 * This feature requires buffering the entire response (for non-streaming APIs) into memory to
486 * enforce a hard timeout when reading the response. For APIs that return large responses this
487 * could be expensive.
488 * <p>
489 * <p>
490 * The client execution timeout feature doesn't have strict guarantees on how quickly a request
491 * is aborted when the timeout is breached. The typical case aborts the request within a few
492 * milliseconds but there may occasionally be requests that don't get aborted until several
493 * seconds after the timer has been breached. Because of this the client execution timeout
494 * feature should not be used when absolute precision is needed.
495 * </p>
496 * <p>
497 * This may be used together with {@link AmazonWebServiceRequest#setSdkRequestTimeout(int)} to
498 * enforce both a timeout on each individual HTTP request (i.e. each retry) and the total time
499 * spent on all requests across retries (i.e. the 'client execution' time). A non-positive value
500 * disables this feature.
501 * </p>
502 * <p>
503 * <b>Note:</b> This feature is not compatible with Java 1.6.
504 * </p>
505 *
506 * @param sdkClientExecutionTimeout
507 * The amount of time (in milliseconds) to allow the client to complete the execution
508 * of an API call. A non-positive value disables the timeout for this request.
509 * @see {@link AmazonWebServiceRequest#setSdkRequestTimeout(int)} to enforce a timeout per HTTP
510 * request
511 */
512 public void setSdkClientExecutionTimeout(int sdkClientExecutionTimeout) {
513 this.sdkClientExecutionTimeout = sdkClientExecutionTimeout;
514 }
515
516 /**
517 * Sets the amount of time (in milliseconds) to allow the client to complete the execution of
518 * an API call. This timeout covers the entire client execution except for marshalling. This
519 * includes request handler execution, all HTTP request including retries, unmarshalling, etc.
520 * <p>
521 * This feature requires buffering the entire response (for non-streaming APIs) into memory to
522 * enforce a hard timeout when reading the response. For APIs that return large responses this
523 * could be expensive.
524 * <p>
525 * <p>
526 * The client execution timeout feature doesn't have strict guarantees on how quickly a request
527 * is aborted when the timeout is breached. The typical case aborts the request within a few
528 * milliseconds but there may occasionally be requests that don't get aborted until several
529 * seconds after the timer has been breached. Because of this the client execution timeout
530 * feature should not be used when absolute precision is needed.
531 * </p>
532 * <p>
533 * This may be used together with {@link AmazonWebServiceRequest#setSdkRequestTimeout(int)} to
534 * enforce both a timeout on each individual HTTP request (i.e. each retry) and the total time
535 * spent on all requests across retries (i.e. the 'client execution' time). A non-positive value
536 * disables this feature.
537 * </p>
538 * <p>
539 * <b>Note:</b> This feature is not compatible with Java 1.6.
540 * </p>
541 *
542 * @param sdkClientExecutionTimeout
543 * The amount of time (in milliseconds) to allow the client to complete the execution
544 * of an API call. A non-positive value disables the timeout for this request.
545 * @return The updated AmazonWebServiceRequest object for method chaining
546 * @see {@link AmazonWebServiceRequest#setSdkRequestTimeout(int)} to enforce a timeout per HTTP
547 * request
548 */
549 public <T extends AmazonWebServiceRequest> T withSdkClientExecutionTimeout(int sdkClientExecutionTimeout) {
550 setSdkClientExecutionTimeout(sdkClientExecutionTimeout);
551 @SuppressWarnings("unchecked")
552 T t = (T) this;
553 return t;
554 }
555
556 @Override
557 public <X> void addHandlerContext(HandlerContextKey<X> key, X value) {
558 this.handlerContext.put(key, value);
559 }
560
561 @Override
562 @SuppressWarnings("unchecked")
563 public <X> X getHandlerContext(HandlerContextKey<X> key) {
564 return (X) this.handlerContext.get(key);
565 }
566
567 /**
568 * Retrieve an unmodifiable collection of all handler context objects. This allows a {@link Request} derived from a
569 * {@link AmazonWebServiceRequest} to inherit its context. This does not protect the objects within the map from being
570 * modified.
571 *
572 * <p>This should not be used by customers.</p>
573 */
574 @SdkInternalApi
575 Map<HandlerContextKey<?>, Object> getHandlerContext() {
576 return Collections.unmodifiableMap(this.handlerContext);
577 }
578
579 /**
580 * Creates a shallow clone of this object for all fields except the handler context. Explicitly does <em>not</em> clone the
581 * deep structure of the other fields in the message.
582 *
583 * @see Object#clone()
584 */
585 @Override
586 public AmazonWebServiceRequest clone() {
587 try {
588 AmazonWebServiceRequest cloned = (AmazonWebServiceRequest) super.clone();
589 cloned.setCloneSource(this);
590
591 // Deep-copy context to ensure modifications made by the handlers do not leak back to the caller or other uses of the
592 // same request.
593 cloned.handlerContext = new HashMap<HandlerContextKey<?>, Object>(cloned.handlerContext);
594
595 return cloned;
596 } catch (CloneNotSupportedException e) {
597 throw new IllegalStateException(
598 "Got a CloneNotSupportedException from Object.clone() " + "even though we're Cloneable!", e);
599 }
600 }
601 }
602