From 8bb90a81bad1e4a602ff2c95780556a09ba2ad0d Mon Sep 17 00:00:00 2001 From: lazerg Date: Wed, 14 Oct 2026 14:02:38 +0500 Subject: [PATCH] bugfix: keep final event when non-seekable event stream reaches EOF --- .../fix-eventstream-final-event-eof.json | 7 +++++++ ...ekableStreamDecodingEventStreamIterator.php | 6 ++++-- ...leStreamDecodingEventStreamIteratorTest.php | 18 ++++++++++++++++++ 3 files changed, 29 insertions(+), 2 deletions(-) create mode 100644 .changes/nextrelease/fix-eventstream-final-event-eof.json diff --git a/.changes/nextrelease/fix-eventstream-final-event-eof.json b/.changes/nextrelease/fix-eventstream-final-event-eof.json new file mode 100644 index 0000000000..daf3e71b3e --- /dev/null +++ b/.changes/nextrelease/fix-eventstream-final-event-eof.json @@ -0,0 +1,7 @@ +[ + { + "type": "bugfix", + "category": "", + "description": "Fixed an issue in NonSeekableStreamDecodingEventStreamIterator where the final event was dropped when reading it reached the end of the stream." + } +] diff --git a/src/Api/Parser/NonSeekableStreamDecodingEventStreamIterator.php b/src/Api/Parser/NonSeekableStreamDecodingEventStreamIterator.php index d59f200e4a..667de81752 100644 --- a/src/Api/Parser/NonSeekableStreamDecodingEventStreamIterator.php +++ b/src/Api/Parser/NonSeekableStreamDecodingEventStreamIterator.php @@ -95,7 +95,9 @@ public function rewind() public function next() { $this->tempBuffer[] = $this->stream->read(1); - if ($this->valid()) { + if ($this->stream->eof()) { + $this->currentEvent = null; + } else { $this->key++; $this->currentEvent = $this->parseEvent(); } @@ -107,6 +109,6 @@ public function next() #[\ReturnTypeWillChange] public function valid() { - return !$this->stream->eof(); + return $this->currentEvent !== null; } } diff --git a/tests/Api/Parser/NonSeekableStreamDecodingEventStreamIteratorTest.php b/tests/Api/Parser/NonSeekableStreamDecodingEventStreamIteratorTest.php index 9da889679f..21065fb8bd 100644 --- a/tests/Api/Parser/NonSeekableStreamDecodingEventStreamIteratorTest.php +++ b/tests/Api/Parser/NonSeekableStreamDecodingEventStreamIteratorTest.php @@ -3,6 +3,7 @@ namespace Aws\Test\Api\Parser; use Aws\Api\Parser\NonSeekableStreamDecodingEventStreamIterator; +use GuzzleHttp\Psr7\BufferStream; use GuzzleHttp\Psr7\NoSeekStream; use GuzzleHttp\Psr7\StreamDecoratorTrait; use GuzzleHttp\Psr7\Utils; @@ -76,6 +77,23 @@ public function testValidReturnsTrueOnEOF() $this->assertFalse($iterator->valid()); } + public function testValidReturnsTrueWhenFinalEventReachesEOF() + { + $encodedEvent = <<write(base64_decode($encodedEvent)); + $iterator = new NonSeekableStreamDecodingEventStreamIterator($stream); + $iterator->rewind(); + $this->assertTrue($stream->eof()); + $this->assertTrue($iterator->valid()); + $this->assertSame('person', $iterator->current()['headers'][':event-type']); + $iterator->next(); + $this->assertFalse($iterator->valid()); + } + #[DataProvider('readAndHashBytesHandlesPartialReadsProvider')] public function testReadAndHashBytesHandlesPartialReads( string $eventName,