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

S3 200 error handling #3024

Merged
merged 25 commits into from
Jul 11, 2024
Merged

S3 200 error handling #3024

merged 25 commits into from
Jul 11, 2024

Conversation

sbera87
Copy link
Contributor

@sbera87 sbera87 commented Jul 2, 2024

Issue #, if available:

Description of changes:

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.

@sbera87 sbera87 requested a review from sbiscigl July 2, 2024 14:21
{
AWS_LOGSTREAM_DEBUG(AWS_CLIENT_LOG_TAG, "Request returned error. Attempting to generate appropriate error codes from response");
auto error = BuildAWSError(httpResponse);
return HttpResponseOutcome(std::move(error));
}
else if(request.HasEmbeddedError(httpResponse->GetResponseBody(), httpResponse->GetHeaders()))
{
return HttpResponseOutcome(std::move(BuildAWSErrorFromResponseBody(httpResponse)) );
Copy link
Contributor

Choose a reason for hiding this comment

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

gives a clang warning error: moving a temporary object prevents copy elision [-Werror,-Wpessimizing-move]

should update this to use a initializer list

return {BuildAWSErrorFromResponseBody(httpResponse)};

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ack

@@ -41,8 +43,14 @@ class AmazonWebServiceRequestMock : public Aws::AmazonWebServiceRequest
virtual const char* GetServiceRequestName() const override { return "AmazonWebServiceRequestMock"; }
virtual bool HasEmbeddedError(Aws::IOStream& body, const Aws::Http::HeaderValueCollection& header) const override {
(void) header;

auto readPointer = body.tellg();
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 fixes the body of response parsing issue existing in test cases. The pointer in the stream was being moved to the end which caused subsequent parsing to fail.

@@ -61,7 +69,7 @@ class CountedRetryStrategy : public Aws::Client::DefaultRetryStrategy
m_attemptedRetries(0)
{}
CountedRetryStrategy(long maxRetires)
: Aws::Client::DefaultRetryStrategy(maxRetires <= 0 ? (std::numeric_limits<long>::max)() : maxRetires),
: Aws::Client::DefaultRetryStrategy(maxRetires < 0 ? (std::numeric_limits<long>::max)() : maxRetires),
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 allows to try explicit tests without retry . There are times when we want to test the workflow in the first iteration only and not retry (which changes the error codes)

GetMockSecretAccessKey()), "service", config.region.empty() ? Aws::Region::US_EAST_1 : config.region),
Aws::MakeShared<MockAWSErrorMarshaller>("MockAWSClient")),
m_countedRetryStrategy(std::static_pointer_cast<CountedRetryStrategy>(config.retryStrategy)) { }
errorMarshaller
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Just adding delegate constructor and leveraging it in passing different error marshallers for different test use cases

@@ -65,3 +65,5 @@ Aws::Http::HeaderValueCollection InvokeRequest::GetRequestSpecificHeaders() cons
return headers;

}

Copy link
Contributor

Choose a reason for hiding this comment

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

lets figure out what is causing this white space to change, this potentiallly could a delta of thousands of files. only codegen changes that should be visible should be in S3.

