Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion src/ClientFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class ClientFactory
/**
* Create a client.
* @param (Closure(): Metadata)|Metadata|string|mixed $service
* @param Metadata|string|null $metadata
* @param null|Metadata|string $metadata
* @throws InvalidArgumentException
* @throws Exception
*/
Expand Down
6 changes: 3 additions & 3 deletions src/Consul/Response.php
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ class Response
private $response;

/**
* @var array|null
* @var null|array
*/
private $decoded;

Expand All @@ -38,7 +38,7 @@ public function __call($name, $arguments)
}

/**
* @param mixed|null $default
* @param null|mixed $default
* @return mixed
* @throws ServerException
*/
Expand All @@ -60,7 +60,7 @@ public function json(?string $key = null, $default = null)
}

/**
* @return bool|object|null
* @return null|bool|object
*/
public function object()
{
Expand Down
2 changes: 1 addition & 1 deletion src/Contract/RegistryInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@ interface RegistryInterface
public function setLoadBalancer(?LoadBalancerInterface $loadBalancer);

/**
* @return LoadBalancerInterface|null
* @return null|LoadBalancerInterface
*/
public function getLoadBalancer();

Expand Down
6 changes: 3 additions & 3 deletions src/Functions.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@
* @template T
*
* @param callable(int):T $callback
* @param (callable(Throwable):mixed)|null $when
* @param null|(callable(Throwable):mixed) $when
* @return T
* @throws Throwable
*/
Expand Down Expand Up @@ -72,7 +72,7 @@ function throw_if($condition, $exception, ...$parameters)
* @template TValue
*
* @param TValue $value
* @param (callable(TValue):mixed)|null $callback
* @param null|(callable(TValue):mixed) $callback
* @return TValue
*/
function tap($value, ?callable $callback = null)
Expand Down Expand Up @@ -105,7 +105,7 @@ public function __call($method, $parameters)
* @template TReturn
*
* @param TValue $value
* @param callable(TValue):TReturn|null $callback
* @param null|callable(TValue):TReturn $callback
* @return ($callback is null ? TValue : TReturn)
*/
function with($value, ?callable $callback = null)
Expand Down
2 changes: 1 addition & 1 deletion src/MetadataManager.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ public static function register(string $name, Metadata $metadata)
}

/**
* @return Metadata|null
* @return null|Metadata
*/
public static function get(string $name)
{
Expand Down
4 changes: 2 additions & 2 deletions src/Support/Arr.php
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ class Arr
* Get an item from an array using "dot" notation.
*
* @param array|ArrayAccess $array
* @param int|string|null $key
* @param null|int|string $key
* @param mixed $default
* @return mixed
*/
Expand Down Expand Up @@ -54,7 +54,7 @@ public static function get($array, $key = null, $default = null)
* Check if an item or items exist in an array using "dot" notation.
*
* @param array|ArrayAccess $array
* @param array|string|null $keys
* @param null|array|string $keys
* @return bool
*/
public static function has($array, $keys)
Expand Down
2 changes: 1 addition & 1 deletion src/Support/UserAgent.php
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
class UserAgent
{
/**
* @var string|null
* @var null|string
*/
protected static $value;

Expand Down
2 changes: 1 addition & 1 deletion src/Transporter/AbstractTransporter.php
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,7 @@
abstract class AbstractTransporter implements TransporterInterface
{
/**
* @var LoadBalancerInterface|null
* @var null|LoadBalancerInterface
*/
protected $loadBalancer;

Expand Down
2 changes: 1 addition & 1 deletion src/Transporter/GrpcTransporter.php
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ class GrpcTransporter extends AbstractTransporter
protected array $options = [];

/**
* @var object|string|null
* @var null|object|string
*/
protected $credentials;

Expand Down
85 changes: 85 additions & 0 deletions src/Transporter/MultiplexRpcTransporter.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
<?php

declare(strict_types=1);
/**
* This file is part of friendsofhyperf/jet.
*
* @link https://github.com/friendsofhyperf/jet
* @document https://github.com/friendsofhyperf/jet/blob/main/README.md
* @contact huangdijia@gmail.com
*/

namespace FriendsOfHyperf\Jet\Transporter;

use Exception;
use FriendsOfHyperf\Jet\Exception\ConnectionException;
use FriendsOfHyperf\Jet\Exception\RecvFailedException;
use RuntimeException;

class MultiplexRpcTransporter extends StreamSocketTransporter
{
public const PING = 'ping';

public const PONG = 'pong';

public function receive()
{
stream_set_blocking($this->client, false);

while (true) {
$header = $this->readBytes(4);

$unpacked = unpack('Nlength', $header);
$length = $unpacked['length'];

if ($length < 4) {
throw new RecvFailedException(sprintf('Invalid package length: %d', $length));
}
$body = $this->readBytes($length);
Comment on lines +32 to +38

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add a maximum frame-size guard before reading the body.

Line 31 reads a peer-declared $length with no upper bound. A malicious or buggy peer can advertise a huge size and force excessive memory/read pressure before failure. Please reject frames above a protocol-safe max.

Suggested patch
 class MultiplexRpcTransporter extends StreamSocketTransporter
 {
     public const PING = 'ping';
     public const PONG = 'pong';
+    private const MAX_FRAME_LENGTH = 8 * 1024 * 1024; // adjust to protocol limit
@@
             $unpacked = unpack('Nlength', $header);
             $length = $unpacked['length'];

             if ($length < 4) {
                 throw new RecvFailedException(sprintf('Invalid package length: %d', $length));
             }
+            if ($length > self::MAX_FRAME_LENGTH) {
+                throw new RecvFailedException(sprintf('Package too large: %d', $length));
+            }
             $body = $this->readBytes($length);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
$unpacked = unpack('Nlength', $header);
$length = $unpacked['length'];
if ($length < 4) {
throw new RecvFailedException(sprintf('Invalid package length: %d', $length));
}
$body = $this->readBytes($length);
class MultiplexRpcTransporter extends StreamSocketTransporter
{
public const PING = 'ping';
public const PONG = 'pong';
private const MAX_FRAME_LENGTH = 8 * 1024 * 1024; // adjust to protocol limit
// ... other class members ...
// In the receive() method or equivalent:
$unpacked = unpack('Nlength', $header);
$length = $unpacked['length'];
if ($length < 4) {
throw new RecvFailedException(sprintf('Invalid package length: %d', $length));
}
if ($length > self::MAX_FRAME_LENGTH) {
throw new RecvFailedException(sprintf('Package too large: %d', $length));
}
$body = $this->readBytes($length);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/Transporter/MultiplexRpcTransporter.php` around lines 25 - 31, Add a
maximum frame-size validation check in the MultiplexRpcTransporter.php file
after unpacking the length and the existing check for length < 4. Before calling
readBytes with the $length value, add an additional condition that validates the
length does not exceed a protocol-safe maximum threshold. If the length exceeds
this maximum, throw a RecvFailedException with an appropriate error message
indicating the frame size is too large. This prevents malicious or buggy peers
from forcing excessive memory consumption by advertising unreasonably large
frame sizes.

if (in_array($body, [self::PING, self::PONG], true)) {
continue;
}

return $header . $body;
}
}

/**
* @throws Exception
*/
private function readBytes(int $length): string
{
$buffer = '';

while (strlen($buffer) < $length) {
$read = [$this->client];
$write = null;
$except = null;

$selected = stream_select($read, $write, $except, $this->timeout);
if ($selected === false) {
throw new RuntimeException('Failed to select stream.');
}

if ($selected === 0) {
throw new RecvFailedException('Receive timeout.');
}

foreach ($read as $stream) {
$chunk = fread($stream, $length - strlen($buffer));

if ($chunk === false) {
throw new RecvFailedException('Receive failed.');
}

if ($chunk === '' && feof($stream)) {
throw new ConnectionException('Connection was closed.');
}

$buffer .= $chunk;
}
}

return $buffer;
}
}
2 changes: 1 addition & 1 deletion src/Transporter/StreamSocketTransporter.php
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@
class StreamSocketTransporter extends AbstractTransporter
{
/**
* @var resource|null
* @var null|resource
*/
protected $client;

Expand Down