diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 3666cd47..b0005012 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -7,10 +7,11 @@ on: jobs: PHPUnit: name: PHPUnit (PHP ${{ matrix.php }}) - runs-on: ubuntu-22.04 + runs-on: ubuntu-24.04 strategy: matrix: php: + - 8.4 - 8.3 - 8.2 - 8.1 diff --git a/CHANGELOG.md b/CHANGELOG.md index f69779c6..07a4cc66 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,16 @@ # Changelog +## 1.11.0 (2024-11-20) + +* Feature: Improve PHP 8.4+ support by avoiding implicitly nullable types. + (#537 by @clue) + +* Feature: Allow underscore character in Uri host. + (#524 by @lulhum) + +* Improve test suite to fix expected error code when ext-sockets is not enabled. + (#539 by @WyriHaximus) + ## 1.10.0 (2024-03-27) * Feature: Add new PSR-7 implementation and remove dated RingCentral PSR-7 dependency. diff --git a/README.md b/README.md index d0550642..fd9ba46e 100644 --- a/README.md +++ b/README.md @@ -2986,7 +2986,7 @@ This project follows [SemVer](https://semver.org/). This will install the latest supported version: ```bash -composer require react/http:^1.10 +composer require react/http:^1.11 ``` See also the [CHANGELOG](CHANGELOG.md) for details about version upgrades. diff --git a/composer.json b/composer.json index 23783c0c..4234210a 100644 --- a/composer.json +++ b/composer.json @@ -31,18 +31,18 @@ "fig/http-message-util": "^1.1", "psr/http-message": "^1.0", "react/event-loop": "^1.2", - "react/promise": "^3 || ^2.3 || ^1.2.1", - "react/socket": "^1.12", - "react/stream": "^1.2" + "react/promise": "^3.2 || ^2.3 || ^1.2.1", + "react/socket": "^1.16", + "react/stream": "^1.4" }, "require-dev": { "clue/http-proxy-react": "^1.8", "clue/reactphp-ssh-proxy": "^1.4", "clue/socks-react": "^1.4", "phpunit/phpunit": "^9.6 || ^5.7 || ^4.8.36", - "react/async": "^4 || ^3 || ^2", + "react/async": "^4.2 || ^3 || ^2", "react/promise-stream": "^1.4", - "react/promise-timer": "^1.9" + "react/promise-timer": "^1.11" }, "autoload": { "psr-4": { diff --git a/src/Browser.php b/src/Browser.php index 01a266ca..9da0dcab 100644 --- a/src/Browser.php +++ b/src/Browser.php @@ -10,6 +10,7 @@ use React\Http\Message\Request; use React\Http\Message\Uri; use React\Promise\PromiseInterface; +use React\Socket\Connector; use React\Socket\ConnectorInterface; use React\Stream\ReadableStreamInterface; use InvalidArgumentException; @@ -88,7 +89,7 @@ public function __construct($connector = null, $loop = null) $loop = $loop ?: Loop::get(); $this->transaction = new Transaction( - Sender::createFromLoop($loop, $connector), + Sender::createFromLoop($loop, $connector ?: new Connector(array(), $loop)), $loop ); } diff --git a/src/Io/Sender.php b/src/Io/Sender.php index 1d563891..5f456b2f 100644 --- a/src/Io/Sender.php +++ b/src/Io/Sender.php @@ -8,7 +8,6 @@ use React\Http\Client\Client as HttpClient; use React\Promise\PromiseInterface; use React\Promise\Deferred; -use React\Socket\Connector; use React\Socket\ConnectorInterface; use React\Stream\ReadableStreamInterface; @@ -48,12 +47,8 @@ class Sender * @param ConnectorInterface|null $connector * @return self */ - public static function createFromLoop(LoopInterface $loop, ConnectorInterface $connector = null) + public static function createFromLoop(LoopInterface $loop, ConnectorInterface $connector) { - if ($connector === null) { - $connector = new Connector(array(), $loop); - } - return new self(new HttpClient(new ClientConnectionManager($connector, $loop))); } diff --git a/src/Message/Uri.php b/src/Message/Uri.php index 4309bbed..1eaf24fe 100644 --- a/src/Message/Uri.php +++ b/src/Message/Uri.php @@ -55,7 +55,7 @@ public function __construct($uri) } // @codeCoverageIgnoreEnd - if ($parts === false || (isset($parts['scheme']) && !\preg_match('#^[a-z]+$#i', $parts['scheme'])) || (isset($parts['host']) && \preg_match('#[\s_%+]#', $parts['host']))) { + if ($parts === false || (isset($parts['scheme']) && !\preg_match('#^[a-z]+$#i', $parts['scheme'])) || (isset($parts['host']) && \preg_match('#[\s%+]#', $parts['host']))) { throw new \InvalidArgumentException('Invalid URI given'); } @@ -173,7 +173,7 @@ public function withHost($host) return $this; } - if (\preg_match('#[\s_%+]#', $host) || ($host !== '' && \parse_url('http://' . $host, \PHP_URL_HOST) !== $host)) { + if (\preg_match('#[\s%+]#', $host) || ($host !== '' && \parse_url('http://' . $host, \PHP_URL_HOST) !== $host)) { throw new \InvalidArgumentException('Invalid URI host given'); } diff --git a/tests/FunctionalBrowserTest.php b/tests/FunctionalBrowserTest.php index 7b8ff84b..ef1b3936 100644 --- a/tests/FunctionalBrowserTest.php +++ b/tests/FunctionalBrowserTest.php @@ -366,7 +366,7 @@ public function testGetRequestWithResponseBufferExceededRejects() $this->setExpectedException( 'OverflowException', 'Response body size of 5 bytes exceeds maximum of 4 bytes', - defined('SOCKET_EMSGSIZE') ? SOCKET_EMSGSIZE : 0 + defined('SOCKET_EMSGSIZE') ? SOCKET_EMSGSIZE : 90 ); \React\Async\await($promise); } @@ -378,7 +378,7 @@ public function testGetRequestWithResponseBufferExceededDuringStreamingRejects() $this->setExpectedException( 'OverflowException', 'Response body size exceeds maximum of 4 bytes', - defined('SOCKET_EMSGSIZE') ? SOCKET_EMSGSIZE : 0 + defined('SOCKET_EMSGSIZE') ? SOCKET_EMSGSIZE : 90 ); \React\Async\await($promise); } diff --git a/tests/Io/SenderTest.php b/tests/Io/SenderTest.php index 03a9b56e..a65b13b3 100644 --- a/tests/Io/SenderTest.php +++ b/tests/Io/SenderTest.php @@ -28,7 +28,9 @@ public function setUpLoop() public function testCreateFromLoop() { - $sender = Sender::createFromLoop($this->loop, null); + $connector = $this->getMockBuilder('React\Socket\ConnectorInterface')->getMock(); + + $sender = Sender::createFromLoop($this->loop, $connector); $this->assertInstanceOf('React\Http\Io\Sender', $sender); } diff --git a/tests/Io/StreamingServerTest.php b/tests/Io/StreamingServerTest.php index b4e3f2f8..b1410fad 100644 --- a/tests/Io/StreamingServerTest.php +++ b/tests/Io/StreamingServerTest.php @@ -32,7 +32,7 @@ public function setUpConnectionMockAndSocket() } - private function mockConnection(array $additionalMethods = null) + private function mockConnection(array $additionalMethods = array()) { $connection = $this->getMockBuilder('React\Socket\Connection') ->disableOriginalConstructor() @@ -49,7 +49,7 @@ private function mockConnection(array $additionalMethods = null) 'getLocalAddress', 'pipe' ), - (is_array($additionalMethods) ? $additionalMethods : array()) + $additionalMethods )) ->getMock(); diff --git a/tests/Message/UriTest.php b/tests/Message/UriTest.php index 05eec723..cc4b16f1 100644 --- a/tests/Message/UriTest.php +++ b/tests/Message/UriTest.php @@ -120,6 +120,9 @@ public static function provideValidUris() ), array( 'http://user%20name:pass%20word@localhost/path%20name?query%20name#frag%20ment' + ), + array( + 'http://docker_container/' ) ); } @@ -338,6 +341,16 @@ public function testWithHostReturnsNewInstanceWhenHostIsChanged() $this->assertEquals('localhost', $uri->getHost()); } + public function testWithHostReturnsNewInstanceWhenHostIsChangedWithUnderscore() + { + $uri = new Uri('http://localhost'); + + $new = $uri->withHost('docker_container'); + $this->assertNotSame($uri, $new); + $this->assertEquals('docker_container', $new->getHost()); + $this->assertEquals('localhost', $uri->getHost()); + } + public function testWithHostReturnsNewInstanceWithHostToLowerCaseWhenHostIsChangedWithUpperCase() { $uri = new Uri('http://localhost');