Skip to content

fix: add streaming flag and error handling#3214

Open
yenfryherrerafeliz wants to merge 18 commits intoaws:masterfrom
yenfryherrerafeliz:feat_add_streaming_flag_middleware
Open

fix: add streaming flag and error handling#3214
yenfryherrerafeliz wants to merge 18 commits intoaws:masterfrom
yenfryherrerafeliz:feat_add_streaming_flag_middleware

Conversation

@yenfryherrerafeliz
Copy link
Contributor

@yenfryherrerafeliz yenfryherrerafeliz commented Nov 20, 2025

Issues #3124, #3018, #3181:

Description of changes:

  • Evaluates if a client's operation requires http streaming flag to be set to true, and if so then it pass the option along.
  • Make error parsers to reused a parsed body for scenario where the body is non seekable and can't be consumed again.
  • Make sure empty payloads are not parsed.

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

- Evaluates if a client's operation requires http streaming flag to be set to true, and if so then it pass the option along.
- Make error parsers to reused a parsed body for scenario where the body is non seekable and can't be consumed again.

Also change the condition:
 (!$body->isSeekable() || $body->getSize())
To:
 (!$body->isSeekable() || !$body->getSize())

The reason is that a stream non seekable will most likely not have a size, which means this condition will always be true.
Reverted the condition to what it was:
(!$body->isSeekable() || $body->getSize())

Why?, I need to understand better what is the usage of this condition before changing. It was breaking some integ tests.
- When a response body is empty then we dont try to parse it.
- When the response body is non seekable then, we read the full body before parsing.
@yenfryherrerafeliz
Copy link
Contributor Author

Running integ tets
vendor/bin/behat --format=progress --tags=integ
...................................................................... 70
...................................................................... 140
...................................................................... 210
......................................

66 scenarios (66 passed)
248 steps (248 passed)
5m9.29s (45.13Mb)
Running smoke tests
vendor/bin/behat --format=progress --suite=smoke --tags='~@noassumerole'
...................................................................... 70
...................................................................... 140
...................................................................... 210
............

111 scenarios (111 passed)
222 steps (222 passed)
0m45.99s (95.47Mb)

@yenfryherrerafeliz yenfryherrerafeliz marked this pull request as ready for review November 26, 2025 15:04
throw new \RuntimeException('The HTTP handler was rejected without an "exception" key value pair.');
}

$serviceError = "AWS HTTP error: " . $err['exception']->getMessage();
Copy link
Member

Choose a reason for hiding this comment

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

The change in format might affect log parsing. I'd leave this unless it's accounted for later

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 basically changed this because it was duplicating the error message. What I did in specific was to append the message from the exception when a response is not available, but, if we have a response then we just use the error message from the deserialization process.

if (!isset($err['response'])) {
    $parts = ['response' => null];
    $serviceError .= $err['exception']->getMessage(); // MOVED HERE.
}

When the response body is a non seekable stream, which happens when the stream flag is set in the request, the parser condition to do a parsing is evaluated to true, but in empty payloads, such as when doing head requests, it fails. To remedy this we read the full body content and evaluate whether the returned value is empty before parsing.
To make a body content to be fully available always in implementations a response
wrapper class has been created that takes in a response and evaluates if the body
is non-seekable then it wrappes it into a CachingStream that will allow the body
to rewind.
Overwrites responses on non-seekable streams by wrapping the non-seekable body on a CachingStream to allow rewind.
Avoid consuming original body before it is cached.
@yenfryherrerafeliz
Copy link
Contributor Author

Running integ tets
vendor/bin/behat --format=progress --tags=integ
...................................................................... 70
...................................................................... 140
...................................................................... 210
......................................

66 scenarios (66 passed)
248 steps (248 passed)
10m14.82s (43.42Mb)
Running smoke tests
vendor/bin/behat --format=progress --suite=smoke --tags='~@noassumerole'
...................................................................... 70
...................................................................... 140
...................................................................... 210
............

111 scenarios (111 passed)
222 steps (222 passed)
0m35.47s (92.58Mb)

Copy link
Member

@stobrien89 stobrien89 left a comment

Choose a reason for hiding this comment

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

A few more comments and an old one (log parsing) that needs to be addressed

Comment on lines +42 to 49
if ($body->isSeekable()) {
$body->rewind();
}

$rawBody = $body->getContents();
if (!empty($rawBody)) {
$parsedBody = $this->parseJson($rawBody, $response);
}
Copy link
Member

Choose a reason for hiding this comment

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

Could this logic and the logic in payload() for JSON and XML parsers be moved into the abstract parsers?

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 logic is like a generic method for parsing JSON payload and is used by JsonRpcErrorParser and RestJsonErrorParser, and actually it was already there; I just changed a few things such as the empty content evaluation, etc.

Regarding moving payload into the abstract class, I think we could, but I would like to understand more why we want to do it?

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.

2 participants