All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.amazonaws.internal.SdkRequestRetryHeaderProvider Maven / Gradle / Ivy

Go to download

The AWS SDK for Java - Core module holds the classes that are used by the individual service clients to interact with Amazon Web Services. Users need to depend on aws-java-sdk artifact for accessing individual client classes.

There is a newer version: 1.12.778
Show newest version
/*
 * Copyright 2019-2024 Amazon.com, Inc. or its affiliates. All Rights Reserved.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at:
 *
 *    http://aws.amazon.com/apache2.0
 *
 * This file is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES
 * OR CONDITIONS OF ANY KIND, either express or implied. See the
 * License for the specific language governing permissions and
 * limitations under the License.
 */

package com.amazonaws.internal;

import com.amazonaws.ClientConfiguration;
import com.amazonaws.Request;
import com.amazonaws.annotation.SdkInternalApi;
import com.amazonaws.annotation.ThreadSafe;
import com.amazonaws.auth.SdkClock;
import com.amazonaws.auth.internal.AWS4SignerUtils;
import com.amazonaws.handlers.HandlerContextKey;
import com.amazonaws.retry.ClockSkewAdjuster;
import com.amazonaws.retry.RetryPolicyAdapter;
import com.amazonaws.retry.v2.RetryPolicy;
import java.util.ArrayList;
import java.util.List;

/**
 * Provides SDK request header "amz-sdk-request"
 */
@ThreadSafe
@SdkInternalApi
public final class SdkRequestRetryHeaderProvider {
    private static final String SDK_REQUEST_RETRY_HEADER = "amz-sdk-request";
    private final ClientConfiguration config;
    private final Integer maxErrorRetry;
    private final ClockSkewAdjuster clockSkewAdjuster;

    public SdkRequestRetryHeaderProvider(ClientConfiguration config,
                                         RetryPolicy retryPolicy,
                                         ClockSkewAdjuster clockSkewAdjuster) {
        this.config = config;
        if (retryPolicy instanceof RetryPolicyAdapter) {
            maxErrorRetry = ((RetryPolicyAdapter) retryPolicy).getMaxErrorRetry() + 1;
        } else {
            maxErrorRetry = null;
        }
        this.clockSkewAdjuster = clockSkewAdjuster;
    }

    public void addSdkRequestRetryHeader(Request request, int attemptNum) {
        List pairs = requestPairs(request, String.valueOf(attemptNum));

        StringBuilder headerValue = new StringBuilder();
        for (Pair pair: pairs) {
            headerValue.append(pair.name).append("=").append(pair.value).append(";");
        }

        String header = headerValue.toString().substring(0, headerValue.length() - 1);
        request.addHeader(SDK_REQUEST_RETRY_HEADER, header);
    }

    private List requestPairs(Request request, String attemptNum) {
        List requestPairs = new ArrayList();

        String optionalTtl = calculateTtl(request);
        if (optionalTtl != null) {
            requestPairs.add(new Pair("ttl", optionalTtl));
        }

        requestPairs.add(new Pair("attempt", attemptNum));

        if (maxErrorRetry != null) {
            requestPairs.add(new Pair("max", String.valueOf(maxErrorRetry)));
        }

        return requestPairs;
    }

    /**
     * Calculate the ttl and format it:
     *
     * ttl = current_time + socket_read_timeout + estimated_skew
     * estimated_skew_i = timeStampFromDateHeader_i-1 - timeClientReceivedResposne_i-1
     */
    private String calculateTtl(Request request) {
        // ttl should be omitted for streaming operations
        if (isStreaming(request)) {
            return null;
        }

        Integer estimatedSkew = clockSkewAdjuster.getEstimatedSkew();
        // Calculating this value requires that we've seen at least one response from the service s
        // o the ttl SHOULD be omitted for the initial request.
        if (estimatedSkew == null) {
            return null;
        }

        long currentTimeMillis = SdkClock.Instance.get().currentTimeMillis();

        // The returned estimatedSkew is derived from (responseTime - clientTime), so -estimatedSkew = clientTime - responseTime
        long ttl = currentTimeMillis + config.getSocketTimeout() - estimatedSkew * 1000;

        return AWS4SignerUtils.formatTimestamp(ttl);
    }

    private boolean isStreaming(Request request) {
        return Boolean.TRUE.equals(request.getHandlerContext(HandlerContextKey.HAS_STREAMING_INPUT)) ||
               Boolean.TRUE.equals(request.getHandlerContext(HandlerContextKey.HAS_STREAMING_OUTPUT));
    }

    private static final class Pair {
        private String name;
        private String value;

        Pair(String name, String value) {
            this.name = name;
            this.value = value;
        }
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy