Upgrade the composer dependencies
authorAlexander Ebert <ebert@woltlab.com>
Wed, 7 Aug 2024 12:36:00 +0000 (14:36 +0200)
committerAlexander Ebert <ebert@woltlab.com>
Wed, 7 Aug 2024 12:36:00 +0000 (14:36 +0200)
63 files changed:
wcfsetup/install/files/lib/system/api/composer.json
wcfsetup/install/files/lib/system/api/composer.lock
wcfsetup/install/files/lib/system/api/composer/autoload_psr4.php
wcfsetup/install/files/lib/system/api/composer/autoload_static.php
wcfsetup/install/files/lib/system/api/composer/installed.json
wcfsetup/install/files/lib/system/api/composer/installed.php
wcfsetup/install/files/lib/system/api/guzzlehttp/guzzle/CHANGELOG.md
wcfsetup/install/files/lib/system/api/guzzlehttp/guzzle/README.md
wcfsetup/install/files/lib/system/api/guzzlehttp/guzzle/composer.json
wcfsetup/install/files/lib/system/api/guzzlehttp/guzzle/src/BodySummarizer.php
wcfsetup/install/files/lib/system/api/guzzlehttp/guzzle/src/Client.php
wcfsetup/install/files/lib/system/api/guzzlehttp/guzzle/src/ClientInterface.php
wcfsetup/install/files/lib/system/api/guzzlehttp/guzzle/src/Cookie/CookieJar.php
wcfsetup/install/files/lib/system/api/guzzlehttp/guzzle/src/Cookie/CookieJarInterface.php
wcfsetup/install/files/lib/system/api/guzzlehttp/guzzle/src/Exception/BadResponseException.php
wcfsetup/install/files/lib/system/api/guzzlehttp/guzzle/src/Exception/ConnectException.php
wcfsetup/install/files/lib/system/api/guzzlehttp/guzzle/src/Exception/RequestException.php
wcfsetup/install/files/lib/system/api/guzzlehttp/guzzle/src/Handler/CurlFactory.php
wcfsetup/install/files/lib/system/api/guzzlehttp/guzzle/src/Handler/CurlMultiHandler.php
wcfsetup/install/files/lib/system/api/guzzlehttp/guzzle/src/Handler/MockHandler.php
wcfsetup/install/files/lib/system/api/guzzlehttp/guzzle/src/Handler/StreamHandler.php
wcfsetup/install/files/lib/system/api/guzzlehttp/guzzle/src/HandlerStack.php
wcfsetup/install/files/lib/system/api/guzzlehttp/guzzle/src/MessageFormatter.php
wcfsetup/install/files/lib/system/api/guzzlehttp/guzzle/src/MessageFormatterInterface.php
wcfsetup/install/files/lib/system/api/guzzlehttp/guzzle/src/Middleware.php
wcfsetup/install/files/lib/system/api/guzzlehttp/guzzle/src/PrepareBodyMiddleware.php
wcfsetup/install/files/lib/system/api/guzzlehttp/guzzle/src/RequestOptions.php
wcfsetup/install/files/lib/system/api/guzzlehttp/guzzle/src/RetryMiddleware.php
wcfsetup/install/files/lib/system/api/guzzlehttp/guzzle/src/TransferStats.php
wcfsetup/install/files/lib/system/api/guzzlehttp/guzzle/src/Utils.php
wcfsetup/install/files/lib/system/api/guzzlehttp/promises/CHANGELOG.md
wcfsetup/install/files/lib/system/api/guzzlehttp/promises/README.md
wcfsetup/install/files/lib/system/api/guzzlehttp/promises/composer.json
wcfsetup/install/files/lib/system/api/guzzlehttp/promises/src/Coroutine.php
wcfsetup/install/files/lib/system/api/guzzlehttp/promises/src/Each.php
wcfsetup/install/files/lib/system/api/guzzlehttp/promises/src/FulfilledPromise.php
wcfsetup/install/files/lib/system/api/guzzlehttp/promises/src/Promise.php
wcfsetup/install/files/lib/system/api/guzzlehttp/promises/src/PromiseInterface.php
wcfsetup/install/files/lib/system/api/guzzlehttp/promises/src/RejectedPromise.php
wcfsetup/install/files/lib/system/api/guzzlehttp/promises/src/RejectionException.php
wcfsetup/install/files/lib/system/api/guzzlehttp/promises/src/Utils.php
wcfsetup/install/files/lib/system/api/guzzlehttp/psr7/CHANGELOG.md
wcfsetup/install/files/lib/system/api/guzzlehttp/psr7/README.md
wcfsetup/install/files/lib/system/api/guzzlehttp/psr7/composer.json
wcfsetup/install/files/lib/system/api/guzzlehttp/psr7/src/CachingStream.php
wcfsetup/install/files/lib/system/api/guzzlehttp/psr7/src/HttpFactory.php
wcfsetup/install/files/lib/system/api/guzzlehttp/psr7/src/MultipartStream.php
wcfsetup/install/files/lib/system/api/guzzlehttp/psr7/src/Query.php
wcfsetup/install/files/lib/system/api/guzzlehttp/psr7/src/Response.php
wcfsetup/install/files/lib/system/api/guzzlehttp/psr7/src/StreamWrapper.php
wcfsetup/install/files/lib/system/api/guzzlehttp/psr7/src/UploadedFile.php
wcfsetup/install/files/lib/system/api/guzzlehttp/psr7/src/Uri.php
wcfsetup/install/files/lib/system/api/guzzlehttp/psr7/src/Utils.php
wcfsetup/install/files/lib/system/api/sabberworm/php-css-parser/CHANGELOG.md
wcfsetup/install/files/lib/system/api/sabberworm/php-css-parser/src/CSSList/CSSList.php
wcfsetup/install/files/lib/system/api/sabberworm/php-css-parser/src/Parsing/ParserState.php
wcfsetup/install/files/lib/system/api/sabberworm/php-css-parser/src/Property/AtRule.php
wcfsetup/install/files/lib/system/api/sabberworm/php-css-parser/src/Property/KeyframeSelector.php
wcfsetup/install/files/lib/system/api/sabberworm/php-css-parser/src/Property/Selector.php
wcfsetup/install/files/lib/system/api/sabberworm/php-css-parser/src/Value/CalcFunction.php
wcfsetup/install/files/lib/system/api/sabberworm/php-css-parser/src/Value/Color.php
wcfsetup/install/files/lib/system/api/sabberworm/php-css-parser/src/Value/Size.php
wcfsetup/install/files/lib/system/api/sabberworm/php-css-parser/src/Value/Value.php

index 0bd94e0b67591289b8d78089d884607b1916e832..42a9e5c36083c14cb6b64bb719eeb23366aa63a7 100644 (file)
@@ -14,8 +14,8 @@
         "dragonmantank/cron-expression": "^3.3.3",
         "erusev/parsedown": "^1.7.4",
         "ezyang/htmlpurifier": "^4.17",
-        "guzzlehttp/guzzle": "^7.8.1",
-        "guzzlehttp/psr7": "^2.6.2",
+        "guzzlehttp/guzzle": "^7.9.2",
+        "guzzlehttp/psr7": "^2.7.0",
         "laminas/laminas-diactoros": "^3.3.1",
         "laminas/laminas-httphandlerrunner": "^2.10.0",
         "laminas/laminas-progressbar": "^2.13",
index 1de7f76c90332dac26982003c55b6da58140d70d..a7431c19f39170b1211ff3a5bc3125267d974ea5 100644 (file)
@@ -4,7 +4,7 @@
         "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
         "This file is @generated automatically"
     ],
