Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

move checksumming operations to a interceptor #3140

Merged
merged 1 commit into from
Oct 11, 2024
Merged

Conversation

sbiscigl
Copy link
Contributor

@sbiscigl sbiscigl commented Oct 9, 2024

Description of changes:

Moves the checksumming operations of the SDK behind a SRA interceptor for better modularization

Check all that applies:

  • Did a review by yourself.
  • Added proper tests to cover this PR. (If tests are not applicable, explain.)
  • Checked if this PR is a breaking (APIs have been changed) change.
  • Checked if this PR will not introduce cross-platform inconsistent behavior.
  • Checked if this PR would require a ReadMe/Wiki update.

Check which platforms you have built SDK on to verify the correctness of this PR.

  • Linux
  • Windows
  • Android
  • MacOS
  • IOS
  • Other Platforms

By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.

ChecksumInterceptor& operator=(ChecksumInterceptor&& other) noexcept = default;
~ChecksumInterceptor() override = default;

ModifyRequestOutcome ModifyRequest(InterceptorContext& context) override
Copy link
Contributor Author

Choose a reason for hiding this comment

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

all of the code in this file is copied from the existing implentation. I will refactor the logic in the next PR. This PR more or less jsut refactors the code out to a single location before handling the actual logical refactor. So while we can address comments on the logic here, a lot will be changing to it in the next PR.

