From 6f00826358fa41a1b16653d1a51d0a70d2ed7f58 Mon Sep 17 00:00:00 2001 From: bch36 <31776675+bch36@users.noreply.github.com> Date: Tue, 2 Mar 2021 12:07:24 -0600 Subject: [PATCH] Clear Payload buffer after receiving Wrench\Client keeps all received Payload objects in perpetuity. This results in a script eventually running out of memory if it's reading a large stream of data. Instead, after receiving any Payload objects buffered since the last call to receive(), clear the buffer of received Payloads. This is safe because they're never accessed again. Clear the buffer in ChromeDevtoolsProtocol\WebSocket\WebSocketClient to avoid upstream changes to Wrench\Client. Additional info: Wrench\Client stores all received Payloads in Client::$received. In fact, if Payload::getPayload() is called (as it is in DevtoolsClient), memory usage will double because the received data is copied from the Payload's comprising Frames (Payload::$frames) into Payload::$buffer. The data is then stored a third time in the ReadResponse and returned to the original caller. The caller only has the ability to delete the third copy of the data in the ReadResponse. This results in memory usage growing quickly and perpetually as a long-lasting stream is read until the script eventually runs out of available memory. For example, if a user generates a large PDF (printToPDF) using a transferMode of ReturnAsStream, they may call $session->io()->read() many times to fetch the generated PDF. As they do so, they'll likely write each block of data to a file. If the buffer of received Payloads is never cleared to free memory, the user is limited to receiving a PDF approximately 1/2 the size of the memory_limit. If the buffer of received Payloads is cleared regularly, then there is theoretically no limit to the size of PDF they can read. --- .../WebSocket/WebSocketClient.php | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/ChromeDevtoolsProtocol/WebSocket/WebSocketClient.php b/src/ChromeDevtoolsProtocol/WebSocket/WebSocketClient.php index 79cfbf19..fb2050b9 100644 --- a/src/ChromeDevtoolsProtocol/WebSocket/WebSocketClient.php +++ b/src/ChromeDevtoolsProtocol/WebSocket/WebSocketClient.php @@ -28,4 +28,16 @@ public function setDeadline(?\DateTimeImmutable $deadline) $this->socket->setDeadline($deadline); } + public function receive() + { + // Forward the receive() call to Client::receive() + $payloads = parent::receive(); + + // If the latest payload(s) are received, clear the buffer. We don't need that copy any more. + if ($payloads) + $this->received = array(); + + // Return the latest received payloads + return $payloads; + } }