From 4b580fec9ecb7d24a080c8d3b47404cb76759fca Mon Sep 17 00:00:00 2001 From: Aaron Piotrowski Date: Thu, 28 Dec 2023 17:14:39 -0600 Subject: [PATCH] ClientException extends SteamException Extending StreamException prevents read() and buffer() from violating the ReadableStream interface. --- src/ClientException.php | 4 +++- src/Driver/Http1Driver.php | 4 ++-- src/Driver/Http2Driver.php | 8 ++++---- src/RequestBody.php | 7 +++---- 4 files changed, 12 insertions(+), 11 deletions(-) diff --git a/src/ClientException.php b/src/ClientException.php index 03f53d30..26e224f0 100644 --- a/src/ClientException.php +++ b/src/ClientException.php @@ -2,6 +2,8 @@ namespace Amp\Http\Server; +use Amp\ByteStream\StreamException; + /** * A ClientException thrown from {@see RequestBody::read()} or {@see RequestBody::buffer()} indicates that the * requesting client stream has been closed due to an error or exceeding a server limit such as the body size limit. @@ -17,7 +19,7 @@ * Responses returned by request handlers after a ClientException has been thrown will be ignored, as a response has * already been generated by the error handler. */ -class ClientException extends \Exception +class ClientException extends StreamException { /** @internal Do not instantiate instances of this exception in your request handlers or middleware! */ public function __construct( diff --git a/src/Driver/Http1Driver.php b/src/Driver/Http1Driver.php index 0f0e8af3..7388810f 100644 --- a/src/Driver/Http1Driver.php +++ b/src/Driver/Http1Driver.php @@ -749,13 +749,13 @@ static function (int $bodySize) use (&$bodySizeLimit): void { $this->pendingResponse->await(); // Wait for response to be generated. $this->pendingResponseCount--; } while ($this->continue); - } catch (StreamException) { - // Client disconnected, finally block will clean up. } catch (ClientException $exception) { if ($this->bodyQueue === null || !$this->pendingResponseCount) { // Send an error response only if another response has not already been sent to the request. $this->sendErrorResponse($exception, $request ?? null)->await(); } + } catch (StreamException) { + // Client disconnected, finally block will clean up. } finally { $this->pendingResponse->finally(function (): void { $this->removeTimeout(); diff --git a/src/Driver/Http2Driver.php b/src/Driver/Http2Driver.php index 99e37953..2d1eb81c 100644 --- a/src/Driver/Http2Driver.php +++ b/src/Driver/Http2Driver.php @@ -165,7 +165,7 @@ public function initializeWriting( if ($this->settings !== null) { // Upgraded connections automatically assume an initial stream with ID 1. - // No date will be incoming on this stream, so body size of 0. + // No data will be incoming on this stream, so body size of 0. $this->createStream(1, 0, Http2Stream::RESERVED | Http2Stream::REMOTE_CLOSED); $this->remoteStreamId = \max(1, $this->remoteStreamId); $this->remainingStreams--; @@ -364,11 +364,11 @@ private function send(int $id, Response $response, Request $request, Cancellatio $id, ); } - } catch (StreamException|CancelledException) { - // Client disconnected, ignore and proceed to clean up below. - $chunk = null; } catch (ClientException $exception) { $error = $exception->getCode() ?? Http2Parser::CANCEL; // Set error code to be used below. + } catch (StreamException|CancelledException) { + // Body stream threw or client disconnected, ignore and proceed to clean up below. + $chunk = null; } catch (\Throwable $throwable) { // Will be rethrown after cleanup below. } diff --git a/src/RequestBody.php b/src/RequestBody.php index 06f9810a..ef3b3a87 100644 --- a/src/RequestBody.php +++ b/src/RequestBody.php @@ -12,7 +12,7 @@ /** * This class allows streamed and buffered access to a request body with an API similar to {@see Payload}. * - * The {@see read()} and {@see buffer()} methods can also throw {@see ClientException} in addition to the usual + * The {@see read()} and {@see buffer()} methods can throw {@see ClientException}, which extends * {@see StreamException}, though generally there is no need to catch this exception. * * Additionally, this class allows increasing the body size limit dynamically. @@ -37,7 +37,6 @@ public function __construct( /** * @throws ClientException - * @throws StreamException */ public function read(?Cancellation $cancellation = null): ?string { @@ -46,7 +45,7 @@ public function read(?Cancellation $cancellation = null): ?string /** * @see Payload::buffer() - * @throws ClientException|BufferException|StreamException + * @throws ClientException|BufferException */ public function buffer(?Cancellation $cancellation = null, int $limit = \PHP_INT_MAX): string { @@ -92,7 +91,7 @@ public function increaseSizeLimit(int $size): void * Buffers entire stream before returning. Use {@see self::buffer()} to optionally provide a {@see Cancellation} * and/or length limit. * - * @throws ClientException|BufferException|StreamException + * @throws ClientException|BufferException */ public function __toString(): string {