-    "content-hash": "f252359a254921f59dc57b78f2c04059",
+    "content-hash": "2c277af11fe355813745d14d0db85a20",
     "packages": [
         {
             "name": "cuyz/valinor",
         },
         {
             "name": "guzzlehttp/guzzle",
-            "version": "7.8.1",
+            "version": "7.9.2",
             "source": {
                 "type": "git",
                 "url": "https://github.com/guzzle/guzzle.git",
-                "reference": "41042bc7ab002487b876a0683fc8dce04ddce104"
+                "reference": "d281ed313b989f213357e3be1a179f02196ac99b"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/guzzle/guzzle/zipball/41042bc7ab002487b876a0683fc8dce04ddce104",
-                "reference": "41042bc7ab002487b876a0683fc8dce04ddce104",
+                "url": "https://api.github.com/repos/guzzle/guzzle/zipball/d281ed313b989f213357e3be1a179f02196ac99b",
+                "reference": "d281ed313b989f213357e3be1a179f02196ac99b",
                 "shasum": ""
             },
             "require": {
                 "ext-json": "*",
-                "guzzlehttp/promises": "^1.5.3 || ^2.0.1",
-                "guzzlehttp/psr7": "^1.9.1 || ^2.5.1",
+                "guzzlehttp/promises": "^1.5.3 || ^2.0.3",
+                "guzzlehttp/psr7": "^2.7.0",
                 "php": "^7.2.5 || ^8.0",
                 "psr/http-client": "^1.0",
                 "symfony/deprecation-contracts": "^2.2 || ^3.0"
             "require-dev": {
                 "bamarni/composer-bin-plugin": "^1.8.2",
                 "ext-curl": "*",
-                "php-http/client-integration-tests": "dev-master#2c025848417c1135031fdf9c728ee53d0a7ceaee as 3.0.999",
+                "guzzle/client-integration-tests": "3.0.2",
                 "php-http/message-factory": "^1.1",
-                "phpunit/phpunit": "^8.5.36 || ^9.6.15",
+                "phpunit/phpunit": "^8.5.39 || ^9.6.20",
                 "psr/log": "^1.1 || ^2.0 || ^3.0"
             },
             "suggest": {
             ],
             "support": {
                 "issues": "https://github.com/guzzle/guzzle/issues",
-                "source": "https://github.com/guzzle/guzzle/tree/7.8.1"
+                "source": "https://github.com/guzzle/guzzle/tree/7.9.2"
             },
             "funding": [
                 {
                     "type": "tidelift"
                 }
             ],
-            "time": "2023-12-03T20:35:24+00:00"
+            "time": "2024-07-24T11:22:20+00:00"
         },
         {
             "name": "guzzlehttp/promises",
-            "version": "2.0.2",
+            "version": "2.0.3",
             "source": {
                 "type": "git",
                 "url": "https://github.com/guzzle/promises.git",
-                "reference": "bbff78d96034045e58e13dedd6ad91b5d1253223"
+                "reference": "6ea8dd08867a2a42619d65c3deb2c0fcbf81c8f8"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/guzzle/promises/zipball/bbff78d96034045e58e13dedd6ad91b5d1253223",
-                "reference": "bbff78d96034045e58e13dedd6ad91b5d1253223",
+                "url": "https://api.github.com/repos/guzzle/promises/zipball/6ea8dd08867a2a42619d65c3deb2c0fcbf81c8f8",
+                "reference": "6ea8dd08867a2a42619d65c3deb2c0fcbf81c8f8",
                 "shasum": ""
             },
             "require": {
             },
             "require-dev": {
                 "bamarni/composer-bin-plugin": "^1.8.2",
-                "phpunit/phpunit": "^8.5.36 || ^9.6.15"
+                "phpunit/phpunit": "^8.5.39 || ^9.6.20"
             },
             "type": "library",
             "extra": {
             ],
             "support": {
                 "issues": "https://github.com/guzzle/promises/issues",
-                "source": "https://github.com/guzzle/promises/tree/2.0.2"
+                "source": "https://github.com/guzzle/promises/tree/2.0.3"
             },
             "funding": [
                 {
                     "type": "tidelift"
                 }
             ],
-            "time": "2023-12-03T20:19:20+00:00"
+            "time": "2024-07-18T10:29:17+00:00"
         },
         {
             "name": "guzzlehttp/psr7",
-            "version": "2.6.2",
+            "version": "2.7.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/guzzle/psr7.git",
-                "reference": "45b30f99ac27b5ca93cb4831afe16285f57b8221"
+                "reference": "a70f5c95fb43bc83f07c9c948baa0dc1829bf201"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/guzzle/psr7/zipball/45b30f99ac27b5ca93cb4831afe16285f57b8221",
-                "reference": "45b30f99ac27b5ca93cb4831afe16285f57b8221",
+                "url": "https://api.github.com/repos/guzzle/psr7/zipball/a70f5c95fb43bc83f07c9c948baa0dc1829bf201",
+                "reference": "a70f5c95fb43bc83f07c9c948baa0dc1829bf201",
                 "shasum": ""
             },
             "require": {
             },
             "require-dev": {
                 "bamarni/composer-bin-plugin": "^1.8.2",
-                "http-interop/http-factory-tests": "^0.9",
-                "phpunit/phpunit": "^8.5.36 || ^9.6.15"
+                "http-interop/http-factory-tests": "0.9.0",
+                "phpunit/phpunit": "^8.5.39 || ^9.6.20"
             },
             "suggest": {
                 "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses"
             ],
             "support": {
                 "issues": "https://github.com/guzzle/psr7/issues",
-                "source": "https://github.com/guzzle/psr7/tree/2.6.2"
+                "source": "https://github.com/guzzle/psr7/tree/2.7.0"
             },
             "funding": [
                 {
                     "type": "tidelift"
                 }
             ],
-            "time": "2023-12-03T20:05:35+00:00"
+            "time": "2024-07-18T11:15:46+00:00"
         },
         {
             "name": "laminas/laminas-diactoros",
         },
         {
             "name": "sabberworm/php-css-parser",
-            "version": "v8.5.1",
+            "version": "v8.6.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/MyIntervals/PHP-CSS-Parser.git",
-                "reference": "4a3d572b0f8b28bb6fd016ae8bbfc445facef152"
+                "reference": "d2fb94a9641be84d79c7548c6d39bbebba6e9a70"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/MyIntervals/PHP-CSS-Parser/zipball/4a3d572b0f8b28bb6fd016ae8bbfc445facef152",
-                "reference": "4a3d572b0f8b28bb6fd016ae8bbfc445facef152",
+                "url": "https://api.github.com/repos/MyIntervals/PHP-CSS-Parser/zipball/d2fb94a9641be84d79c7548c6d39bbebba6e9a70",
+                "reference": "d2fb94a9641be84d79c7548c6d39bbebba6e9a70",
                 "shasum": ""
             },
             "require": {
             ],
             "support": {
                 "issues": "https://github.com/MyIntervals/PHP-CSS-Parser/issues",
-                "source": "https://github.com/MyIntervals/PHP-CSS-Parser/tree/v8.5.1"
+                "source": "https://github.com/MyIntervals/PHP-CSS-Parser/tree/v8.6.0"
             },
-            "time": "2024-02-15T16:41:13+00:00"
+            "time": "2024-07-01T07:33:21+00:00"
         },
         {
             "name": "scssphp/scssphp",
index b75b3a32f0127f67df82742fafb47871215b4b5a..78f3e785330a4caa0215d03a014371acb95d9762 100644 (file)
@@ -15,7 +15,7 @@ return array(
     'Psr\\SimpleCache\\' => array($vendorDir . '/psr/simple-cache/src'),
     'Psr\\Log\\' => array($vendorDir . '/psr/log/src'),
     'Psr\\Http\\Server\\' => array($vendorDir . '/psr/http-server-handler/src', $vendorDir . '/psr/http-server-middleware/src'),
-    'Psr\\Http\\Message\\' => array($vendorDir . '/psr/http-message/src', $vendorDir . '/psr/http-factory/src'),
+    'Psr\\Http\\Message\\' => array($vendorDir . '/psr/http-factory/src', $vendorDir . '/psr/http-message/src'),
     'Psr\\Http\\Client\\' => array($vendorDir . '/psr/http-client/src'),
     'Psr\\EventDispatcher\\' => array($vendorDir . '/psr/event-dispatcher/src'),
     'Psr\\Clock\\' => array($vendorDir . '/psr/clock/src'),
index db46c9c43c2c5d5e3d8c54e89e07a187e0824cc0..c987c54178cb148b6a708383a4c858da88f54139 100644 (file)
@@ -111,8 +111,8 @@ class ComposerStaticInita1f5f7c74275d47a45049a2936db1d0d
         ),
         'Psr\\Http\\Message\\' => 
         array (
-            0 => __DIR__ . '/..' . '/psr/http-message/src',
-            1 => __DIR__ . '/..' . '/psr/http-factory/src',
+            0 => __DIR__ . '/..' . '/psr/http-factory/src',
+            1 => __DIR__ . '/..' . '/psr/http-message/src',
         ),
         'Psr\\Http\\Client\\' => 
         array (
index e12181b6a627f38fe70f60f202a2a3af36a772ac..1e0b8c79a6a04ae94387a7731ba3b2222c8eeb24 100644 (file)
         },
         {
             "name": "guzzlehttp/guzzle",
-            "version": "7.8.1",
-            "version_normalized": "7.8.1.0",
+            "version": "7.9.2",
+            "version_normalized": "7.9.2.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/guzzle/guzzle.git",
-                "reference": "41042bc7ab002487b876a0683fc8dce04ddce104"
+                "reference": "d281ed313b989f213357e3be1a179f02196ac99b"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/guzzle/guzzle/zipball/41042bc7ab002487b876a0683fc8dce04ddce104",
-                "reference": "41042bc7ab002487b876a0683fc8dce04ddce104",
+                "url": "https://api.github.com/repos/guzzle/guzzle/zipball/d281ed313b989f213357e3be1a179f02196ac99b",
+                "reference": "d281ed313b989f213357e3be1a179f02196ac99b",
                 "shasum": ""
             },
             "require": {
                 "ext-json": "*",
-                "guzzlehttp/promises": "^1.5.3 || ^2.0.1",
-                "guzzlehttp/psr7": "^1.9.1 || ^2.5.1",
+                "guzzlehttp/promises": "^1.5.3 || ^2.0.3",
+                "guzzlehttp/psr7": "^2.7.0",
                 "php": "^7.2.5 || ^8.0",
                 "psr/http-client": "^1.0",
                 "symfony/deprecation-contracts": "^2.2 || ^3.0"
             "require-dev": {
                 "bamarni/composer-bin-plugin": "^1.8.2",
                 "ext-curl": "*",
-                "php-http/client-integration-tests": "dev-master#2c025848417c1135031fdf9c728ee53d0a7ceaee as 3.0.999",
+                "guzzle/client-integration-tests": "3.0.2",
                 "php-http/message-factory": "^1.1",
-                "phpunit/phpunit": "^8.5.36 || ^9.6.15",
+                "phpunit/phpunit": "^8.5.39 || ^9.6.20",
                 "psr/log": "^1.1 || ^2.0 || ^3.0"
             },
             "suggest": {
                 "ext-intl": "Required for Internationalized Domain Name (IDN) support",
                 "psr/log": "Required for using the Log middleware"
             },
-            "time": "2023-12-03T20:35:24+00:00",
+            "time": "2024-07-24T11:22:20+00:00",
             "type": "library",
             "extra": {
                 "bamarni-bin": {
             ],
             "support": {
                 "issues": "https://github.com/guzzle/guzzle/issues",
-                "source": "https://github.com/guzzle/guzzle/tree/7.8.1"
+                "source": "https://github.com/guzzle/guzzle/tree/7.9.2"
             },
             "funding": [
                 {
         },
         {
             "name": "guzzlehttp/promises",
-            "version": "2.0.2",
-            "version_normalized": "2.0.2.0",
+            "version": "2.0.3",
+            "version_normalized": "2.0.3.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/guzzle/promises.git",
-                "reference": "bbff78d96034045e58e13dedd6ad91b5d1253223"
+                "reference": "6ea8dd08867a2a42619d65c3deb2c0fcbf81c8f8"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/guzzle/promises/zipball/bbff78d96034045e58e13dedd6ad91b5d1253223",
-                "reference": "bbff78d96034045e58e13dedd6ad91b5d1253223",
+                "url": "https://api.github.com/repos/guzzle/promises/zipball/6ea8dd08867a2a42619d65c3deb2c0fcbf81c8f8",
+                "reference": "6ea8dd08867a2a42619d65c3deb2c0fcbf81c8f8",
                 "shasum": ""
             },
             "require": {
             },
             "require-dev": {
                 "bamarni/composer-bin-plugin": "^1.8.2",
-                "phpunit/phpunit": "^8.5.36 || ^9.6.15"
+                "phpunit/phpunit": "^8.5.39 || ^9.6.20"
             },
-            "time": "2023-12-03T20:19:20+00:00",
+            "time": "2024-07-18T10:29:17+00:00",
             "type": "library",
             "extra": {
                 "bamarni-bin": {
             ],
             "support": {
                 "issues": "https://github.com/guzzle/promises/issues",
-                "source": "https://github.com/guzzle/promises/tree/2.0.2"
+                "source": "https://github.com/guzzle/promises/tree/2.0.3"
             },
             "funding": [
                 {
         },
         {
             "name": "guzzlehttp/psr7",
-            "version": "2.6.2",
-            "version_normalized": "2.6.2.0",
+            "version": "2.7.0",
+            "version_normalized": "2.7.0.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/guzzle/psr7.git",
-                "reference": "45b30f99ac27b5ca93cb4831afe16285f57b8221"
+                "reference": "a70f5c95fb43bc83f07c9c948baa0dc1829bf201"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/guzzle/psr7/zipball/45b30f99ac27b5ca93cb4831afe16285f57b8221",
-                "reference": "45b30f99ac27b5ca93cb4831afe16285f57b8221",
+                "url": "https://api.github.com/repos/guzzle/psr7/zipball/a70f5c95fb43bc83f07c9c948baa0dc1829bf201",
+                "reference": "a70f5c95fb43bc83f07c9c948baa0dc1829bf201",
                 "shasum": ""
             },
             "require": {
             },
             "require-dev": {
                 "bamarni/composer-bin-plugin": "^1.8.2",
-                "http-interop/http-factory-tests": "^0.9",
-                "phpunit/phpunit": "^8.5.36 || ^9.6.15"
+                "http-interop/http-factory-tests": "0.9.0",
+                "phpunit/phpunit": "^8.5.39 || ^9.6.20"
             },
             "suggest": {
                 "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses"
             },
-            "time": "2023-12-03T20:05:35+00:00",
+            "time": "2024-07-18T11:15:46+00:00",
             "type": "library",
             "extra": {
                 "bamarni-bin": {
             ],
             "support": {
                 "issues": "https://github.com/guzzle/psr7/issues",
-                "source": "https://github.com/guzzle/psr7/tree/2.6.2"
+                "source": "https://github.com/guzzle/psr7/tree/2.7.0"
             },
             "funding": [
                 {
         },
         {
             "name": "sabberworm/php-css-parser",
-            "version": "v8.5.1",
-            "version_normalized": "8.5.1.0",
+            "version": "v8.6.0",
+            "version_normalized": "8.6.0.0",
             "source": {
                 "type": "git",
                 "url": "https://github.com/MyIntervals/PHP-CSS-Parser.git",
-                "reference": "4a3d572b0f8b28bb6fd016ae8bbfc445facef152"
+                "reference": "d2fb94a9641be84d79c7548c6d39bbebba6e9a70"
             },
             "dist": {
                 "type": "zip",
-                "url": "https://api.github.com/repos/MyIntervals/PHP-CSS-Parser/zipball/4a3d572b0f8b28bb6fd016ae8bbfc445facef152",
-                "reference": "4a3d572b0f8b28bb6fd016ae8bbfc445facef152",
+                "url": "https://api.github.com/repos/MyIntervals/PHP-CSS-Parser/zipball/d2fb94a9641be84d79c7548c6d39bbebba6e9a70",
+                "reference": "d2fb94a9641be84d79c7548c6d39bbebba6e9a70",
                 "shasum": ""
             },
             "require": {
             "suggest": {
                 "ext-mbstring": "for parsing UTF-8 CSS"
             },
-            "time": "2024-02-15T16:41:13+00:00",
+            "time": "2024-07-01T07:33:21+00:00",
             "type": "library",
             "extra": {
                 "branch-alias": {
             ],
             "support": {
                 "issues": "https://github.com/MyIntervals/PHP-CSS-Parser/issues",
-                "source": "https://github.com/MyIntervals/PHP-CSS-Parser/tree/v8.5.1"
+                "source": "https://github.com/MyIntervals/PHP-CSS-Parser/tree/v8.6.0"
             },
             "install-path": "../sabberworm/php-css-parser"
         },
index dc64a679aaebe12c9e032a103ae7fa573461039b..56f16ba31160c08e8ab72337f0bf4b283694a4e1 100644 (file)
@@ -3,7 +3,7 @@
         'name' => '__root__',
         'pretty_version' => '6.0.x-dev',
         'version' => '6.0.9999999.9999999-dev',
-        'reference' => '284adc7603f0e4cc0733ad4011c123c12ffa6e3a',
+        'reference' => '415af88f6254b5e2467702489eb4e03e0e43104c',
         'type' => 'project',
         'install_path' => __DIR__ . '/../',
         'aliases' => array(),
@@ -13,7 +13,7 @@
         '__root__' => array(
             'pretty_version' => '6.0.x-dev',
             'version' => '6.0.9999999.9999999-dev',
-            'reference' => '284adc7603f0e4cc0733ad4011c123c12ffa6e3a',
+            'reference' => '415af88f6254b5e2467702489eb4e03e0e43104c',
             'type' => 'project',
             'install_path' => __DIR__ . '/../',
             'aliases' => array(),
             'dev_requirement' => false,
         ),
         'guzzlehttp/guzzle' => array(
-            'pretty_version' => '7.8.1',
-            'version' => '7.8.1.0',
-            'reference' => '41042bc7ab002487b876a0683fc8dce04ddce104',
+            'pretty_version' => '7.9.2',
+            'version' => '7.9.2.0',
+            'reference' => 'd281ed313b989f213357e3be1a179f02196ac99b',
             'type' => 'library',
             'install_path' => __DIR__ . '/../guzzlehttp/guzzle',
             'aliases' => array(),
             'dev_requirement' => false,
         ),
         'guzzlehttp/promises' => array(
-            'pretty_version' => '2.0.2',
-            'version' => '2.0.2.0',
-            'reference' => 'bbff78d96034045e58e13dedd6ad91b5d1253223',
+            'pretty_version' => '2.0.3',
+            'version' => '2.0.3.0',
+            'reference' => '6ea8dd08867a2a42619d65c3deb2c0fcbf81c8f8',
             'type' => 'library',
             'install_path' => __DIR__ . '/../guzzlehttp/promises',
             'aliases' => array(),
             'dev_requirement' => false,
         ),
         'guzzlehttp/psr7' => array(
-            'pretty_version' => '2.6.2',
-            'version' => '2.6.2.0',
-            'reference' => '45b30f99ac27b5ca93cb4831afe16285f57b8221',
+            'pretty_version' => '2.7.0',
+            'version' => '2.7.0.0',
+            'reference' => 'a70f5c95fb43bc83f07c9c948baa0dc1829bf201',
             'type' => 'library',
             'install_path' => __DIR__ . '/../guzzlehttp/psr7',
             'aliases' => array(),
         'psr/http-factory-implementation' => array(
             'dev_requirement' => false,
             'provided' => array(
-                0 => '1.0',
-                1 => '^1.1 || ^2.0',
+                0 => '^1.1 || ^2.0',
+                1 => '1.0',
             ),
         ),
         'psr/http-message' => array(
         'psr/http-message-implementation' => array(
             'dev_requirement' => false,
             'provided' => array(
-                0 => '1.0',
-                1 => '^1.1 || ^2.0',
+                0 => '^1.1 || ^2.0',
+                1 => '1.0',
             ),
         ),
         'psr/http-server-handler' => array(
             'dev_requirement' => false,
         ),
         'sabberworm/php-css-parser' => array(
-            'pretty_version' => 'v8.5.1',
-            'version' => '8.5.1.0',
-            'reference' => '4a3d572b0f8b28bb6fd016ae8bbfc445facef152',
+            'pretty_version' => 'v8.6.0',
+            'version' => '8.6.0.0',
+            'reference' => 'd2fb94a9641be84d79c7548c6d39bbebba6e9a70',
             'type' => 'library',
             'install_path' => __DIR__ . '/../sabberworm/php-css-parser',
             'aliases' => array(),
index 13709d1b8a3ac90db759e89a2f1031b31dc33b70..e0b6216598a18cbb849d6608c40525c8b2065b7e 100644 (file)
@@ -3,6 +3,37 @@
 Please refer to [UPGRADING](UPGRADING.md) guide for upgrading to a major version.
 
 
+## 7.9.2 - 2024-07-24
+
+### Fixed
+
+- Adjusted handler selection to use cURL if its version is 7.21.2 or higher, rather than 7.34.0
+
+
+## 7.9.1 - 2024-07-19
+
+### Fixed
+
+- Fix TLS 1.3 check for HTTP/2 requests
+
+
+## 7.9.0 - 2024-07-18
+
+### Changed
+
+- Improve protocol version checks to provide feedback around unsupported protocols
+- Only select the cURL handler by default if 7.34.0 or higher is linked
+- Improved `CurlMultiHandler` to avoid busy wait if possible
+- Dropped support for EOL `guzzlehttp/psr7` v1
+- Improved URI user info redaction in errors
+
+## 7.8.2 - 2024-07-18
+
+### Added
+
+- Support for PHP 8.4
+
+
 ## 7.8.1 - 2023-12-03
 
 ### Changed
index 6d78a9309c5fb92bae2e0339002e4875d32702ca..cdaebee3ff98f2acceb8f7acb8be23126d399994 100644 (file)
@@ -62,11 +62,11 @@ composer require guzzlehttp/guzzle
 
 | Version | Status              | Packagist           | Namespace    | Repo                | Docs                | PSR-7 | PHP Version  |
 |---------|---------------------|---------------------|--------------|---------------------|---------------------|-------|--------------|
-| 3.x     | EOL                 | `guzzle/guzzle`     | `Guzzle`     | [v3][guzzle-3-repo] | [v3][guzzle-3-docs] | No    | >=5.3.3,<7.0 |
-| 4.x     | EOL                 | `guzzlehttp/guzzle` | `GuzzleHttp` | [v4][guzzle-4-repo] | N/A                 | No    | >=5.4,<7.0   |
-| 5.x     | EOL                 | `guzzlehttp/guzzle` | `GuzzleHttp` | [v5][guzzle-5-repo] | [v5][guzzle-5-docs] | No    | >=5.4,<7.4   |
-| 6.x     | Security fixes only | `guzzlehttp/guzzle` | `GuzzleHttp` | [v6][guzzle-6-repo] | [v6][guzzle-6-docs] | Yes   | >=5.5,<8.0   |
-| 7.x     | Latest              | `guzzlehttp/guzzle` | `GuzzleHttp` | [v7][guzzle-7-repo] | [v7][guzzle-7-docs] | Yes   | >=7.2.5,<8.4 |
+| 3.x     | EOL (2016-10-31)    | `guzzle/guzzle`     | `Guzzle`     | [v3][guzzle-3-repo] | [v3][guzzle-3-docs] | No    | >=5.3.3,<7.0 |
+| 4.x     | EOL (2016-10-31)    | `guzzlehttp/guzzle` | `GuzzleHttp` | [v4][guzzle-4-repo] | N/A                 | No    | >=5.4,<7.0   |
+| 5.x     | EOL (2019-10-31)    | `guzzlehttp/guzzle` | `GuzzleHttp` | [v5][guzzle-5-repo] | [v5][guzzle-5-docs] | No    | >=5.4,<7.4   |
+| 6.x     | EOL (2023-10-31)    | `guzzlehttp/guzzle` | `GuzzleHttp` | [v6][guzzle-6-repo] | [v6][guzzle-6-docs] | Yes   | >=5.5,<8.0   |
+| 7.x     | Latest              | `guzzlehttp/guzzle` | `GuzzleHttp` | [v7][guzzle-7-repo] | [v7][guzzle-7-docs] | Yes   | >=7.2.5,<8.5 |
 
 [guzzle-3-repo]: https://github.com/guzzle/guzzle3
 [guzzle-4-repo]: https://github.com/guzzle/guzzle/tree/4.x
index 69583d7cc2329efd8c0de38aa4838c077297c361..cbede149ac0bdf72f0412e7f3eb4882beef592c2 100644 (file)
             "homepage": "https://github.com/Tobion"
         }
     ],
+    "repositories": [
+        {
+            "type": "package",
+            "package": {
+                "name": "guzzle/client-integration-tests",
+                "version": "v3.0.2",
+                "dist": {
+                    "url": "https://codeload.github.com/guzzle/client-integration-tests/zip/2c025848417c1135031fdf9c728ee53d0a7ceaee",
+                    "type": "zip"
+                },
+                "require": {
+                    "php": "^7.2.5 || ^8.0",
+                    "phpunit/phpunit": "^7.5.20 || ^8.5.8 || ^9.3.11",
+                    "php-http/message": "^1.0 || ^2.0",
+                    "guzzlehttp/psr7": "^1.7 || ^2.0",
+                    "th3n3rd/cartesian-product": "^0.3"
+                },
+                "autoload": {
+                    "psr-4": {
+                        "Http\\Client\\Tests\\": "src/"
+                    }
+                },
+                "bin": [
+                    "bin/http_test_server"
+                ]
+            }
+        }
+    ],
     "require": {
         "php": "^7.2.5 || ^8.0",
         "ext-json": "*",
-        "guzzlehttp/promises": "^1.5.3 || ^2.0.1",
-        "guzzlehttp/psr7": "^1.9.1 || ^2.5.1",
+        "guzzlehttp/promises": "^1.5.3 || ^2.0.3",
+        "guzzlehttp/psr7": "^2.7.0",
         "psr/http-client": "^1.0",
         "symfony/deprecation-contracts": "^2.2 || ^3.0"
     },
@@ -64,9 +92,9 @@
     "require-dev": {
         "ext-curl": "*",
         "bamarni/composer-bin-plugin": "^1.8.2",
-        "php-http/client-integration-tests": "dev-master#2c025848417c1135031fdf9c728ee53d0a7ceaee as 3.0.999",
+        "guzzle/client-integration-tests": "3.0.2",
         "php-http/message-factory": "^1.1",
-        "phpunit/phpunit": "^8.5.36 || ^9.6.15",
+        "phpunit/phpunit": "^8.5.39 || ^9.6.20",
         "psr/log": "^1.1 || ^2.0 || ^3.0"
     },
     "suggest": {
index 6eca94ef97a97f051fa5458cde2f1e7a2bd65316..761506dd07029080d4ed81b597253090f5c672bb 100644 (file)
@@ -11,7 +11,7 @@ final class BodySummarizer implements BodySummarizerInterface
      */
     private $truncateAt;
 
-    public function __construct(int $truncateAt = null)
+    public function __construct(?int $truncateAt = null)
     {
         $this->truncateAt = $truncateAt;
     }
@@ -22,7 +22,7 @@ final class BodySummarizer implements BodySummarizerInterface
     public function summarize(MessageInterface $message): ?string
     {
         return $this->truncateAt === null
-            ? \GuzzleHttp\Psr7\Message::bodySummary($message)
-            : \GuzzleHttp\Psr7\Message::bodySummary($message, $this->truncateAt);
+            ? Psr7\Message::bodySummary($message)
+            : Psr7\Message::bodySummary($message, $this->truncateAt);
     }
 }
index bc6efc90fcbd6055c80748c6b2a38ecffea39608..c78919a4fcbf3d35f44307bea36d7192f9117279 100644 (file)
@@ -52,7 +52,7 @@ class Client implements ClientInterface, \Psr\Http\Client\ClientInterface
      *
      * @param array $config Client configuration settings.
      *
-     * @see \GuzzleHttp\RequestOptions for a list of available request options.
+     * @see RequestOptions for a list of available request options.
      */
     public function __construct(array $config = [])
     {
@@ -202,7 +202,7 @@ class Client implements ClientInterface, \Psr\Http\Client\ClientInterface
      *
      * @deprecated Client::getConfig will be removed in guzzlehttp/guzzle:8.0.
      */
-    public function getConfig(string $option = null)
+    public function getConfig(?string $option = null)
     {
         return $option === null
             ? $this->config
index 1788e16ab35a8ce4b2a7ed0ede92ffbaf133ba5f..6aaee61afc27304a6606087fa95cd8c8f27ba64e 100644 (file)
@@ -80,5 +80,5 @@ interface ClientInterface
      *
      * @deprecated ClientInterface::getConfig will be removed in guzzlehttp/guzzle:8.0.
      */
-    public function getConfig(string $option = null);
+    public function getConfig(?string $option = null);
 }
index c29b4b7e915910871164c1d08685093ebc22335a..b616cf2ed6bea739ee18495de2feaf5aee3e7122 100644 (file)
@@ -103,7 +103,7 @@ class CookieJar implements CookieJarInterface
         }, $this->getIterator()->getArrayCopy());
     }
 
-    public function clear(string $domain = null, string $path = null, string $name = null): void
+    public function clear(?string $domain = null, ?string $path = null, ?string $name = null): void
     {
         if (!$domain) {
             $this->cookies = [];
index 8c55cc6f70097af4445a3f6fe84f0e9099e90456..93ada58d224168a458da6c11ff4eb7d58ff6fda5 100644 (file)
@@ -62,7 +62,7 @@ interface CookieJarInterface extends \Countable, \IteratorAggregate
      * @param string|null $path   Clears cookies matching a domain and path
      * @param string|null $name   Clears cookies matching a domain, path, and name
      */
-    public function clear(string $domain = null, string $path = null, string $name = null): void;
+    public function clear(?string $domain = null, ?string $path = null, ?string $name = null): void;
 
     /**
      * Discard all sessions cookies.
index a80956c9d2a0368a3de8c114b357f2dd7f9e338a..ba67ad498c541b5a3dedddef4964e51edfb45642 100644 (file)
@@ -14,7 +14,7 @@ class BadResponseException extends RequestException
         string $message,
         RequestInterface $request,
         ResponseInterface $response,
-        \Throwable $previous = null,
+        ?\Throwable $previous = null,
         array $handlerContext = []
     ) {
         parent::__construct($message, $request, $response, $previous, $handlerContext);
index e1a31519cfa2d6f36a8e5f807285bf6c51195934..eab51ca1771fa853b99d59796274c833ff8bc895 100644 (file)
@@ -25,7 +25,7 @@ class ConnectException extends TransferException implements NetworkExceptionInte
     public function __construct(
         string $message,
         RequestInterface $request,
-        \Throwable $previous = null,
+        ?\Throwable $previous = null,
         array $handlerContext = []
     ) {
         parent::__construct($message, 0, $previous);
index c2d0a9cccfc5151114033c751754de01de298aa0..b42c88abfa4334334a0063c2ab3177babce5287a 100644 (file)
@@ -7,7 +7,6 @@ use GuzzleHttp\BodySummarizerInterface;
 use Psr\Http\Client\RequestExceptionInterface;
 use Psr\Http\Message\RequestInterface;
 use Psr\Http\Message\ResponseInterface;
-use Psr\Http\Message\UriInterface;
 
 /**
  * HTTP Request exception
@@ -32,8 +31,8 @@ class RequestException extends TransferException implements RequestExceptionInte
     public function __construct(
         string $message,
         RequestInterface $request,
-        ResponseInterface $response = null,
-        \Throwable $previous = null,
+        ?ResponseInterface $response = null,
+        ?\Throwable $previous = null,
         array $handlerContext = []
     ) {
         // Set the code of the exception if the response is set and not future.
@@ -63,10 +62,10 @@ class RequestException extends TransferException implements RequestExceptionInte
      */
     public static function create(
         RequestInterface $request,
-        ResponseInterface $response = null,
-        \Throwable $previous = null,
+        ?ResponseInterface $response = null,
+        ?\Throwable $previous = null,
         array $handlerContext = [],
-        BodySummarizerInterface $bodySummarizer = null
+        ?BodySummarizerInterface $bodySummarizer = null
     ): self {
         if (!$response) {
             return new self(
@@ -90,8 +89,7 @@ class RequestException extends TransferException implements RequestExceptionInte
             $className = __CLASS__;
         }
 
-        $uri = $request->getUri();
-        $uri = static::obfuscateUri($uri);
+        $uri = \GuzzleHttp\Psr7\Utils::redactUserInfo($request->getUri());
 
         // Client Error: `GET /` resulted in a `404 Not Found` response:
         // <html> ... (truncated)
@@ -113,20 +111,6 @@ class RequestException extends TransferException implements RequestExceptionInte
         return new $className($message, $request, $response, $previous, $handlerContext);
     }
 
-    /**
-     * Obfuscates URI if there is a username and a password present
-     */
-    private static function obfuscateUri(UriInterface $uri): UriInterface
-    {
-        $userInfo = $uri->getUserInfo();
-
-        if (false !== ($pos = \strpos($userInfo, ':'))) {
-            return $uri->withUserInfo(\substr($userInfo, 0, $pos), '***');
-        }
-
-        return $uri;
-    }
-
     /**
      * Get the request that caused the exception
      */
index 16a9422321e42075ec894f3f76536d1ae2efcaeb..fe36137513ea364cdc5adbda2dcf9b62faaa7351 100644 (file)
@@ -11,6 +11,7 @@ use GuzzleHttp\Psr7\LazyOpenStream;
 use GuzzleHttp\TransferStats;
 use GuzzleHttp\Utils;
 use Psr\Http\Message\RequestInterface;
+use Psr\Http\Message\UriInterface;
 
 /**
  * Creates curl resources from a request
@@ -46,6 +47,16 @@ class CurlFactory implements CurlFactoryInterface
 
     public function create(RequestInterface $request, array $options): EasyHandle
     {
+        $protocolVersion = $request->getProtocolVersion();
+
+        if ('2' === $protocolVersion || '2.0' === $protocolVersion) {
+            if (!self::supportsHttp2()) {
+                throw new ConnectException('HTTP/2 is supported by the cURL handler, however libcurl is built without HTTP/2 support.', $request);
+            }
+        } elseif ('1.0' !== $protocolVersion && '1.1' !== $protocolVersion) {
+            throw new ConnectException(sprintf('HTTP/%s is not supported by the cURL handler.', $protocolVersion), $request);
+        }
+
         if (isset($options['curl']['body_as_string'])) {
             $options['_body_as_string'] = $options['curl']['body_as_string'];
             unset($options['curl']['body_as_string']);
@@ -72,6 +83,42 @@ class CurlFactory implements CurlFactoryInterface
         return $easy;
     }
 
+    private static function supportsHttp2(): bool
+    {
+        static $supportsHttp2 = null;
+
+        if (null === $supportsHttp2) {
+            $supportsHttp2 = self::supportsTls12()
+                && defined('CURL_VERSION_HTTP2')
+                && (\CURL_VERSION_HTTP2 & \curl_version()['features']);
+        }
+
+        return $supportsHttp2;
+    }
+
+    private static function supportsTls12(): bool
+    {
+        static $supportsTls12 = null;
+
+        if (null === $supportsTls12) {
+            $supportsTls12 = \CURL_SSLVERSION_TLSv1_2 & \curl_version()['features'];
+        }
+
+        return $supportsTls12;
+    }
+
+    private static function supportsTls13(): bool
+    {
+        static $supportsTls13 = null;
+
+        if (null === $supportsTls13) {
+            $supportsTls13 = defined('CURL_SSLVERSION_TLSv1_3')
+                && (\CURL_SSLVERSION_TLSv1_3 & \curl_version()['features']);
+        }
+
+        return $supportsTls13;
+    }
+
     public function release(EasyHandle $easy): void
     {
         $resource = $easy->handle;
@@ -147,7 +194,7 @@ class CurlFactory implements CurlFactoryInterface
             'error' => \curl_error($easy->handle),
             'appconnect_time' => \curl_getinfo($easy->handle, \CURLINFO_APPCONNECT_TIME),
         ] + \curl_getinfo($easy->handle);
-        $ctx[self::CURL_VERSION_STR] = \curl_version()['version'];
+        $ctx[self::CURL_VERSION_STR] = self::getCurlVersion();
         $factory->release($easy);
 
         // Retry when nothing is present or when curl failed to rewind.
@@ -158,6 +205,17 @@ class CurlFactory implements CurlFactoryInterface
         return self::createRejection($easy, $ctx);
     }
 
+    private static function getCurlVersion(): string
+    {
+        static $curlVersion = null;
+
+        if (null === $curlVersion) {
+            $curlVersion = \curl_version()['version'];
+        }
+
+        return $curlVersion;
+    }
+
     private static function createRejection(EasyHandle $easy, array $ctx): PromiseInterface
     {
         static $connectionErrors = [
@@ -194,15 +252,22 @@ class CurlFactory implements CurlFactoryInterface
             );
         }
 
+        $uri = $easy->request->getUri();
+
+        $sanitizedError = self::sanitizeCurlError($ctx['error'] ?? '', $uri);
+
         $message = \sprintf(
             'cURL error %s: %s (%s)',
             $ctx['errno'],
-            $ctx['error'],
+            $sanitizedError,
             'see https://curl.haxx.se/libcurl/c/libcurl-errors.html'
         );
-        $uriString = (string) $easy->request->getUri();
-        if ($uriString !== '' && false === \strpos($ctx['error'], $uriString)) {
-            $message .= \sprintf(' for %s', $uriString);
+
+        if ('' !== $sanitizedError) {
+            $redactedUriString = \GuzzleHttp\Psr7\Utils::redactUserInfo($uri)->__toString();
+            if ($redactedUriString !== '' && false === \strpos($sanitizedError, $redactedUriString)) {
+                $message .= \sprintf(' for %s', $redactedUriString);
+            }
         }
 
         // Create a connection exception if it was a specific error code.
@@ -213,6 +278,24 @@ class CurlFactory implements CurlFactoryInterface
         return P\Create::rejectionFor($error);
     }
 
+    private static function sanitizeCurlError(string $error, UriInterface $uri): string
+    {
+        if ('' === $error) {
+            return $error;
+        }
+
+        $baseUri = $uri->withQuery('')->withFragment('');
+        $baseUriString = $baseUri->__toString();
+
+        if ('' === $baseUriString) {
+            return $error;
+        }
+
+        $redactedUriString = \GuzzleHttp\Psr7\Utils::redactUserInfo($baseUri)->__toString();
+
+        return str_replace($baseUriString, $redactedUriString, $error);
+    }
+
     /**
      * @return array<int|string, mixed>
      */
@@ -232,10 +315,11 @@ class CurlFactory implements CurlFactoryInterface
         }
 
         $version = $easy->request->getProtocolVersion();
-        if ($version == 1.1) {
-            $conf[\CURLOPT_HTTP_VERSION] = \CURL_HTTP_VERSION_1_1;
-        } elseif ($version == 2.0) {
+
+        if ('2' === $version || '2.0' === $version) {
             $conf[\CURLOPT_HTTP_VERSION] = \CURL_HTTP_VERSION_2_0;
+        } elseif ('1.1' === $version) {
+            $conf[\CURLOPT_HTTP_VERSION] = \CURL_HTTP_VERSION_1_1;
         } else {
             $conf[\CURLOPT_HTTP_VERSION] = \CURL_HTTP_VERSION_1_0;
         }
@@ -390,8 +474,10 @@ class CurlFactory implements CurlFactoryInterface
                 // The empty string enables all available decoders and implicitly
                 // sets a matching 'Accept-Encoding' header.
                 $conf[\CURLOPT_ENCODING] = '';
-                // But as the user did not specify any acceptable encodings we need
-                // to overwrite this implicit header with an empty one.
+                // But as the user did not specify any encoding preference,
+                // let's leave it up to server by preventing curl from sending
+                // the header, which will be interpreted as 'Accept-Encoding: *'.
+                // https://www.rfc-editor.org/rfc/rfc9110#field.accept-encoding
                 $conf[\CURLOPT_HTTPHEADER][] = 'Accept-Encoding:';
             }
         }
@@ -455,23 +541,35 @@ class CurlFactory implements CurlFactoryInterface
         }
 
         if (isset($options['crypto_method'])) {
-            if (\STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT === $options['crypto_method']) {
-                if (!defined('CURL_SSLVERSION_TLSv1_0')) {
-                    throw new \InvalidArgumentException('Invalid crypto_method request option: TLS 1.0 not supported by your version of cURL');
+            $protocolVersion = $easy->request->getProtocolVersion();
+
+            // If HTTP/2, upgrade TLS 1.0 and 1.1 to 1.2
+            if ('2' === $protocolVersion || '2.0' === $protocolVersion) {
+                if (
+                    \STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT === $options['crypto_method']
+                    || \STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT === $options['crypto_method']
+                    || \STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT === $options['crypto_method']
+                ) {
+                    $conf[\CURLOPT_SSLVERSION] = \CURL_SSLVERSION_TLSv1_2;
+                } elseif (defined('STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT') && \STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT === $options['crypto_method']) {
+                    if (!self::supportsTls13()) {
+                        throw new \InvalidArgumentException('Invalid crypto_method request option: TLS 1.3 not supported by your version of cURL');
+                    }
+                    $conf[\CURLOPT_SSLVERSION] = \CURL_SSLVERSION_TLSv1_3;
+                } else {
+                    throw new \InvalidArgumentException('Invalid crypto_method request option: unknown version provided');
                 }
+            } elseif (\STREAM_CRYPTO_METHOD_TLSv1_0_CLIENT === $options['crypto_method']) {
                 $conf[\CURLOPT_SSLVERSION] = \CURL_SSLVERSION_TLSv1_0;
             } elseif (\STREAM_CRYPTO_METHOD_TLSv1_1_CLIENT === $options['crypto_method']) {
-                if (!defined('CURL_SSLVERSION_TLSv1_1')) {
-                    throw new \InvalidArgumentException('Invalid crypto_method request option: TLS 1.1 not supported by your version of cURL');
-                }
                 $conf[\CURLOPT_SSLVERSION] = \CURL_SSLVERSION_TLSv1_1;
             } elseif (\STREAM_CRYPTO_METHOD_TLSv1_2_CLIENT === $options['crypto_method']) {
-                if (!defined('CURL_SSLVERSION_TLSv1_2')) {
+                if (!self::supportsTls12()) {
                     throw new \InvalidArgumentException('Invalid crypto_method request option: TLS 1.2 not supported by your version of cURL');
                 }
                 $conf[\CURLOPT_SSLVERSION] = \CURL_SSLVERSION_TLSv1_2;
             } elseif (defined('STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT') && \STREAM_CRYPTO_METHOD_TLSv1_3_CLIENT === $options['crypto_method']) {
-                if (!defined('CURL_SSLVERSION_TLSv1_3')) {
+                if (!self::supportsTls13()) {
                     throw new \InvalidArgumentException('Invalid crypto_method request option: TLS 1.3 not supported by your version of cURL');
                 }
                 $conf[\CURLOPT_SSLVERSION] = \CURL_SSLVERSION_TLSv1_3;
index a64e1821a9f3ac6791f07585642645637cf6f8f7..73a6abe333b51e4b890121faadac03b13b218876 100644 (file)
@@ -2,6 +2,7 @@
 
 namespace GuzzleHttp\Handler;
 
+use Closure;
 use GuzzleHttp\Promise as P;
 use GuzzleHttp\Promise\Promise;
 use GuzzleHttp\Promise\PromiseInterface;
@@ -159,6 +160,9 @@ class CurlMultiHandler
             }
         }
 
+        // Run curl_multi_exec in the queue to enable other async tasks to run
+        P\Utils::queue()->add(Closure::fromCallable([$this, 'tickInQueue']));
+
         // Step through the task queue which may add additional requests.
         P\Utils::queue()->run();
 
@@ -169,11 +173,24 @@ class CurlMultiHandler
         }
 
         while (\curl_multi_exec($this->_mh, $this->active) === \CURLM_CALL_MULTI_PERFORM) {
+            // Prevent busy looping for slow HTTP requests.
+            \curl_multi_select($this->_mh, $this->selectTimeout);
         }
 
         $this->processMessages();
     }
 
+    /**
+     * Runs \curl_multi_exec() inside the event loop, to prevent busy looping
+     */
+    private function tickInQueue(): void
+    {
+        if (\curl_multi_exec($this->_mh, $this->active) === \CURLM_CALL_MULTI_PERFORM) {
+            \curl_multi_select($this->_mh, 0);
+            P\Utils::queue()->add(Closure::fromCallable([$this, 'tickInQueue']));
+        }
+    }
+
     /**
      * Runs until all outstanding connections have completed.
      */
index 77ffed521022e0020e11a96d192d87ebd8e16c54..3ecd5964de269a2190af51b6c342a398c6183ec1 100644 (file)
@@ -52,21 +52,21 @@ class MockHandler implements \Countable
      * @param callable|null $onFulfilled Callback to invoke when the return value is fulfilled.
      * @param callable|null $onRejected  Callback to invoke when the return value is rejected.
      */
-    public static function createWithMiddleware(array $queue = null, callable $onFulfilled = null, callable $onRejected = null): HandlerStack
+    public static function createWithMiddleware(?array $queue = null, ?callable $onFulfilled = null, ?callable $onRejected = null): HandlerStack
     {
         return HandlerStack::create(new self($queue, $onFulfilled, $onRejected));
     }
 
     /**
      * The passed in value must be an array of
-     * {@see \Psr\Http\Message\ResponseInterface} objects, Exceptions,
+     * {@see ResponseInterface} objects, Exceptions,
      * callables, or Promises.
      *
      * @param array<int, mixed>|null $queue       The parameters to be passed to the append function, as an indexed array.
      * @param callable|null          $onFulfilled Callback to invoke when the return value is fulfilled.
      * @param callable|null          $onRejected  Callback to invoke when the return value is rejected.
      */
-    public function __construct(array $queue = null, callable $onFulfilled = null, callable $onRejected = null)
+    public function __construct(?array $queue = null, ?callable $onFulfilled = null, ?callable $onRejected = null)
     {
         $this->onFulfilled = $onFulfilled;
         $this->onRejected = $onRejected;
@@ -200,7 +200,7 @@ class MockHandler implements \Countable
     private function invokeStats(
         RequestInterface $request,
         array $options,
-        ResponseInterface $response = null,
+        ?ResponseInterface $response = null,
         $reason = null
     ): void {
         if (isset($options['on_stats'])) {
index 61632f5649c9a9aa12321524a8a047225ee68458..1d89a8fbc83523e0999b1cccaa689ac6ca71e994 100644 (file)
@@ -40,6 +40,12 @@ class StreamHandler
             \usleep($options['delay'] * 1000);
         }
 
+        $protocolVersion = $request->getProtocolVersion();
+
+        if ('1.0' !== $protocolVersion && '1.1' !== $protocolVersion) {
+            throw new ConnectException(sprintf('HTTP/%s is not supported by the stream handler.', $protocolVersion), $request);
+        }
+
         $startTime = isset($options['on_stats']) ? Utils::currentTime() : null;
 
         try {
@@ -83,8 +89,8 @@ class StreamHandler
         array $options,
         RequestInterface $request,
         ?float $startTime,
-        ResponseInterface $response = null,
-        \Throwable $error = null
+        ?ResponseInterface $response = null,
+        ?\Throwable $error = null
     ): void {
         if (isset($options['on_stats'])) {
             $stats = new TransferStats($request, $response, Utils::currentTime() - $startTime, $error, []);
@@ -273,7 +279,7 @@ class StreamHandler
 
         // HTTP/1.1 streams using the PHP stream wrapper require a
         // Connection: close header
-        if ($request->getProtocolVersion() == '1.1'
+        if ($request->getProtocolVersion() === '1.1'
             && !$request->hasHeader('Connection')
         ) {
             $request = $request->withHeader('Connection', 'close');
index 6cb12f07ab59e5852710b822fe1cb6eefc06494b..03f9a18ffd8adf06179fa567359adc123d681d22 100644 (file)
@@ -44,7 +44,7 @@ class HandlerStack
      *                                                                            handler is provided, the best handler for your
      *                                                                            system will be utilized.
      */
-    public static function create(callable $handler = null): self
+    public static function create(?callable $handler = null): self
     {
         $stack = new self($handler ?: Utils::chooseHandler());
         $stack->push(Middleware::httpErrors(), 'http_errors');
@@ -58,7 +58,7 @@ class HandlerStack
     /**
      * @param (callable(RequestInterface, array): PromiseInterface)|null $handler Underlying HTTP handler.
      */
-    public function __construct(callable $handler = null)
+    public function __construct(?callable $handler = null)
     {
         $this->handler = $handler;
     }
@@ -131,7 +131,7 @@ class HandlerStack
      * @param callable(callable): callable $middleware Middleware function
      * @param string                       $name       Name to register for this middleware.
      */
-    public function unshift(callable $middleware, string $name = null): void
+    public function unshift(callable $middleware, ?string $name = null): void
     {
         \array_unshift($this->stack, [$middleware, $name]);
         $this->cached = null;
index 04e9eb37a42591c9807b8687def12eff9bdba129..9b77eee8324dcb825825dc689d6b7a9a01bba933 100644 (file)
@@ -68,7 +68,7 @@ class MessageFormatter implements MessageFormatterInterface
      * @param ResponseInterface|null $response Response that was received
      * @param \Throwable|null        $error    Exception that was received
      */
-    public function format(RequestInterface $request, ResponseInterface $response = null, \Throwable $error = null): string
+    public function format(RequestInterface $request, ?ResponseInterface $response = null, ?\Throwable $error = null): string
     {
         $cache = [];
 
index 47934614a05d4541fcef0b7ce72574fa151fd662..a39ac248ee32913583e7e497715ee1f1f461bb3e 100644 (file)
@@ -14,5 +14,5 @@ interface MessageFormatterInterface
      * @param ResponseInterface|null $response Response that was received
      * @param \Throwable|null        $error    Exception that was received
      */
-    public function format(RequestInterface $request, ResponseInterface $response = null, \Throwable $error = null): string;
+    public function format(RequestInterface $request, ?ResponseInterface $response = null, ?\Throwable $error = null): string;
 }
index 7e3eb6b3a0286eaebaf960e13ff93aa995ce2719..6edbb3fe4fcc2d4eedd403abc01fc0061b9b2e21 100644 (file)
@@ -55,7 +55,7 @@ final class Middleware
      *
      * @return callable(callable): callable Returns a function that accepts the next handler.
      */
-    public static function httpErrors(BodySummarizerInterface $bodySummarizer = null): callable
+    public static function httpErrors(?BodySummarizerInterface $bodySummarizer = null): callable
     {
         return static function (callable $handler) use ($bodySummarizer): callable {
             return static function ($request, array $options) use ($handler, $bodySummarizer) {
@@ -132,7 +132,7 @@ final class Middleware
      *
      * @return callable Returns a function that accepts the next handler.
      */
-    public static function tap(callable $before = null, callable $after = null): callable
+    public static function tap(?callable $before = null, ?callable $after = null): callable
     {
         return static function (callable $handler) use ($before, $after): callable {
             return static function (RequestInterface $request, array $options) use ($handler, $before, $after) {
@@ -176,7 +176,7 @@ final class Middleware
      *
      * @return callable Returns a function that accepts the next handler.
      */
-    public static function retry(callable $decider, callable $delay = null): callable
+    public static function retry(callable $decider, ?callable $delay = null): callable
     {
         return static function (callable $handler) use ($decider, $delay): RetryMiddleware {
             return new RetryMiddleware($decider, $handler, $delay);
index 0a8de812893abafc987548630d1d9bbcbe9c16b8..7dde6c5f462ec6be72c4d86959f30cd244654e18 100644 (file)
@@ -76,8 +76,8 @@ class PrepareBodyMiddleware
 
         $expect = $options['expect'] ?? null;
 
-        // Return if disabled or if you're not using HTTP/1.1 or HTTP/2.0
-        if ($expect === false || $request->getProtocolVersion() < 1.1) {
+        // Return if disabled or using HTTP/1.0
+        if ($expect === false || $request->getProtocolVersion() === '1.0') {
             return;
         }
 
index a38768c0c100e03f653eb47cff1b16ec80d65bd7..84a3500e44dfc0d52ee987ec929a1952d3362c97 100644 (file)
@@ -61,7 +61,7 @@ final class RequestOptions
      * Specifies whether or not cookies are used in a request or what cookie
      * jar to use or what cookies to send. This option only works if your
      * handler has the `cookie` middleware. Valid values are `false` and
-     * an instance of {@see \GuzzleHttp\Cookie\CookieJarInterface}.
+     * an instance of {@see Cookie\CookieJarInterface}.
      */
     public const COOKIES = 'cookies';
 
index 8f4d93ac44b47ed601c6f91ca373fe1125ecf1da..65f49cb759d612b7641c8fff697dedda72f068ca 100644 (file)
@@ -40,7 +40,7 @@ class RetryMiddleware
      *                                                                         and returns the number of
      *                                                                         milliseconds to delay.
      */
-    public function __construct(callable $decider, callable $nextHandler, callable $delay = null)
+    public function __construct(callable $decider, callable $nextHandler, ?callable $delay = null)
     {
         $this->decider = $decider;
         $this->nextHandler = $nextHandler;
@@ -110,7 +110,7 @@ class RetryMiddleware
         };
     }
 
-    private function doRetry(RequestInterface $request, array $options, ResponseInterface $response = null): PromiseInterface
+    private function doRetry(RequestInterface $request, array $options, ?ResponseInterface $response = null): PromiseInterface
     {
         $options['delay'] = ($this->delay)(++$options['retries'], $response, $request);
 
index 2ce9e38f2753546fc85fbba5ffdd1c47083c64c2..93fa334c8d7aa71688628270b30f317c97e4d2d9 100644 (file)
@@ -46,8 +46,8 @@ final class TransferStats
      */
     public function __construct(
         RequestInterface $request,
-        ResponseInterface $response = null,
-        float $transferTime = null,
+        ?ResponseInterface $response = null,
+        ?float $transferTime = null,
         $handlerErrorData = null,
         array $handlerStats = []
     ) {
index 93d6d39cd98fa6f04c7699fc56dbb477fc87c172..df529270e122a04223f33dab8e526956b852864c 100644 (file)
@@ -71,7 +71,7 @@ final class Utils
             return \STDOUT;
         }
 
-        return \GuzzleHttp\Psr7\Utils::tryFopen('php://output', 'w');
+        return Psr7\Utils::tryFopen('php://output', 'w');
     }
 
     /**
@@ -87,7 +87,7 @@ final class Utils
     {
         $handler = null;
 
-        if (\defined('CURLOPT_CUSTOMREQUEST')) {
+        if (\defined('CURLOPT_CUSTOMREQUEST') && \function_exists('curl_version') && version_compare(curl_version()['version'], '7.21.2') >= 0) {
             if (\function_exists('curl_multi_exec') && \function_exists('curl_exec')) {
                 $handler = Proxy::wrapSync(new CurlMultiHandler(), new CurlHandler());
             } elseif (\function_exists('curl_exec')) {
index c73afb903de030a7bdbda2ec54b15ab9c2dbec0b..707925a0bfdc796668041a988a23e793190d6019 100644 (file)
@@ -1,6 +1,13 @@
 # CHANGELOG
 
 
+## 2.0.3 - 2024-07-18
+
+### Changed
+
+- PHP 8.4 support
+
+
 ## 2.0.2 - 2023-12-03
 
 ### Changed
index a32d3d29c798a029157f0d7f86e539112ab5ab80..d1c814fe7deaa07ca8198a2b1ac362587b81bb28 100644 (file)
@@ -38,10 +38,10 @@ composer require guzzlehttp/promises
 
 ## Version Guidance
 
-| Version | Status                 | PHP Version  |
-|---------|------------------------|--------------|
-| 1.x     | Bug and security fixes | >=5.5,<8.3   |
-| 2.x     | Latest                 | >=7.2.5,<8.4 |
+| Version | Status              | PHP Version  |
+|---------|---------------------|--------------|
+| 1.x     | Security fixes only | >=5.5,<8.3   |
+| 2.x     | Latest              | >=7.2.5,<8.5 |
 
 
 ## Quick Start
index 6c5bdd662a3fde53e2e022eabe2e6484a6eeaa9f..f64ed7714e1ce7e1e878e5070106c7835b31621d 100644 (file)
@@ -30,7 +30,7 @@
     },
     "require-dev": {
         "bamarni/composer-bin-plugin": "^1.8.2",
-        "phpunit/phpunit": "^8.5.36 || ^9.6.15"
+        "phpunit/phpunit": "^8.5.39 || ^9.6.20"
     },
     "autoload": {
         "psr-4": {
index 0b5b9c0a4018cb330602d28d9d07abaf5554b474..0da0228344857480a0ac1a2d30bfcc55087b483b 100644 (file)
@@ -84,8 +84,8 @@ final class Coroutine implements PromiseInterface
     }
 
     public function then(
-        callable $onFulfilled = null,
-        callable $onRejected = null
+        ?callable $onFulfilled = null,
+        ?callable $onRejected = null
     ): PromiseInterface {
         return $this->result->then($onFulfilled, $onRejected);
     }
index c09d23c60b814fafe3dc4390a70996cdcd9b843c..dd72c8310be59b8a7b34bf2fe5a21d719d2a774a 100644 (file)
@@ -23,8 +23,8 @@ final class Each
      */
     public static function of(
         $iterable,
-        callable $onFulfilled = null,
-        callable $onRejected = null
+        ?callable $onFulfilled = null,
+        ?callable $onRejected = null
     ): PromiseInterface {
         return (new EachPromise($iterable, [
             'fulfilled' => $onFulfilled,
@@ -46,8 +46,8 @@ final class Each
     public static function ofLimit(
         $iterable,
         $concurrency,
-        callable $onFulfilled = null,
-        callable $onRejected = null
+        ?callable $onFulfilled = null,
+        ?callable $onRejected = null
     ): PromiseInterface {
         return (new EachPromise($iterable, [
             'fulfilled' => $onFulfilled,
@@ -67,7 +67,7 @@ final class Each
     public static function ofLimitAll(
         $iterable,
         $concurrency,
-        callable $onFulfilled = null
+        ?callable $onFulfilled = null
     ): PromiseInterface {
         return self::ofLimit(
             $iterable,
index ab7129659deafce7dd6c6b909cc7edf32fa276b5..727ec315c4c4e8e4a9f70abe043f30d60ae6115b 100644 (file)
@@ -31,8 +31,8 @@ class FulfilledPromise implements PromiseInterface
     }
 
     public function then(
-        callable $onFulfilled = null,
-        callable $onRejected = null
+        ?callable $onFulfilled = null,
+        ?callable $onRejected = null
     ): PromiseInterface {
         // Return itself if there is no onFulfilled function.
         if (!$onFulfilled) {
index 1b07bdc9a116c3ece856022bf5c4ba4f83a533e2..c0c5be2c0981702a7c02c0d4ae913302de8d63bf 100644 (file)
@@ -25,16 +25,16 @@ class Promise implements PromiseInterface
      * @param callable $cancelFn Fn that when invoked cancels the promise.
      */
     public function __construct(
-        callable $waitFn = null,
-        callable $cancelFn = null
+        ?callable $waitFn = null,
+        ?callable $cancelFn = null
     ) {
         $this->waitFn = $waitFn;
         $this->cancelFn = $cancelFn;
     }
 
     public function then(
-        callable $onFulfilled = null,
-        callable $onRejected = null
+        ?callable $onFulfilled = null,
+        ?callable $onRejected = null
     ): PromiseInterface {
         if ($this->state === self::PENDING) {
             $p = new Promise(null, [$this, 'cancel']);
index 2824802bb254287fd053492da91d084e895e2ccc..c11721e4d92c5c44fbf87c15d8e6fe606cc1194a 100644 (file)
@@ -27,8 +27,8 @@ interface PromiseInterface
      * @param callable $onRejected  Invoked when the promise is rejected.
      */
     public function then(
-        callable $onFulfilled = null,
-        callable $onRejected = null
+        ?callable $onFulfilled = null,
+        ?callable $onRejected = null
     ): PromiseInterface;
 
     /**
index d947da1f5019a8e0aaffa0f9d9726f627ad341d3..1ebf0b2a627bebcdf6ecdd8510d9a8b43267aae3 100644 (file)
@@ -31,8 +31,8 @@ class RejectedPromise implements PromiseInterface
     }
 
     public function then(
-        callable $onFulfilled = null,
-        callable $onRejected = null
+        ?callable $onFulfilled = null,
+        ?callable $onRejected = null
     ): PromiseInterface {
         // If there's no onRejected callback then just return self.
         if (!$onRejected) {
index 72a81ba20d17d3262aef2cece5e695596746bd89..47dca8624867da19af02982e0abb499681bb3214 100644 (file)
@@ -18,7 +18,7 @@ class RejectionException extends \RuntimeException
      * @param mixed       $reason      Rejection reason.
      * @param string|null $description Optional description.
      */
-    public function __construct($reason, string $description = null)
+    public function __construct($reason, ?string $description = null)
     {
         $this->reason = $reason;
 
index e1570d727af78b7c22d195f6a0ef2e217b1835cf..45b0893fcc38b741dfefe80a30851c539fa21078 100644 (file)
@@ -21,7 +21,7 @@ final class Utils
      *
      * @param TaskQueueInterface|null $assign Optionally specify a new queue instance.
      */
-    public static function queue(TaskQueueInterface $assign = null): TaskQueueInterface
+    public static function queue(?TaskQueueInterface $assign = null): TaskQueueInterface
     {
         static $queue;
 
index fe3eda70ab10d407b9267ff9c0b16a726a9eaa18..75aabfb93e9db9cf3c1bc7c3b4fbef8789420b7f 100644 (file)
@@ -5,6 +5,23 @@ All notable changes to this project will be documented in this file.
 The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
 and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
 
+## 2.7.0 - 2024-07-18
+
+### Added
+
+- Add `Utils::redactUserInfo()` method
+- Add ability to encode bools as ints in `Query::build`
+
+## 2.6.3 - 2024-07-18
+
+### Fixed
+
+- Make `StreamWrapper::stream_stat()` return `false` if inner stream's size is `null` 
+
+### Changed
+
+- PHP 8.4 support
+
 ## 2.6.2 - 2023-12-03
 
 ### Fixed
index 850fa9d70e8962fc49d341b16a18a07f1eb63e74..2e9bb0b9b152ea1c8aadab5f590f1a75f723e733 100644 (file)
@@ -24,8 +24,8 @@ composer require guzzlehttp/psr7
 
 | Version | Status              | PHP Version  |
 |---------|---------------------|--------------|
-| 1.x     | Security fixes only | >=5.4,<8.1   |
-| 2.x     | Latest              | >=7.2.5,<8.4 |
+| 1.x     | EOL (2024-06-30)    | >=5.4,<8.2   |
+| 2.x     | Latest              | >=7.2.5,<8.5 |
 
 
 ## AppendStream
@@ -436,7 +436,7 @@ will be parsed into `['foo[a]' => '1', 'foo[b]' => '2'])`.
 
 ## `GuzzleHttp\Psr7\Query::build`
 
-`public static function build(array $params, int|false $encoding = PHP_QUERY_RFC3986): string`
+`public static function build(array $params, int|false $encoding = PHP_QUERY_RFC3986, bool $treatBoolsAsInts = true): string`
 
 Build a query string from an array of key value pairs.
 
@@ -498,11 +498,18 @@ a message.
 
 ## `GuzzleHttp\Psr7\Utils::readLine`
 
-`public static function readLine(StreamInterface $stream, int $maxLength = null): string`
+`public static function readLine(StreamInterface $stream, ?int $maxLength = null): string`
 
 Read a line from the stream up to the maximum allowed buffer length.
 
 
+## `GuzzleHttp\Psr7\Utils::redactUserInfo`
+
+`public static function redactUserInfo(UriInterface $uri): UriInterface`
+
+Redact the password in the user info part of a URI.
+
+
 ## `GuzzleHttp\Psr7\Utils::streamFor`
 
 `public static function streamFor(resource|string|null|int|float|bool|StreamInterface|callable|\Iterator $resource = '', array $options = []): StreamInterface`
@@ -674,7 +681,7 @@ termed a relative-path reference.
 
 ### `GuzzleHttp\Psr7\Uri::isSameDocumentReference`
 
-`public static function isSameDocumentReference(UriInterface $uri, UriInterface $base = null): bool`
+`public static function isSameDocumentReference(UriInterface $uri, ?UriInterface $base = null): bool`
 
 Whether the URI is a same-document reference. A same-document reference refers to a URI that is, aside from its
 fragment component, identical to the base URI. When no base URI is given, only an empty URI reference
index 70293fc40626fbbfc726ed50c0a23f4e2e7f50ff..28d15f57142446c0a2b36ab4aee2eb4d58beb144 100644 (file)
@@ -61,8 +61,8 @@
     },
     "require-dev": {
         "bamarni/composer-bin-plugin": "^1.8.2",
-        "http-interop/http-factory-tests": "^0.9",
-        "phpunit/phpunit": "^8.5.36 || ^9.6.15"
+        "http-interop/http-factory-tests": "0.9.0",
+        "phpunit/phpunit": "^8.5.39 || ^9.6.20"
     },
     "suggest": {
         "laminas/laminas-httphandlerrunner": "Emit PSR-7 responses"
index f34722cff5bfcfda7ce3fbef7458106779aed36b..7e4554d5c7e3fe8985f1d4ff4c942c3f065566d2 100644 (file)
@@ -33,7 +33,7 @@ final class CachingStream implements StreamInterface
      */
     public function __construct(
         StreamInterface $stream,
-        StreamInterface $target = null
+        ?StreamInterface $target = null
     ) {
         $this->remoteStream = $stream;
         $this->stream = $target ?: new Stream(Utils::tryFopen('php://temp', 'r+'));
index 73d17e33788dccd6452cbf1cd960d7b1920de795..3ef15103a707dcd5f55b359aa497add0bc5e709d 100644 (file)
@@ -27,10 +27,10 @@ final class HttpFactory implements RequestFactoryInterface, ResponseFactoryInter
 {
     public function createUploadedFile(
         StreamInterface $stream,
-        int $size = null,
+        ?int $size = null,
         int $error = \UPLOAD_ERR_OK,
-        string $clientFilename = null,
-        string $clientMediaType = null
+        ?string $clientFilename = null,
+        ?string $clientMediaType = null
     ): UploadedFileInterface {
         if ($size === null) {
             $size = $stream->getSize();
index d23fba8a3addc8756ce1b903ce846f894b486136..43d718f6587d7b1978dfe78e586dbc0c61be3e66 100644 (file)
@@ -32,7 +32,7 @@ final class MultipartStream implements StreamInterface
      *
      * @throws \InvalidArgumentException
      */
-    public function __construct(array $elements = [], string $boundary = null)
+    public function __construct(array $elements = [], ?string $boundary = null)
     {
         $this->boundary = $boundary ?: bin2hex(random_bytes(20));
         $this->stream = $this->createStream($elements);
index 8b94927973c69220a7f69ad7cc9e465df6433790..ccf867a0bddb3c177f418f3e724b32b0297ffd9d 100644 (file)
@@ -63,12 +63,15 @@ final class Query
      * string. This function does not modify the provided keys when an array is
      * encountered (like `http_build_query()` would).
      *
-     * @param array     $params   Query string parameters.
-     * @param int|false $encoding Set to false to not encode, PHP_QUERY_RFC3986
-     *                            to encode using RFC3986, or PHP_QUERY_RFC1738
-     *                            to encode using RFC1738.
+     * @param array     $params           Query string parameters.
+     * @param int|false $encoding         Set to false to not encode,
+     *                                    PHP_QUERY_RFC3986 to encode using
+     *                                    RFC3986, or PHP_QUERY_RFC1738 to
+     *                                    encode using RFC1738.
+     * @param bool      $treatBoolsAsInts Set to true to encode as 0/1, and
+     *                                    false as false/true.
      */
-    public static function build(array $params, $encoding = PHP_QUERY_RFC3986): string
+    public static function build(array $params, $encoding = PHP_QUERY_RFC3986, bool $treatBoolsAsInts = true): string
     {
         if (!$params) {
             return '';
@@ -86,12 +89,14 @@ final class Query
             throw new \InvalidArgumentException('Invalid type');
         }
 
+        $castBool = $treatBoolsAsInts ? static function ($v) { return (int) $v; } : static function ($v) { return $v ? 'true' : 'false'; };
+
         $qs = '';
         foreach ($params as $k => $v) {
             $k = $encoder((string) $k);
             if (!is_array($v)) {
                 $qs .= $k;
-                $v = is_bool($v) ? (int) $v : $v;
+                $v = is_bool($v) ? $castBool($v) : $v;
                 if ($v !== null) {
                     $qs .= '='.$encoder((string) $v);
                 }
@@ -99,7 +104,7 @@ final class Query
             } else {
                 foreach ($v as $vv) {
                     $qs .= $k;
-                    $vv = is_bool($vv) ? (int) $vv : $vv;
+                    $vv = is_bool($vv) ? $castBool($vv) : $vv;
                     if ($vv !== null) {
                         $qs .= '='.$encoder((string) $vv);
                     }
index 00f16e2d9ac2870cefef5a530bbc28890787b66e..34e612fda5203abf6e7ffdbf81484d8b70d21ba8 100644 (file)
@@ -96,7 +96,7 @@ class Response implements ResponseInterface
         array $headers = [],
         $body = null,
         string $version = '1.1',
-        string $reason = null
+        ?string $reason = null
     ) {
         $this->assertStatusCodeRange($status);
 
index ae853881423e6fa78faed91f9c5d4f2e633fa0c8..77b04d74719c287fc984a8f53dcb889cd58ef2b2 100644 (file)
@@ -69,7 +69,7 @@ final class StreamWrapper
         }
     }
 
-    public function stream_open(string $path, string $mode, int $options, string &$opened_path = null): bool
+    public function stream_open(string $path, string $mode, int $options, ?string &$opened_path = null): bool
     {
         $options = stream_context_get_options($this->context);
 
@@ -136,10 +136,14 @@ final class StreamWrapper
      *   ctime: int,
      *   blksize: int,
      *   blocks: int
-     * }
+     * }|false
      */
-    public function stream_stat(): array
+    public function stream_stat()
     {
+        if ($this->stream->getSize() === null) {
+            return false;
+        }
+
         static $modeMap = [
             'r' => 33060,
             'rb' => 33060,
index b26719937654c92a1c4c3b358846a127272e7f5c..9c9ea49fbdee65819ac4beaa22ee31e7351c80da 100644 (file)
@@ -64,8 +64,8 @@ class UploadedFile implements UploadedFileInterface
         $streamOrFile,
         ?int $size,
         int $errorStatus,
-        string $clientFilename = null,
-        string $clientMediaType = null
+        ?string $clientFilename = null,
+        ?string $clientMediaType = null
     ) {
         $this->setError($errorStatus);
         $this->size = $size;
index f1feee8714e621e280466419c3b76f0fc5beaeec..481dfca9461949217cd1d4870c7a029f3be13d16 100644 (file)
@@ -279,7 +279,7 @@ class Uri implements UriInterface, \JsonSerializable
      *
      * @see https://datatracker.ietf.org/doc/html/rfc3986#section-4.4
      */
-    public static function isSameDocumentReference(UriInterface $uri, UriInterface $base = null): bool
+    public static function isSameDocumentReference(UriInterface $uri, ?UriInterface $base = null): bool
     {
         if ($base !== null) {
             $uri = UriResolver::resolve($base, $uri);
index bf5ea9dba8d47cde6757ee589963ac93a383cc40..7682d2cdc7d27c55e8ef936a9d1a3fd178625dd7 100644 (file)
@@ -231,7 +231,7 @@ final class Utils
      * @param StreamInterface $stream    Stream to read from
      * @param int|null        $maxLength Maximum buffer length
      */
-    public static function readLine(StreamInterface $stream, int $maxLength = null): string
+    public static function readLine(StreamInterface $stream, ?int $maxLength = null): string
     {
         $buffer = '';
         $size = 0;
@@ -250,6 +250,20 @@ final class Utils
         return $buffer;
     }
 
+    /**
+     * Redact the password in the user info part of a URI.
+     */
+    public static function redactUserInfo(UriInterface $uri): UriInterface
+    {
+        $userInfo = $uri->getUserInfo();
+
+        if (false !== ($pos = \strpos($userInfo, ':'))) {
+            return $uri->withUserInfo(\substr($userInfo, 0, $pos), '***');
+        }
+
+        return $uri;
+    }
+
     /**
      * Create a new stream based on the input type.
      *
index 302cf1dd1690f4e6d65e4f22faadb1be80bea336..d1837d0b6a33d27717dc6b63c92b9e09a9ac4d6e 100644 (file)
@@ -15,10 +15,32 @@ This project adheres to [Semantic Versioning](https://semver.org/).
 
 ### Fixed
 
+## 8.6.0
+
+### Added
+- Support arithmetic operators in CSS function arguments (#607)
+- Add support for inserting an item in a CSS list (#545)
+- Add support for the `dvh`, `lvh` and `svh` length units (#415)
+
+### Changed
+
+- Improve performance of Value::parseValue with many delimiters by refactoring to remove array_search() (#413)
+
+## 8.5.2
+
+### Changed
+
+- Mark all class constants as `@internal` (#500)
+
+### Fixed
+
+- Fix undefined local variable in `CalcFunction::parse()` (#593)
+
 ## 8.5.1
 
 ### Fixed
 
+- Fix PHP notice caused by parsing invalid color values having less than 6 characters (#485)
 - Fix (regression) failure to parse at-rules with strict parsing (#456)
 
 ## 8.5.0
index 603f662b170902a8a45cf79018720846596f7429..4bb37589149f44843e6c849ddde2870388903bee 100644 (file)
@@ -296,6 +296,22 @@ abstract class CSSList implements Renderable, Commentable
         array_splice($this->aContents, $iOffset, $iLength, $mReplacement);
     }
 
+    /**
+     * Inserts an item in the CSS list before its sibling. If the desired sibling cannot be found,
+     * the item is appended at the end.
+     *
+     * @param RuleSet|CSSList|Import|Charset $item
+     * @param RuleSet|CSSList|Import|Charset $sibling
+     */
+    public function insertBefore($item, $sibling)
+    {
+        if (in_array($sibling, $this->aContents, true)) {
+            $this->replace($sibling, [$item, $sibling]);
+        } else {
+            $this->append($item);
+        }
+    }
+
     /**
      * Removes an item from the CSS list.
      *
index 7a99f327be29303503a908eb2f00d055fa5f8980..0757846174ab2d96b49e6bab1309347bfe62cae1 100644 (file)
@@ -9,6 +9,8 @@ class ParserState
 {
     /**
      * @var null
+     *
+     * @internal
      */
     const EOF = null;
 
index 9536ff5e973ec05c4d56192a283f7113bdcebaf7..77b8fd82437b7e709cb627fa6d66ca19d52aba85 100644 (file)
@@ -12,6 +12,8 @@ interface AtRule extends Renderable, Commentable
      * we’re whitelisting the block rules and have anything else be treated as a set rule.
      *
      * @var string
+     *
+     * @internal
      */
     const BLOCK_RULES = 'media/document/supports/region-style/font-feature-values';
 
@@ -19,6 +21,8 @@ interface AtRule extends Renderable, Commentable
      * … and more font-specific ones (to be used inside font-feature-values)
      *
      * @var string
+     *
+     * @internal
      */
     const SET_RULES = 'font-face/counter-style/page/swash/styleset/annotation';
 
index 14ea5ebb77a2f605e305d18e0cda5c1ab56cdb88..9d4795a256118c74c2e91f1354fe04f45bb82ffc 100644 (file)
@@ -8,6 +8,8 @@ class KeyframeSelector extends Selector
      * regexp for specificity calculations
      *
      * @var string
+     *
+     * @internal
      */
     const SELECTOR_VALIDATION_RX = '/
     ^(
index 70c9b2fd5c22d950b5bc55961d4ae7e38470f7ba..159b64c42d1722391e6d1335476874b46429fcd1 100644 (file)
@@ -12,6 +12,8 @@ class Selector
      * regexp for specificity calculations
      *
      * @var string
+     *
+     * @internal
      */
     const NON_ID_ATTRIBUTES_AND_PSEUDO_CLASSES_RX = '/
         (\.[\w]+)                   # classes
@@ -36,6 +38,8 @@ class Selector
      * regexp for specificity calculations
      *
      * @var string
+     *
+     * @internal
      */
     const ELEMENTS_AND_PSEUDO_ELEMENTS_RX = '/
         ((^|[\s\+\>\~]+)[\w]+   # elements
@@ -49,6 +53,8 @@ class Selector
      * regexp for specificity calculations
      *
      * @var string
+     *
+     * @internal
      */
     const SELECTOR_VALIDATION_RX = '/
         ^(
index 5ffd071f97695af6d635a577b9f954511c76bf55..a3db27101c4cd024871a735e783d353d92b2c343 100644 (file)
@@ -10,11 +10,15 @@ class CalcFunction extends CSSFunction
 {
     /**
      * @var int
+     *
+     * @internal
      */
     const T_OPERAND = 1;
 
     /**
      * @var int
+     *
+     * @internal
      */
     const T_OPERATOR = 2;
 
@@ -87,7 +91,7 @@ class CalcFunction extends CSSFunction
                         sprintf(
                             'Next token was expected to be an operand of type %s. Instead "%s" was found.',
                             implode(', ', $aOperators),
-                            $oVal
+                            $oParserState->peek()
                         ),
                         '',
                         'custom',
index 1cf00ccec901f46a6cb1816ca15b1633fea27f6a..5daad412e48d4a26dcfbee52d88f41aa9b61b583 100644 (file)
@@ -56,12 +56,19 @@ class Color extends CSSFunction
                         $oParserState->currentLine()
                     ),
                 ];
-            } else {
+            } elseif ($oParserState->strlen($sValue) === 6) {
                 $aColor = [
                     'r' => new Size(intval($sValue[0] . $sValue[1], 16), null, true, $oParserState->currentLine()),
                     'g' => new Size(intval($sValue[2] . $sValue[3], 16), null, true, $oParserState->currentLine()),
                     'b' => new Size(intval($sValue[4] . $sValue[5], 16), null, true, $oParserState->currentLine()),
                 ];
+            } else {
+                throw new UnexpectedTokenException(
+                    'Invalid hex color value',
+                    $sValue,
+                    'custom',
+                    $oParserState->currentLine()
+                );
             }
         } else {
             $sColorMode = $oParserState->parseIdentifier(true);
index 36a32381413b7681c5658e556ee3dab9f643434c..5b5ab77238de8c165637bb59817456d2d46ef9d8 100644 (file)
@@ -16,16 +16,27 @@ class Size extends PrimitiveValue
      * vh/vw/vm(ax)/vmin/rem are absolute insofar as they don’t scale to the immediate parent (only the viewport)
      *
      * @var array<int, string>
+     *
+     * @internal
      */
-    const ABSOLUTE_SIZE_UNITS = ['px', 'cm', 'mm', 'mozmm', 'in', 'pt', 'pc', 'vh', 'vw', 'vmin', 'vmax', 'rem'];
+    const ABSOLUTE_SIZE_UNITS = [
+        'px', 'pt', 'pc',
+        'cm', 'mm', 'mozmm', 'in',
+        'vh', 'dvh', 'svh', 'lvh',
+        'vw', 'vmin', 'vmax', 'rem',
+    ];
 
     /**
      * @var array<int, string>
+     *
+     * @internal
      */
     const RELATIVE_SIZE_UNITS = ['%', 'em', 'ex', 'ch', 'fr'];
 
     /**
      * @var array<int, string>
+     *
+     * @internal
      */
     const NON_SIZE_UNITS = ['deg', 'grad', 'rad', 's', 'ms', 'turn', 'Hz', 'kHz'];
 
index ce6d5790a758b440cab03a916553a1c007561a0d..4b174db0b58d93021fd15cea8ca39d686e98a385 100644 (file)
@@ -67,23 +67,30 @@ abstract class Value implements Renderable
         }
         // Convert the list to list objects
         foreach ($aListDelimiters as $sDelimiter) {
-            if (count($aStack) === 1) {
+            $iStackLength = count($aStack);
+            if ($iStackLength === 1) {
                 return $aStack[0];
             }
-            $iStartPosition = null;
-            while (($iStartPosition = array_search($sDelimiter, $aStack, true)) !== false) {
+            $aNewStack = [];
+            for ($iStartPosition = 0; $iStartPosition < $iStackLength; ++$iStartPosition) {
+                if ($iStartPosition === ($iStackLength - 1) || $sDelimiter !== $aStack[$iStartPosition + 1]) {
+                    $aNewStack[] = $aStack[$iStartPosition];
+                    continue;
+                }
                 $iLength = 2; //Number of elements to be joined
-                for ($i = $iStartPosition + 2; $i < count($aStack); $i += 2, ++$iLength) {
+                for ($i = $iStartPosition + 3; $i < $iStackLength; $i += 2, ++$iLength) {
                     if ($sDelimiter !== $aStack[$i]) {
                         break;
                     }
                 }
                 $oList = new RuleValueList($sDelimiter, $oParserState->currentLine());
-                for ($i = $iStartPosition - 1; $i - $iStartPosition + 1 < $iLength * 2; $i += 2) {
+                for ($i = $iStartPosition; $i - $iStartPosition < $iLength * 2; $i += 2) {
                     $oList->addListComponent($aStack[$i]);
                 }
-                array_splice($aStack, $iStartPosition - 1, $iLength * 2 - 1, [$oList]);
+                $aNewStack[] = $oList;
+                $iStartPosition += $iLength * 2 - 2;
             }
+            $aStack = $aNewStack;
         }
         if (!isset($aStack[0])) {
             throw new UnexpectedTokenException(
@@ -156,7 +163,16 @@ abstract class Value implements Renderable
         } elseif ($oParserState->comes("U+")) {
             $oValue = self::parseUnicodeRangeValue($oParserState);
         } else {
-            $oValue = self::parseIdentifierOrFunction($oParserState);
+            $sNextChar = $oParserState->peek(1);
+            try {
+                $oValue = self::parseIdentifierOrFunction($oParserState);
+            } catch (UnexpectedTokenException $e) {
+                if (\in_array($sNextChar, ['+', '-', '*', '/'], true)) {
+                    $oValue = $oParserState->consume(1);
+                } else {
+                    throw $e;
+                }
+            }
         }
         $oParserState->consumeWhiteSpace();
         return $oValue;