-
Notifications
You must be signed in to change notification settings - Fork 1.1k
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
S3 200 error handling #3024
Conversation
{ | ||
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)) ); |
There was a problem hiding this comment.
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)};
There was a problem hiding this comment.
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(); |
There was a problem hiding this comment.
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), |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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; | |||
|
|||
} | |||
|
There was a problem hiding this comment.
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 | |||
{ | |||
{ |
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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 @@ | |||
/** |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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(); |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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 | |||
|
There was a problem hiding this comment.
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 | |||
|
There was a problem hiding this comment.
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
Aws::StringStream ss; | ||
ss << "No response body."; | ||
|
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
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 @@ | |||
/** |
There was a problem hiding this comment.
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 |
There was a problem hiding this comment.
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) { |
There was a problem hiding this comment.
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 "; |
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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"}; |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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(); |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
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).
There was a problem hiding this comment.
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; |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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(); |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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()); |
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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(); |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
…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.
Issue #, if available:
Description of changes:
Check all that applies:
Check which platforms you have built SDK on to verify the correctness of this PR.
By submitting this pull request, I confirm that you can use, modify, copy, and redistribute this contribution, under the terms of your choice.