@Override
    public void sign(SignableRequest<?> request, AWSCredentials credentials) {

        if (resourcePath == null) {
            throw new UnsupportedOperationException(
                    "Cannot sign a request using a dummy S3Signer instance with "
                            + "no resource path");
        }

        if (credentials == null || credentials.getAWSSecretKey() == null) {
            log.debug("Canonical string will not be signed, as no AWS Secret Key was provided");
            return;
        }

        AWSCredentials sanitizedCredentials = sanitizeCredentials(credentials);
        if (sanitizedCredentials instanceof AWSSessionCredentials) {
            addSessionCredentials(request,
                    (AWSSessionCredentials) sanitizedCredentials);
        }

        /*
         * In s3 sigv2, the way slash characters are encoded should be
         * consistent in both the request url and the encoded resource path.
         * Since we have to encode "//" to "/%2F" in the request url to make
         * httpclient works, we need to do the same encoding here for the
         * resource path.
         */
        String encodedResourcePath = SdkHttpUtils.appendUri(
                request.getEndpoint().getPath(), SdkHttpUtils.urlEncode(resourcePath, true),
                true);

        int timeOffset = request.getTimeOffset();
        Date date = getSignatureDate(timeOffset);
        request.addHeader(Headers.DATE, ServiceUtils.formatRfc822Date(date));
        String canonicalString = RestUtils.makeS3CanonicalString(httpVerb,
                encodedResourcePath, request, null, additionalQueryParamsToSign);
        log.debug("Calculated string to sign:\n\"" + canonicalString + "\"");

        String signature = super.signAndBase64Encode(canonicalString,
                sanitizedCredentials.getAWSSecretKey(),
                SigningAlgorithm.HmacSHA1);
        request.addHeader("Authorization",
                "AWS " + sanitizedCredentials.getAWSAccessKeyId() + ":"
                        + signature);
    }
Constructs a new S3Signer to sign requests based on the Amazon Web Services credentials,
HTTP method and canonical S3 resource path.

@param httpVerb
           The HTTP verb (GET, PUT, POST, HEAD, DELETE) the request is
           using.
@param resourcePath
           The canonical S3 resource path (ex: "/", "/<bucket name>/", or
           "/<bucket name>/<key>".
@param additionalQueryParamsToSign
           A collection of user-specified query parameters that should be
           included in the canonical request, in addition to those
           default parameters that are always signed.

@see RestUtils#makeS3CanonicalString(String, String, Request, String)
aws-java-sdk-s3/src/main/java/com/amazonaws/services/s3/internal/S3Signer.java