aboutsummaryrefslogtreecommitdiff
path: root/vendor/guzzlehttp/guzzle/src/Handler
diff options
context:
space:
mode:
authorwn_ <invalid@email.com>2024-10-07 20:22:01 +0000
committerwn_ <invalid@email.com>2024-10-07 20:22:01 +0000
commit124c4e254250ebac336392711b32dfd6fa3caef3 (patch)
treeab331cad28c1619db93474c846b11dc3e131c85f /vendor/guzzlehttp/guzzle/src/Handler
parentdf489df309dc831b357a9cc36fe72ad5a99d22e0 (diff)
Update Guzzle to 7.9.2
https://github.com/guzzle/guzzle/releases
Diffstat (limited to 'vendor/guzzlehttp/guzzle/src/Handler')
-rw-r--r--vendor/guzzlehttp/guzzle/src/Handler/CurlFactory.php134
-rw-r--r--vendor/guzzlehttp/guzzle/src/Handler/CurlMultiHandler.php17
-rw-r--r--vendor/guzzlehttp/guzzle/src/Handler/MockHandler.php8
-rw-r--r--vendor/guzzlehttp/guzzle/src/Handler/StreamHandler.php12
4 files changed, 146 insertions, 25 deletions
diff --git a/vendor/guzzlehttp/guzzle/src/Handler/CurlFactory.php b/vendor/guzzlehttp/guzzle/src/Handler/CurlFactory.php
index 16a942232..fe3613751 100644
--- a/vendor/guzzlehttp/guzzle/src/Handler/CurlFactory.php
+++ b/vendor/guzzlehttp/guzzle/src/Handler/CurlFactory.php
@@ -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;
diff --git a/vendor/guzzlehttp/guzzle/src/Handler/CurlMultiHandler.php b/vendor/guzzlehttp/guzzle/src/Handler/CurlMultiHandler.php
index a64e1821a..73a6abe33 100644
--- a/vendor/guzzlehttp/guzzle/src/Handler/CurlMultiHandler.php
+++ b/vendor/guzzlehttp/guzzle/src/Handler/CurlMultiHandler.php
@@ -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,12 +173,25 @@ 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.
*/
public function execute(): void
diff --git a/vendor/guzzlehttp/guzzle/src/Handler/MockHandler.php b/vendor/guzzlehttp/guzzle/src/Handler/MockHandler.php
index 77ffed521..3ecd5964d 100644
--- a/vendor/guzzlehttp/guzzle/src/Handler/MockHandler.php
+++ b/vendor/guzzlehttp/guzzle/src/Handler/MockHandler.php
@@ -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'])) {
diff --git a/vendor/guzzlehttp/guzzle/src/Handler/StreamHandler.php b/vendor/guzzlehttp/guzzle/src/Handler/StreamHandler.php
index 61632f564..1d89a8fbc 100644
--- a/vendor/guzzlehttp/guzzle/src/Handler/StreamHandler.php
+++ b/vendor/guzzlehttp/guzzle/src/Handler/StreamHandler.php
@@ -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');