else if (checksumAlgorithmName == "crc32")
{
std::shared_ptr<Aws::Utils::Crypto::CRC32> crc32 = Aws::MakeShared<Aws::Utils::Crypto::CRC32>(AWS_CLIENT_LOG_TAG);
httpRequest->AddResponseValidationHash("crc", crc32);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

this is actually a bug right now, this will result in response validation not being done on for objects using crc32. This is fixed in the interceptor refactor.

context.SetRequest(pRequestCtx->m_httpRequest);
for (const auto& interceptor : m_interceptors)
{
auto modifiedRequest = interceptor->ModifyRequest(context);
Copy link
Contributor

Choose a reason for hiding this comment

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

for the interceptor API,
please rename ModifyRequest into something like ModifyBeforeSigningRequest to be compliant with the internal reference design.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

yeah that was a miss on my part, it aligns with rusts as well, updating

{
const auto& httpRequest = context.GetTransmitRequest();
const auto& modeledRequest = context.GetModeledRequest();
if (httpRequest == nullptr)
Copy link
Contributor

Choose a reason for hiding this comment

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

nit : can also use if (!httpRequest)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

this is the code style that crt uses so i wanted to keep it consistent

Copy link
Contributor

Choose a reason for hiding this comment

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

if thats the case, its my advice adopt this to avoid typo '='
if (nullptr == httpRequest)

}
else if (checksumAlgorithmName == "crc32")
{
if (modeledRequest.IsStreaming())
Copy link
Contributor

Choose a reason for hiding this comment

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

cleanup: this block can be wrapped in a lambda accepting std:function which can be Aws::Utils::HashingUtils::CalculateCRC32 or Aws::Utils::HashingUtils::CalculateCRC32C or Aws::Utils::HashingUtils::CalculateSHA256
Rest is the same. Just easy to read and more code reuse.

Also we should move away from hardcoded strings like "crc32" unless they are constants defined or just use enum.
And move to switch case, which is much faster than if/else

Copy link
Contributor Author

Choose a reason for hiding this comment

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

from my other comment

all of the code in this file is copied from the existing implentation. I will refactor the logic in the next PR. This PR more or less jsut refactors the code out to a single location before handling the actual logical refactor. So while we can address comments on the logic here, a lot will be changing to it in the next PR.

This code could be cleaned up in a lot of different ways, and we plan on it. Its actually the next PR im going to raise. I dont like how this is strucutred and we ill be moving away from this giant if-else block alltogether. This PR is more focused on moving it out of the client and compartmentalizing it, then cleaning it up

const auto& request = context.GetModeledRequest();
const auto transmitRequest = context.GetTransmitRequest();
const auto response = context.GetTransmitResponse();
if (transmitRequest == nullptr || transmitRequest == nullptr)
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: condense if (!(transmitRequest )
Duplicate : if (transmitRequest == nullptr || transmitRequest == nullptr), you meant response

Copy link
Contributor Author

Choose a reason for hiding this comment

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

you meant response

yep good catch

nit: condense if (!(transmitRequest ))

this is the code style that crt uses so i wanted to keep it consistent

{
for (const Aws::String& responseChecksumAlgorithmName : modeledRequest.GetResponseChecksumAlgorithmNames())
{
const auto lowered = Aws::Utils::StringUtils::ToLower(responseChecksumAlgorithmName.c_str());
Copy link
Contributor

Choose a reason for hiding this comment

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

cleanup: can be condensed for readability/reusability. One approach is we can use base class for different hash types and invoke a method on base type to add response validation hash from a const set of supported hash type clases

Copy link
Contributor Author

Choose a reason for hiding this comment

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

from my other comment

all of the code in this file is copied from the existing implentation. I will refactor the logic in the next PR. This PR more or less jsut refactors the code out to a single location before handling the actual logical refactor. So while we can address comments on the logic here, a lot will be changing to it in the next PR.

This code could be cleaned up in a lot of different ways, and we plan on it. Its actually the next PR im going to raise. I dont like how this is strucutred and we ill be moving away from this giant if-else block alltogether. This PR is more focused on moving it out of the client and compartmentalizing it, then cleaning it up

@@ -543,6 +547,17 @@ HttpResponseOutcome AWSClient::AttemptOneRequest(const std::shared_ptr<Aws::Http
*m_telemetryProvider->getMeter(this->GetServiceClientName(), {}),
{{TracingUtils::SMITHY_METHOD_DIMENSION, request.GetServiceRequestName()},{TracingUtils::SMITHY_SERVICE_DIMENSION, this->GetServiceClientName()}});

InterceptorContext context{request};
context.SetTransmitRequest(httpRequest);
for (const auto& interceptor : m_interceptors)
Copy link
Contributor

Choose a reason for hiding this comment

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

where is the check for m_interceptors empty? should it be empty?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

m_interceptors could be empty in which case we apply zero interceptors. infact a optimization we could make in teh future is make per-client interceptors. right now all clients will execute a checksum interceptors as they did before. but in the future we could optimize it where if a client doesnt do any checksumming, it will not compose the interceptor

@@ -570,27 +585,13 @@ HttpResponseOutcome AWSClient::AttemptOneRequest(const std::shared_ptr<Aws::Http
*m_telemetryProvider->getMeter(this->GetServiceClientName(), {}),
{{TracingUtils::SMITHY_METHOD_DIMENSION, request.GetServiceRequestName()},{TracingUtils::SMITHY_SERVICE_DIMENSION, this->GetServiceClientName()}});

if (request.ShouldValidateResponseChecksum())
context.SetTransmitResponse(httpResponse);
for (const auto& interceptor : m_interceptors)
Copy link
Contributor

Choose a reason for hiding this comment

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

what if interceptors is empty. will the workflow still be correct, if not maybe return an error

Copy link
Contributor Author

Choose a reason for hiding this comment

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

m_interceptors could be empty in which case we apply zero interceptors. infact a optimization we could make in teh future is make per-client interceptors. right now all clients will execute a checksum interceptors as they did before. but in the future we could optimize it where if a client doesnt do any checksumming, it will not compose the interceptor

}

private:
Aws::Map<Aws::String, Aws::String> m_attributes{};
std::shared_ptr<Aws::Http::HttpRequest> m_request{nullptr};
std::shared_ptr<Aws::Http::HttpResponse> m_response{nullptr};
const Aws::AmazonWebServiceRequest& m_modeledRequest;
Copy link
Contributor

Choose a reason for hiding this comment

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

storing reference? what happens if caller out of scope. is that possible in this workflow?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

nope its a borrow from the parent scope, in the current workflow its not possible

Copy link
Contributor

@sbera87 sbera87 left a comment

Choose a reason for hiding this comment

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

looks good overall. Minor changes needed in error checking/handling. Raised some questions for just robustness.

@sbiscigl sbiscigl force-pushed the checksum-interceptors branch 2 times, most recently from efc0b6b to 79ac465 Compare October 10, 2024 20:06
@sbiscigl sbiscigl marked this pull request as ready for review October 11, 2024 15:14
@sbiscigl sbiscigl merged commit ac9296d into main Oct 11, 2024
4 checks passed
@sbiscigl sbiscigl deleted the checksum-interceptors branch October 11, 2024 15:14
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