@@ -74,7 +74,7 @@ namespace Aws
* Abstract AWS Client. Contains most of the functionality necessary to build an http request, get it signed, and send it across the wire.
*/
class AWS_CORE_API AWSClient
{
{
Copy link
Contributor

Choose a reason for hiding this comment

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

nit pick: whitepace change

const Aws::Http::HeaderValueCollection &header) const
{
// Header is unused
(void) header;
Copy link
Contributor

Choose a reason for hiding this comment

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

we have a macro AWS_UNREFERENCED_PARAM that we try to use in this instance instead of a void cast, which is itself a void cast, but its a little more readable.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ack

_mockHttpClient->AddResponseToReturn(mockResponse);

const auto response = _s3Client->CopyObject(request);
std::cout<<"Custom Error2:"<<response.GetError()<<std::endl;
Copy link
Contributor

Choose a reason for hiding this comment

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

think you forgot to remove this

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ack, will remove

@@ -1,578 +1,669 @@
/**
Copy link
Contributor

Choose a reason for hiding this comment

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

what happend here, should try to preserve git history so that we can trace the different S3 customizations that we have going on here.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ack

Aws::String xmlString((Aws::IStreamBufIterator(httpResponse->GetResponseBody())), Aws::IStreamBufIterator());

ss <<xmlString;
ss << " current pointer location in stream = "<<httpResponse->GetResponseBody().tellp();
Copy link
Contributor

Choose a reason for hiding this comment

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

instead of returning the pointer location lets just stilll return No response body. and log out a debug statement. The message consumed as a error message in a response could be somewhat confusing.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ack

@@ -76,6 +76,32 @@ Aws::Http::HeaderValueCollection ${typeInfo.className}::GetRequestSpecificHeader

}
#end

Copy link
Contributor

Choose a reason for hiding this comment

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

ah this is is what is causing the whitespace change, put it inside the #if. a empty line in a vm file will result in a new line in the code that is generated.

@@ -83,4 +83,30 @@ Aws::Http::HeaderValueCollection ${typeInfo.className}::GetRequestSpecificHeader
return headers;
}
#end

Copy link
Contributor

Choose a reason for hiding this comment

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

same thing here no new white space change outside of the if statement

@sbera87 sbera87 requested a review from sbiscigl July 8, 2024 13:08
Aws::StringStream ss;
ss << "No response body.";

Copy link
Contributor Author

Choose a reason for hiding this comment

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

added appropriate error message based upon the case

@@ -143,6 +148,28 @@ class AWSClientTestSuite : public Aws::Testing::AwsCppSdkGTestSuite
}
};


class XMLClientTestSuite : public AWSClientTestSuite
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Adding a child test suite class for xml parsing which uses a different error marshaller

Copy link
Contributor

Choose a reason for hiding this comment

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

this is nice!

const Aws::Http::HeaderValueCollection &header) const
{
// Header is unused
(void) header;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

ack

_mockHttpClient->AddResponseToReturn(mockResponse);

const auto response = _s3Client->CopyObject(request);
std::cout<<"Custom Error2:"<<response.GetError()<<std::endl;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

ack, will remove

@@ -1,578 +1,669 @@
/**
Copy link
Contributor Author

Choose a reason for hiding this comment

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

ack

@@ -16,8 +17,29 @@ using namespace Aws::S3::Model;

const char* ALLOCATION_TAG = "S3UnitTest";

class S3UnitTest_S3EmbeddedErrorTestNonOKResponse_Test;

class S3TestClient : public S3Client
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 a quick way of adding a test wrapper on top of S3 client class to be able to make unit test related changes



//Set http error and error in body in a way to hit generic xml error marshaller, which sets the exception name
TEST_F(S3UnitTest, S3EmbeddedErrorTestNonOKResponse) {
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 test case improves code coverage and tests corner case when there is a error body in response but http response code is not ok as well as the client is not S3. This defaults to generic error marshaller then.

auto mockRequest = Aws::MakeShared<Standard::StandardHttpRequest>(ALLOCATION_TAG, "mockuri", HttpMethod::HTTP_GET);
mockRequest->SetResponseStreamFactory([]() -> IOStream* {
return Aws::New<StringStream>(ALLOCATION_TAG, R"(<?xml version="1.0" encoding="UTF-8"?><Error><Code>SlowDown</Code><Message>Please reduce your request rate.</Message></Error>)", std::ios_base::in | std::ios_base::binary);
const std::string mockResponseString = "\n <?xml version=\"1.0\" encoding=\"UTF-8\"?>\n\n <Error>\n <Code>InternalError</Code>\n <Message>We encountered an internal error. Please try again.</Message>\n <RequestId>656c76696e6727732072657175657374</RequestId>\n <HostId>Uuag1LuByRx9e6j5Onimru9pO4ZVKnJ2Qz7/C1NPcfTWAtRPfTaOFg==</HostId>\n </Error>\n ";
Copy link
Contributor Author

Choose a reason for hiding this comment

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

add a retryable error

@@ -16,8 +17,29 @@ using namespace Aws::S3::Model;

const char* ALLOCATION_TAG = "S3UnitTest";

class S3UnitTest_S3EmbeddedErrorTestNonOKResponse_Test;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

Forward declaration of test class for friend class in google test suite

//if response code not ok, use error marshaller
if(httpResponse.GetResponseCode() != HttpResponseCode::OK)
{
return XmlErrorMarshaller::Marshall(httpResponse);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

for any error code other than ok, fall back to generic xml error marshaller

return XmlErrorMarshaller::Marshall(httpResponse);
}

Aws::String message{"Error in body of the response"};
Copy link
Contributor

Choose a reason for hiding this comment

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

why do we need this initial string value?

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 base case error in case the if conditions are not met. This is basically default error in the top condition block

auto messageNode = doc.GetRootElement().FirstChild("Message") ;
if(!messageNode.IsNull())
{
message = messageNode.GetText();
Copy link
Contributor

Choose a reason for hiding this comment

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

GetText
Get the inner text of the node (potentially includes other nodes)

Please check that the xml node does not have any children (to avoid accidental tracing of wrong message). The best case would be to check if the node contains only text value, but our XML wrapper seems to not provide such api.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ack. added an extra check if have children. But in my opinion this would still be ok because as long as the first root element is error , we will indicate error in response body. The specific code is obtained from parsing the exact message child node which is where the additional check will help

bodyError = codeNode.GetText();
}
}
body.seekg(readPointer);
Copy link
Contributor

Choose a reason for hiding this comment

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

nit: I think it would be better to rewind the stream right after parsing (anyway parsing is done by copying the stream into another string).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ack, in this case it won't matter since the steam was already parsed and string copied over already by this point. but I can move it to the end of the function.

const Aws::Http::HeaderValueCollection &header) const
{
// Header is unused
(void) header;
Copy link
Contributor

Choose a reason for hiding this comment

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

nit but please change: AWS_UNREFERENCED_PARAM(header); or just remove the header variable name from the signature.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ack

Aws::String message{"Error in body of the response"};
//extract error message and code in the body
auto& body = httpResponse.GetResponseBody();
auto readPointer = body.tellg();
Copy link
Contributor

Choose a reason for hiding this comment

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

check if the stream is valid, i.e. good before doing operations on it.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ack

}
else
{
Aws::String xmlString((Aws::IStreamBufIterator(httpResponse->GetResponseBody())), Aws::IStreamBufIterator());
Copy link
Contributor

Choose a reason for hiding this comment

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

some debug tracing here, please remove or update

Copy link
Contributor Author

Choose a reason for hiding this comment

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

ack

// Header is unused
(void) header;

auto readPointer = body.tellg();
Copy link
Contributor

Choose a reason for hiding this comment

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

not very clear why a similar logic is here and in ErrorMarshaller (well I guess I understand why, because one answers if there is such error and another parses and error to the object).

nit: would be nice to extract this logic into some common function in S3 Client to avoid copy-pasted generated code.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

While I agree, this cleanup can be done as part of a separate PR after further review of XML error parsing. The XML parser does a few more steps than this . As of now, we can keep S3 handling separate before redirecting to a common API

@sbera87 sbera87 requested a review from SergeyRyabinin July 9, 2024 13:47
@sbera87 sbera87 changed the title S3 200 error handling [Work in Progress] S3 200 error handling Jul 11, 2024
sbera87 and others added 8 commits July 11, 2024 13:29
…translate pin functions. With this change, customers can use one-time TR-31 keys directly in dataplane operations without the need to first import them into the service.

Add v2 smoke tests and smithy smokeTests trait for SDK testing.
Added further restrictions on logging of potentially sensitive inputs and outputs.
JSON body inspection: Update documentation to clarify that JSON parsing doesn't include full validation.
Add v2 smoke tests and smithy smokeTests trait for SDK testing.
Add v2 smoke tests and smithy smokeTests trait for SDK testing.
Authentication profiles are Amazon Connect resources (in gated preview) that allow you to configure authentication settings for users in your contact center. This release adds support for new ListAuthenticationProfiles, DescribeAuthenticationProfile and UpdateAuthenticationProfile APIs.
Updates EKS managed node groups to support EC2 Capacity Blocks for ML
Add v2 smoke tests and smithy smokeTests trait for SDK testing.
Add v2 smoke tests and smithy smokeTests trait for SDK testing.
@sbera87 sbera87 merged commit 6651887 into main Jul 11, 2024
4 checks passed
@sbera87 sbera87 deleted the s3_200 branch November 25, 2024 20:51
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.

5 participants