checksumming = new CompletableFuture<>();
diff --git a/core/http-auth-aws/src/main/java/software/amazon/awssdk/http/auth/aws/internal/signer/DefaultV4RequestSigner.java b/core/http-auth-aws/src/main/java/software/amazon/awssdk/http/auth/aws/internal/signer/DefaultV4RequestSigner.java
index d4763301855a..7e1a2850ccd4 100644
--- a/core/http-auth-aws/src/main/java/software/amazon/awssdk/http/auth/aws/internal/signer/DefaultV4RequestSigner.java
+++ b/core/http-auth-aws/src/main/java/software/amazon/awssdk/http/auth/aws/internal/signer/DefaultV4RequestSigner.java
@@ -32,6 +32,14 @@
import software.amazon.awssdk.utils.BinaryUtils;
import software.amazon.awssdk.utils.Logger;
+/**
+ * The default implementation of a v4-request-signer. It performs each step of the SigV4 signing process, but does not add the
+ * signature or auth information to the request itself.
+ *
+ * All signing information, such as signature, signing key, canonical request, etc. is present in context object that is
+ * returned. This can be used by the caller to add the auth info to the request, such as adding the signature as a query
+ * parameter or building an authorization header using the signature and canonical request headers.
+ */
@SdkInternalApi
public final class DefaultV4RequestSigner implements V4RequestSigner {
diff --git a/core/http-auth-aws/src/main/java/software/amazon/awssdk/http/auth/aws/internal/signer/FlexibleChecksummer.java b/core/http-auth-aws/src/main/java/software/amazon/awssdk/http/auth/aws/internal/signer/FlexibleChecksummer.java
index a7b2f56ea636..fac0b56f6d40 100644
--- a/core/http-auth-aws/src/main/java/software/amazon/awssdk/http/auth/aws/internal/signer/FlexibleChecksummer.java
+++ b/core/http-auth-aws/src/main/java/software/amazon/awssdk/http/auth/aws/internal/signer/FlexibleChecksummer.java
@@ -35,7 +35,9 @@
import software.amazon.awssdk.http.auth.aws.signer.Checksummer;
/**
- * A "flexible" implementation of a checksummer.
+ * A "flexible" implementation of a checksummer. It takes a map of checksums and their header names, computes them efficiently
+ * by updating each checksum while reading the payload (once), and adds the computed checksum strings to the request using the
+ * given header names in the map. This should be used in cases where a (flexible) checksum algorithm is present during signing.
*/
@SdkInternalApi
public final class FlexibleChecksummer implements Checksummer {
diff --git a/core/http-auth-aws/src/main/java/software/amazon/awssdk/http/auth/aws/internal/signer/PrecomputedChecksummer.java b/core/http-auth-aws/src/main/java/software/amazon/awssdk/http/auth/aws/internal/signer/PrecomputedChecksummer.java
index e9adb3459f86..7a5fbb153ae8 100644
--- a/core/http-auth-aws/src/main/java/software/amazon/awssdk/http/auth/aws/internal/signer/PrecomputedChecksummer.java
+++ b/core/http-auth-aws/src/main/java/software/amazon/awssdk/http/auth/aws/internal/signer/PrecomputedChecksummer.java
@@ -28,8 +28,8 @@
/**
* An implementation of a checksummer that simply passes along a computed value as a checksum. Specifically, this is used in
- * the cases where the checksum is a pre-defined value that dictates specific behavior by the signer (such as aws-chunked
- * payload signing, unsigned streaming with trailers, etc.).
+ * the cases where the checksum is a pre-defined value that dictates specific behavior by the signer, and flexible checksums is
+ * not enabled for the request (such as aws-chunked payload signing without trailers, unsigned streaming without trailers, etc.).
*/
@SdkInternalApi
public final class PrecomputedChecksummer implements Checksummer {
diff --git a/core/http-auth-aws/src/main/java/software/amazon/awssdk/http/auth/aws/internal/util/ChecksumUtil.java b/core/http-auth-aws/src/main/java/software/amazon/awssdk/http/auth/aws/internal/util/ChecksumUtil.java
index c6e542b22f68..e96b6b69e18c 100644
--- a/core/http-auth-aws/src/main/java/software/amazon/awssdk/http/auth/aws/internal/util/ChecksumUtil.java
+++ b/core/http-auth-aws/src/main/java/software/amazon/awssdk/http/auth/aws/internal/util/ChecksumUtil.java
@@ -17,6 +17,7 @@
import static software.amazon.awssdk.checksums.DefaultChecksumAlgorithm.CRC32;
import static software.amazon.awssdk.checksums.DefaultChecksumAlgorithm.CRC32C;
+import static software.amazon.awssdk.checksums.DefaultChecksumAlgorithm.MD5;
import static software.amazon.awssdk.checksums.DefaultChecksumAlgorithm.SHA1;
import static software.amazon.awssdk.checksums.DefaultChecksumAlgorithm.SHA256;
@@ -27,6 +28,7 @@
import software.amazon.awssdk.http.auth.aws.internal.checksums.ConstantChecksum;
import software.amazon.awssdk.http.auth.aws.internal.checksums.Crc32CChecksum;
import software.amazon.awssdk.http.auth.aws.internal.checksums.Crc32Checksum;
+import software.amazon.awssdk.http.auth.aws.internal.checksums.Md5Checksum;
import software.amazon.awssdk.http.auth.aws.internal.checksums.SdkChecksum;
import software.amazon.awssdk.http.auth.aws.internal.checksums.Sha1Checksum;
import software.amazon.awssdk.http.auth.aws.internal.checksums.Sha256Checksum;
@@ -51,11 +53,7 @@ public static String checksumHeaderName(ChecksumAlgorithm checksumAlgorithm) {
}
/**
- * Gets the SdkChecksum object based on the given ChecksumAlgorithm. Instances for CRC32C, CRC32 Algorithm will be added from
- * CRT Java library once they are available in release.
- *
- * @param checksumAlgorithm Algorithm for calculating the checksum
- * @return an SdkChecksum instance.
+ * Gets the SdkChecksum object based on the given ChecksumAlgorithm.
*/
public static SdkChecksum fromChecksumAlgorithm(ChecksumAlgorithm checksumAlgorithm) {
if (SHA256.algorithmId().equals(checksumAlgorithm.algorithmId())) {
@@ -74,6 +72,10 @@ public static SdkChecksum fromChecksumAlgorithm(ChecksumAlgorithm checksumAlgori
return new Crc32CChecksum();
}
+ if (MD5.algorithmId().equals(checksumAlgorithm.algorithmId())) {
+ return new Md5Checksum();
+ }
+
if (CONSTANT_CHECKSUM.equals(checksumAlgorithm.algorithmId())) {
return new ConstantChecksum(((ConstantChecksumAlgorithm) checksumAlgorithm).value);
}
diff --git a/core/http-auth-aws/src/main/java/software/amazon/awssdk/http/auth/aws/signer/Checksummer.java b/core/http-auth-aws/src/main/java/software/amazon/awssdk/http/auth/aws/signer/Checksummer.java
index c7baa06176bc..60531c93fecc 100644
--- a/core/http-auth-aws/src/main/java/software/amazon/awssdk/http/auth/aws/signer/Checksummer.java
+++ b/core/http-auth-aws/src/main/java/software/amazon/awssdk/http/auth/aws/signer/Checksummer.java
@@ -48,7 +48,7 @@ static Checksummer create() {
}
/**
- * Get a flexible checksummer that uses the given checksum-algorithm and the default.
+ * Get a flexible checksummer that performs two checksums: the given checksum-algorithm and the default (sha256).
*/
static Checksummer create(ChecksumAlgorithm checksumAlgorithm) {
if (checksumAlgorithm != null) {
@@ -63,14 +63,15 @@ static Checksummer create(ChecksumAlgorithm checksumAlgorithm) {
}
/**
- * Get a flexible checksummer that uses the given checksum-algorithm and the default.
+ * Get a precomputed checksummer that results the given checksum string.
*/
static Checksummer create(String checksum) {
return new PrecomputedChecksummer(() -> checksum);
}
/**
- * Get a flexible checksummer that uses the given checksum-algorithm and the default.
+ * Get a flexible checksummer that performs two checksums: the given checksum-algorithm and a precomputed checksum from the
+ * given checksum string.
*/
static Checksummer create(String checksum, ChecksumAlgorithm checksumAlgorithm) {
if (checksumAlgorithm != null) {
diff --git a/core/http-auth-aws/src/main/java/software/amazon/awssdk/http/auth/aws/signer/V4Context.java b/core/http-auth-aws/src/main/java/software/amazon/awssdk/http/auth/aws/signer/V4Context.java
index f2f058c82715..6934c81e7c16 100644
--- a/core/http-auth-aws/src/main/java/software/amazon/awssdk/http/auth/aws/signer/V4Context.java
+++ b/core/http-auth-aws/src/main/java/software/amazon/awssdk/http/auth/aws/signer/V4Context.java
@@ -25,7 +25,7 @@
@SdkProtectedApi
@Immutable
public final class V4Context {
- private final String checksum;
+ private final String contentHash;
private final byte[] signingKey;
private final String signature;
private final V4CanonicalRequest canonicalRequest;
@@ -33,15 +33,15 @@ public final class V4Context {
public V4Context(String contentHash, byte[] signingKey, String signature,
V4CanonicalRequest canonicalRequest, SdkHttpRequest.Builder signedRequest) {
- this.checksum = contentHash;
+ this.contentHash = contentHash;
this.signingKey = signingKey.clone();
this.signature = signature;
this.canonicalRequest = canonicalRequest;
this.signedRequest = signedRequest;
}
- public String getContentChecksum() {
- return checksum;
+ public String getContentHash() {
+ return contentHash;
}
public byte[] getSigningKey() {
diff --git a/core/http-auth-aws/src/test/java/software/amazon/awssdk/http/auth/aws/internal/signer/DefaultAwsV4HttpSignerTest.java b/core/http-auth-aws/src/test/java/software/amazon/awssdk/http/auth/aws/internal/signer/DefaultAwsV4HttpSignerTest.java
index a0486c504cdd..446fd9a53e5a 100644
--- a/core/http-auth-aws/src/test/java/software/amazon/awssdk/http/auth/aws/internal/signer/DefaultAwsV4HttpSignerTest.java
+++ b/core/http-auth-aws/src/test/java/software/amazon/awssdk/http/auth/aws/internal/signer/DefaultAwsV4HttpSignerTest.java
@@ -235,7 +235,7 @@ public void sign_WithPayloadSigningFalseAndChunkEncodingTrueWithoutTrailer_Throw
}
@Test
- public void sign_withFlexibleChecksum_DelegatesToFlexibleChecksummer() {
+ public void sign_withChecksumAlgorithm_DelegatesToChecksummerWithThatChecksumAlgorithm() {
SyncSignRequest extends AwsCredentialsIdentity> request = generateBasicRequest(
AwsCredentialsIdentity.create("access", "secret"),
httpRequest -> {
@@ -250,7 +250,7 @@ public void sign_withFlexibleChecksum_DelegatesToFlexibleChecksummer() {
}
@Test
- public void sign_withFlexibleChecksumAndPayloadSigningFalse_DelegatesToFlexibleChecksummer() {
+ public void sign_withChecksumAlgorithmAndPayloadSigningFalse_DelegatesToChecksummerWithThatChecksumAlgorithm() {
SyncSignRequest extends AwsCredentialsIdentity> request = generateBasicRequest(
AwsCredentialsIdentity.create("access", "secret"),
httpRequest -> {
@@ -258,7 +258,6 @@ public void sign_withFlexibleChecksumAndPayloadSigningFalse_DelegatesToFlexibleC
signRequest -> signRequest
.putProperty(CHECKSUM_ALGORITHM, CRC32)
.putProperty(PAYLOAD_SIGNING_ENABLED, false)
-
);
SyncSignedRequest signedRequest = signer.sign(request);
diff --git a/core/http-auth-aws/src/test/java/software/amazon/awssdk/http/auth/aws/internal/signer/DefaultChecksummerTest.java b/core/http-auth-aws/src/test/java/software/amazon/awssdk/http/auth/aws/internal/signer/DefaultChecksummerTest.java
new file mode 100644
index 000000000000..f59f78295b32
--- /dev/null
+++ b/core/http-auth-aws/src/test/java/software/amazon/awssdk/http/auth/aws/internal/signer/DefaultChecksummerTest.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 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.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0
+ *
+ * or in the "license" file accompanying this file. 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 software.amazon.awssdk.http.auth.aws.internal.signer;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import io.reactivex.Flowable;
+import java.io.ByteArrayInputStream;
+import java.net.URI;
+import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
+import org.junit.jupiter.api.Test;
+import org.reactivestreams.Publisher;
+import software.amazon.awssdk.http.ContentStreamProvider;
+import software.amazon.awssdk.http.SdkHttpMethod;
+import software.amazon.awssdk.http.SdkHttpRequest;
+
+public class DefaultChecksummerTest {
+
+ ContentStreamProvider payload = () -> new ByteArrayInputStream("foo".getBytes(StandardCharsets.UTF_8));
+ Publisher payloadAsync = Flowable.just(ByteBuffer.wrap("foo".getBytes(StandardCharsets.UTF_8)));
+
+
+ SdkHttpRequest.Builder request = SdkHttpRequest.builder()
+ .uri(URI.create("https://localhost"))
+ .method(SdkHttpMethod.GET);
+
+ @Test
+ public void checksummer_shouldAddSha256ChecksumToAmzContentSha256Header() {
+ DefaultChecksummer checksummer = new DefaultChecksummer();
+ SdkHttpRequest expectedRequest = request
+ .putHeader("x-amz-content-sha256", "2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae")
+ .build();
+
+ checksummer.checksum(payload, request);
+
+ assertEquals(expectedRequest.toString(), request.build().toString());
+ }
+
+ @Test
+ public void checksummerAsync_shouldAddSha256ChecksumToAmzContentSha256Header() {
+ DefaultChecksummer checksummer = new DefaultChecksummer();
+ SdkHttpRequest expectedRequest = request
+ .putHeader("x-amz-content-sha256", "2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae")
+ .build();
+
+ checksummer.checksum(payloadAsync, request);
+
+ assertEquals(expectedRequest.toString(), request.build().toString());
+ }
+}
diff --git a/core/http-auth-aws/src/test/java/software/amazon/awssdk/http/auth/aws/internal/signer/DefaultRequestSignerTest.java b/core/http-auth-aws/src/test/java/software/amazon/awssdk/http/auth/aws/internal/signer/DefaultRequestSignerTest.java
new file mode 100644
index 000000000000..4cbe98387ca5
--- /dev/null
+++ b/core/http-auth-aws/src/test/java/software/amazon/awssdk/http/auth/aws/internal/signer/DefaultRequestSignerTest.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright 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.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0
+ *
+ * or in the "license" file accompanying this file. 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 software.amazon.awssdk.http.auth.aws.internal.signer;
+
+import static java.time.ZoneOffset.UTC;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static software.amazon.awssdk.utils.BinaryUtils.toHex;
+
+import java.net.URI;
+import java.time.Clock;
+import java.time.Instant;
+import org.junit.jupiter.api.Test;
+import software.amazon.awssdk.http.SdkHttpMethod;
+import software.amazon.awssdk.http.SdkHttpRequest;
+import software.amazon.awssdk.http.auth.aws.signer.CredentialScope;
+import software.amazon.awssdk.http.auth.aws.signer.V4Context;
+import software.amazon.awssdk.http.auth.aws.signer.V4Properties;
+import software.amazon.awssdk.http.auth.aws.signer.V4RequestSigner;
+import software.amazon.awssdk.identity.spi.AwsCredentialsIdentity;
+
+public class DefaultRequestSignerTest {
+
+ V4Properties v4Properties = V4Properties.builder()
+ .credentials(AwsCredentialsIdentity.create("foo", "bar"))
+ .credentialScope(new CredentialScope("baz", "qux", Instant.EPOCH))
+ .signingClock(Clock.fixed(Instant.EPOCH, UTC))
+ .doubleUrlEncode(true)
+ .normalizePath(true)
+ .build();
+
+ V4RequestSigner requestSigner = new DefaultV4RequestSigner(v4Properties);
+
+ @Test
+ public void requestSigner_sign_shouldReturnSignedContext_butNotAddAnyAuthInfoToRequest() {
+ SdkHttpRequest.Builder request = SdkHttpRequest
+ .builder()
+ .uri(URI.create("https://localhost"))
+ .method(SdkHttpMethod.GET)
+ .putHeader("x-amz-content-sha256", "quux");
+ String expectedContentHash = "quux";
+ String expectedSigningKeyHex = "3d558b7a87b67996abc908071e0771a31b2a7977ab247144e60a6cba3356be1f";
+ String expectedSignature = "7557839280ea0ef5c4acc66e5670d0857ac4f491884b1b8031d4dea2fc33483c";
+ String expectedCanonicalRequestString = "GET\n/\n\n"
+ + "host:localhost\nx-amz-content-sha256:quux\n\n"
+ + "host;x-amz-content-sha256\nquux";
+ String expectedHost = "localhost";
+
+ V4Context v4Context = requestSigner.sign(request);
+
+ assertEquals(expectedContentHash, v4Context.getContentHash());
+ assertEquals(expectedSigningKeyHex, toHex(v4Context.getSigningKey()));
+ assertEquals(expectedSignature, v4Context.getSignature());
+ assertEquals(expectedCanonicalRequestString, v4Context.getCanonicalRequest().getCanonicalRequestString());
+ assertEquals(expectedHost, v4Context.getSignedRequest().firstMatchingHeader("Host").orElse(""));
+ }
+}
diff --git a/core/http-auth-aws/src/test/java/software/amazon/awssdk/http/auth/aws/internal/signer/FlexibleChecksummerTest.java b/core/http-auth-aws/src/test/java/software/amazon/awssdk/http/auth/aws/internal/signer/FlexibleChecksummerTest.java
new file mode 100644
index 000000000000..550fbc9ff003
--- /dev/null
+++ b/core/http-auth-aws/src/test/java/software/amazon/awssdk/http/auth/aws/internal/signer/FlexibleChecksummerTest.java
@@ -0,0 +1,120 @@
+/*
+ * Copyright 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.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0
+ *
+ * or in the "license" file accompanying this file. 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 software.amazon.awssdk.http.auth.aws.internal.signer;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static software.amazon.awssdk.checksums.DefaultChecksumAlgorithm.CRC32;
+import static software.amazon.awssdk.checksums.DefaultChecksumAlgorithm.SHA256;
+
+import io.reactivex.Flowable;
+import java.io.ByteArrayInputStream;
+import java.net.URI;
+import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
+import java.util.Collections;
+import org.junit.jupiter.api.Test;
+import org.reactivestreams.Publisher;
+import software.amazon.awssdk.http.ContentStreamProvider;
+import software.amazon.awssdk.http.SdkHttpMethod;
+import software.amazon.awssdk.http.SdkHttpRequest;
+import software.amazon.awssdk.utils.ImmutableMap;
+
+public class FlexibleChecksummerTest {
+
+ ContentStreamProvider payload = () -> new ByteArrayInputStream("foo".getBytes(StandardCharsets.UTF_8));
+ Publisher payloadAsync = Flowable.just(ByteBuffer.wrap("foo".getBytes(StandardCharsets.UTF_8)));
+
+
+ SdkHttpRequest.Builder request = SdkHttpRequest.builder()
+ .uri(URI.create("https://localhost"))
+ .method(SdkHttpMethod.GET);
+
+ @Test
+ public void checksummer_withNoChecksums_shouldNotAddAnyChecksum() {
+ FlexibleChecksummer checksummer = new FlexibleChecksummer(Collections.emptyMap());
+ SdkHttpRequest expectedRequest = request.build();
+
+ checksummer.checksum(payload, request);
+
+ assertEquals(expectedRequest.toString(), request.build().toString());
+ }
+
+ @Test
+ public void checksummerAsync_withNoChecksums_shouldNotAddAnyChecksum() {
+ FlexibleChecksummer checksummer = new FlexibleChecksummer(Collections.emptyMap());
+ SdkHttpRequest expectedRequest = request.build();
+
+ checksummer.checksum(payloadAsync, request);
+
+ assertEquals(expectedRequest.toString(), request.build().toString());
+ }
+
+ @Test
+ public void checksummer_withOneChecksum_shouldAddOneChecksum() {
+ FlexibleChecksummer checksummer = new FlexibleChecksummer(ImmutableMap.of("sha256", SHA256));
+ SdkHttpRequest expectedRequest = request
+ .putHeader("sha256", "2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae")
+ .build();
+
+ checksummer.checksum(payload, request);
+
+ assertEquals(expectedRequest.toString(), request.build().toString());
+ }
+
+ @Test
+ public void checksummerAsync_withOneChecksum_shouldAddOneChecksum() {
+ FlexibleChecksummer checksummer = new FlexibleChecksummer(Collections.emptyMap());
+ SdkHttpRequest expectedRequest = request
+ .putHeader("sha256", "2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae")
+ .build();
+
+ checksummer.checksum(payloadAsync, request);
+
+ assertEquals(expectedRequest.toString(), request.build().toString());
+ }
+
+ @Test
+ public void checksummer_withTwoChecksums_shouldAddTwoChecksums() {
+ FlexibleChecksummer checksummer = new FlexibleChecksummer(ImmutableMap.of(
+ "sha256", SHA256,
+ "crc32", CRC32
+ ));
+ SdkHttpRequest expectedRequest = request
+ .putHeader("sha256", "2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae")
+ .putHeader("crc32", "8c736521")
+ .build();
+
+ checksummer.checksum(payload, request);
+
+ assertEquals(expectedRequest.toString(), request.build().toString());
+ }
+
+ @Test
+ public void checksummerAsync_withTwoChecksums_shouldAddTwoChecksums() {
+ FlexibleChecksummer checksummer = new FlexibleChecksummer(ImmutableMap.of(
+ "sha256", SHA256,
+ "crc32", CRC32
+ ));
+ SdkHttpRequest expectedRequest = request
+ .putHeader("sha256", "2c26b46b68ffc68ff99b453c1d30413413422d706483bfa0f98a5e886266e7ae")
+ .putHeader("crc32", "8c736521")
+ .build();
+
+ checksummer.checksum(payloadAsync, request);
+
+ assertEquals(expectedRequest.toString(), request.build().toString());
+ }
+}
diff --git a/core/http-auth-aws/src/test/java/software/amazon/awssdk/http/auth/aws/internal/signer/PrecomputedChecksummerTest.java b/core/http-auth-aws/src/test/java/software/amazon/awssdk/http/auth/aws/internal/signer/PrecomputedChecksummerTest.java
new file mode 100644
index 000000000000..ead8524019eb
--- /dev/null
+++ b/core/http-auth-aws/src/test/java/software/amazon/awssdk/http/auth/aws/internal/signer/PrecomputedChecksummerTest.java
@@ -0,0 +1,64 @@
+/*
+ * Copyright 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.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0
+ *
+ * or in the "license" file accompanying this file. 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 software.amazon.awssdk.http.auth.aws.internal.signer;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+import io.reactivex.Flowable;
+import java.io.ByteArrayInputStream;
+import java.net.URI;
+import java.nio.ByteBuffer;
+import java.nio.charset.StandardCharsets;
+import org.junit.jupiter.api.Test;
+import org.reactivestreams.Publisher;
+import software.amazon.awssdk.http.ContentStreamProvider;
+import software.amazon.awssdk.http.SdkHttpMethod;
+import software.amazon.awssdk.http.SdkHttpRequest;
+
+public class PrecomputedChecksummerTest {
+
+ ContentStreamProvider payload = () -> new ByteArrayInputStream("foo".getBytes(StandardCharsets.UTF_8));
+ Publisher payloadAsync = Flowable.just(ByteBuffer.wrap("foo".getBytes(StandardCharsets.UTF_8)));
+
+
+ SdkHttpRequest.Builder request = SdkHttpRequest.builder()
+ .uri(URI.create("https://localhost"))
+ .method(SdkHttpMethod.GET);
+
+ @Test
+ public void checksummer_shouldAddComputedValue() {
+ PrecomputedChecksummer checksummer = new PrecomputedChecksummer(() -> "something");
+ SdkHttpRequest expectedRequest = request
+ .putHeader("x-amz-content-sha256", "something")
+ .build();
+
+ checksummer.checksum(payload, request);
+
+ assertEquals(expectedRequest.toString(), request.build().toString());
+ }
+
+ @Test
+ public void checksummerAsync_shouldAddComputedValue() {
+ PrecomputedChecksummer checksummer = new PrecomputedChecksummer(() -> "something");
+ SdkHttpRequest expectedRequest = request
+ .putHeader("x-amz-content-sha256", "something")
+ .build();
+
+ checksummer.checksum(payloadAsync, request);
+
+ assertEquals(expectedRequest.toString(), request.build().toString());
+ }
+}
diff --git a/core/http-auth-aws/src/test/java/software/amazon/awssdk/http/auth/aws/internal/util/ChecksumUtilTest.java b/core/http-auth-aws/src/test/java/software/amazon/awssdk/http/auth/aws/internal/util/ChecksumUtilTest.java
new file mode 100644
index 000000000000..f0215c94b642
--- /dev/null
+++ b/core/http-auth-aws/src/test/java/software/amazon/awssdk/http/auth/aws/internal/util/ChecksumUtilTest.java
@@ -0,0 +1,66 @@
+/*
+ * Copyright 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.
+ * A copy of the License is located at
+ *
+ * http://aws.amazon.com/apache2.0
+ *
+ * or in the "license" file accompanying this file. 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 software.amazon.awssdk.http.auth.aws.internal.util;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static software.amazon.awssdk.checksums.DefaultChecksumAlgorithm.CRC32;
+import static software.amazon.awssdk.checksums.DefaultChecksumAlgorithm.CRC32C;
+import static software.amazon.awssdk.checksums.DefaultChecksumAlgorithm.MD5;
+import static software.amazon.awssdk.checksums.DefaultChecksumAlgorithm.SHA1;
+import static software.amazon.awssdk.checksums.DefaultChecksumAlgorithm.SHA256;
+import static software.amazon.awssdk.http.auth.aws.internal.util.ChecksumUtil.checksumHeaderName;
+import static software.amazon.awssdk.http.auth.aws.internal.util.ChecksumUtil.fromChecksumAlgorithm;
+import static software.amazon.awssdk.http.auth.aws.internal.util.ChecksumUtil.readAll;
+
+import java.io.ByteArrayInputStream;
+import org.junit.jupiter.api.Test;
+import software.amazon.awssdk.http.auth.aws.internal.checksums.Crc32CChecksum;
+import software.amazon.awssdk.http.auth.aws.internal.checksums.Crc32Checksum;
+import software.amazon.awssdk.http.auth.aws.internal.checksums.Md5Checksum;
+import software.amazon.awssdk.http.auth.aws.internal.checksums.Sha1Checksum;
+import software.amazon.awssdk.http.auth.aws.internal.checksums.Sha256Checksum;
+
+public class ChecksumUtilTest {
+
+ @Test
+ public void checksumHeaderName_shouldFormatName() {
+ assertEquals("x-amz-checksum-sha256", checksumHeaderName(SHA256));
+ assertEquals("x-amz-checksum-sha1", checksumHeaderName(SHA1));
+ assertEquals("x-amz-checksum-crc32", checksumHeaderName(CRC32));
+ assertEquals("x-amz-checksum-crc32c", checksumHeaderName(CRC32C));
+ assertEquals("x-amz-checksum-md5", checksumHeaderName(MD5));
+ }
+
+ @Test
+ public void fromChecksumAlgorithm_mapsToCorrectSdkChecksum() {
+ assertEquals(Sha256Checksum.class, fromChecksumAlgorithm(SHA256).getClass());
+ assertEquals(Sha1Checksum.class, fromChecksumAlgorithm(SHA1).getClass());
+ assertEquals(Crc32Checksum.class, fromChecksumAlgorithm(CRC32).getClass());
+ assertEquals(Crc32CChecksum.class, fromChecksumAlgorithm(CRC32C).getClass());
+ assertEquals(Md5Checksum.class, fromChecksumAlgorithm(MD5).getClass());
+ }
+
+ @Test
+ public void readAll_consumesEntireStream() {
+ int bytes = 4096 * 4 + 1;
+ byte[] buf = new byte[bytes];
+ ByteArrayInputStream inputStream = new ByteArrayInputStream(buf);
+
+ readAll(inputStream);
+
+ assertEquals(0, inputStream.available());
+ }
+}