Skip to content

Conversation

dagnir
Copy link
Contributor

@dagnir dagnir commented Oct 7, 2025

Motivation and Context

Add support for payload signing of async streaming requests signed with SigV4 using default AwsV4HttpSigner (using AwsV4HttpSigner.create()). Note, requests using the http URI scheme will not be signed regardless of the value of AwsV4FamilyHttpSigner.PAYLOAD_SIGNING_ENABLED to remain consistent with existing behavior. This may change in a future release.

Modifications

Testing

Screenshots (if appropriate)

Types of changes

  • Bug fix (non-breaking change which fixes an issue)
  • New feature (non-breaking change which adds functionality)

Checklist

  • I have read the CONTRIBUTING document
  • Local run of mvn install succeeds
  • My code follows the code style of this project
  • My change requires a change to the Javadoc documentation
  • I have updated the Javadoc documentation accordingly
  • I have added tests to cover my changes
  • All new and existing tests passed
  • I have added a changelog entry. Adding a new entry must be accomplished by running the scripts/new-change script and following the instructions. Commit the new file created by the script in .changes/next-release with your changes.
  • My change is to implement 1.11 parity feature and I have updated LaunchChangelog

License

  • I confirm that this pull request can be released under the Apache 2 license

dagnir added 5 commits August 5, 2025 14:14
This commit adds support for SigV4 signing of async request payloads.

In addition this commit moves the support for trailing checksums from
HttpChecksumStage to the V4 signer implementation; this puts it in line
with how sync chunked bodies are already handled.
 - Rename to computeAndMoveContentLength
 - Rename variable to chunkedPayload
 - Fix javadocs
 - Sign payload only if non-null
Combine these two steps to improve performance by reducing memory
allocations.
@dagnir dagnir force-pushed the dongie/sra-chunk-encoding-pt1 branch from fcda677 to 488b723 Compare October 7, 2025 22:18
@dagnir dagnir force-pushed the dongie/sra-chunk-encoding-pt1 branch from 3a9cb34 to e52ea62 Compare October 8, 2025 21:30
@dagnir dagnir marked this pull request as ready for review October 8, 2025 21:40
@dagnir dagnir requested a review from a team as a code owner October 8, 2025 21:40
Copy link

sonarqubecloud bot commented Oct 9, 2025

String checksumHeaderName = checksumHeaderName(checksumAlgorithm);
request.appendHeader(X_AMZ_TRAILER, checksumHeaderName);
}
request.putHeader(Header.CONTENT_LENGTH, Long.toString(encodedContentLength));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I thought content-length header is not required, is that not the case?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm not sure. Per the public docs, it's required unless Transfer-Encoding is present and the value is not identity.

This logic is preserved from the existing signer code

request.putHeader(Header.CONTENT_LENGTH, Long.toString(encodedContentLength));
request.appendHeader(CONTENT_ENCODING, AWS_CHUNKED);
.

@Fred1155 do you have any other info on this?

Comment on lines +179 to +181
// should not happen, this header is added by moveContentLength
.orElseThrow(() -> new RuntimeException(X_AMZ_DECODED_CONTENT_LENGTH
+ " header not present"));
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should we fail the future instead?

Copy link
Contributor Author

@dagnir dagnir Oct 10, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm it should fail the future right?

        CompletableFuture<String> c1 = new CompletableFuture<>();
        c1.complete("Hello");

        CompletableFuture<String> c2 = c1.thenApply(s -> {
            throw new RuntimeException();
        });

        c2.join(); // throws

}
executionAttributes.putAttribute(RESOLVED_CHECKSUM_SPECS, resolvedChecksumSpecs);

SdkHttpRequest httpRequest = context.executionContext().interceptorContext().httpRequest();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We are going to have a separate PR/release for this change, right?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think it's possible to separate these two, otherwise the body would get double chunk encoding.

I know we discussed doing a version bump for this removal. We can do the version bump and release both in the same minor version?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Even if we revert to this change in the signer?

        if (isChunkEncoding && isPayloadSigning) {
            // TODO(sra-identity-and-auth): We need to implement aws-chunk content-encoding for async.
            //  For now, we basically have to treat this as an unsigned case because there are existing s3 use-cases for
            //  Unsigned-payload + HTTP. These requests SHOULD be signed-payload, but are not pre-SRA, hence the problem. This
            //  will be taken care of in HttpChecksumStage for now, so we shouldn't throw an unsupported exception here, we
            //  should just fall through to the default since it will already encoded by the time it gets here.
            return V4PayloadSigner.create();

NVM if it'd actually make it worse.

@dagnir dagnir mentioned this pull request Oct 10, 2025
12 tasks
* and/or trailers representing trailing headers with their signature at the end.
*/
@SdkInternalApi
public final class AwsChunkedV4aPayloadSigner implements V4aPayloadSigner {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't we need to support signAsync in this class as well?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, but I will follow up with a separate PR for that; same for DefaultAwsCrtV4aHttpSigner.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Gotcha, but as soon as we remove the switching logic in HttpChecksumStage.java, sigv4a streaming operations will be broken, right? since it doesn't do AWS chunked encoding for async

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤦‍♂️ Ah I think you are right. In that case I can merge this back to the feature branch, and follow up with that. This PR is big enough as it is

if (clientType == ClientType.ASYNC &&
isStreamingUnsignedPayload(httpRequest, executionAttributes, resolvedChecksumSpecs,
resolvedChecksumSpecs.isRequestStreaming())) {
addFlexibleChecksumInTrailer(request, context, resolvedChecksumSpecs);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If a customer had an execution interceptor put on this checksum stage, that now doesnt have the calculated checksum, can this be a potentially breaking change?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Discussed this offline, there shouldn't really be any risk here. The checksum calculation still happened in a "streaming" fashion before by wrapping the publisher in the checksum publisher; we weren't calculating the checksum upfront.

 - Update variable naming
 - Throw if decoded content length not present
 - Throw if input request doesn't have content-length header
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants