PluginProbe
Yoast SEO – Advanced SEO with real-time guidance and built-in AI / trunk
Yoast SEO – Advanced SEO with real-time guidance and built-in AI vtrunk
28.5 28.4 28.3 28.2 28.1 28.0 27.9 27.8 27.7 27.6 27.5 trunk 18.0 18.1 18.2 18.3 18.4 18.4.1 18.5 18.5.1 18.6 18.7 18.8 18.9 19.0 All 129 releases
← All changes | vendor_prefixed/guzzlehttp/guzzle/src/Client.php +232 -18 28.0 → trunk View file →
@@ -2,11 +2,13 @@
2 2
3 3 namespace YoastSEO_Vendor\GuzzleHttp;
4 4
5 5 use YoastSEO_Vendor\GuzzleHttp\Cookie\CookieJar;
6 +use YoastSEO_Vendor\GuzzleHttp\Cookie\CookieJarInterface;
6 7 use YoastSEO_Vendor\GuzzleHttp\Exception\GuzzleException;
7 8 use YoastSEO_Vendor\GuzzleHttp\Exception\InvalidArgumentException;
8 9 use YoastSEO_Vendor\GuzzleHttp\Handler\CurlShareHandleState;
10 +use YoastSEO_Vendor\GuzzleHttp\Handler\CurlVersion;
9 11 use YoastSEO_Vendor\GuzzleHttp\Promise as P;
10 12 use YoastSEO_Vendor\GuzzleHttp\Promise\PromiseInterface;
11 13 use YoastSEO_Vendor\Psr\Http\Message\RequestInterface;
12 14 use YoastSEO_Vendor\Psr\Http\Message\ResponseInterface;
@@ -48,8 +50,22 @@
48 50 * - base_uri: (string|UriInterface) Base URI of the client that is merged
49 51 * into relative URIs. Can be a string or instance of UriInterface.
50 52 * - transport_sharing: (string|null) Transport sharing mode for the
51 53 * default handler. Accepts TransportSharing::* or null. Defaults to null.
54 + * - max_host_connections: (int|null) Maximum concurrent connections per
55 + * host, applied by the default CurlMultiHandler. The default stream
56 + * fallback receives the cap as a marker only: it rejects enabled
57 + * response streaming ("stream" => true) and does not limit overlapping
58 + * buffered calls.
59 + * - max_total_connections: (int|null) Maximum concurrent connections
60 + * overall, applied by the default CurlMultiHandler. The default stream
61 + * fallback receives the cap as a marker only: it rejects enabled
62 + * response streaming ("stream" => true) and does not limit overlapping
63 + * buffered calls.
64 + * - multiplex: (string|null) Multiplexing::NONE to disable multiplexing on
65 + * the default CurlMultiHandler; the value also becomes the default
66 + * "multiplex" request option. Other Multiplexing::* values act as the
67 + * default request option only.
52 68 * - **: any request option
53 69 *
54 70 * @param array $config Client configuration settings.
55 71 *
@@ -56,15 +72,35 @@
56 72 * @see RequestOptions for a list of available request options.
57 73 */
58 74 public function __construct(array $config = [])
59 75 {
76 + $handlerOptions = [];
77 + foreach (['max_host_connections', 'max_total_connections'] as $capOption) {
78 + if (\array_key_exists($capOption, $config)) {
79 + if ($config[$capOption] !== null) {
80 + $handlerOptions[$capOption] = $config[$capOption];
81 + }
82 + unset($config[$capOption]);
83 + }
84 + }
85 + // Deliberately not unset: the value also becomes the default
86 + // "multiplex" request option, which the configured handler accepts.
87 + $handlerMultiplex = ($config['multiplex'] ?? null) === \YoastSEO_Vendor\GuzzleHttp\Multiplexing::NONE;
60 88 $transportSharing = \array_key_exists('transport_sharing', $config) ? $config['transport_sharing'] : null;
61 89 $transportSharingMode = \YoastSEO_Vendor\GuzzleHttp\Handler\CurlShareHandleState::normalizeMode($transportSharing, 'transport_sharing');
62 90 unset($config['transport_sharing']);
63 91 if (!isset($config['handler'])) {
64 - $config['handler'] = $transportSharingMode === \YoastSEO_Vendor\GuzzleHttp\TransportSharing::NONE ? \YoastSEO_Vendor\GuzzleHttp\HandlerStack::create() : \YoastSEO_Vendor\GuzzleHttp\HandlerStack::create(\YoastSEO_Vendor\GuzzleHttp\Utils::chooseHandler(['transport_sharing' => $transportSharingMode]));
92 + if ($transportSharingMode !== \YoastSEO_Vendor\GuzzleHttp\TransportSharing::NONE) {
93 + $handlerOptions['transport_sharing'] = $transportSharingMode;
94 + }
95 + if ($handlerMultiplex) {
96 + $handlerOptions['multiplex'] = \YoastSEO_Vendor\GuzzleHttp\Multiplexing::NONE;
97 + }
98 + $config['handler'] = $handlerOptions === [] ? \YoastSEO_Vendor\GuzzleHttp\HandlerStack::create() : \YoastSEO_Vendor\GuzzleHttp\HandlerStack::create(\YoastSEO_Vendor\GuzzleHttp\Utils::chooseHandler($handlerOptions));
65 99 } elseif (!\is_callable($config['handler'])) {
66 100 throw new \YoastSEO_Vendor\GuzzleHttp\Exception\InvalidArgumentException('handler must be a callable');
101 + } elseif ($handlerOptions !== []) {
102 + throw new \YoastSEO_Vendor\GuzzleHttp\Exception\InvalidArgumentException('The "max_host_connections" and "max_total_connections" client options require Guzzle to create the default handler. Configure the options on the CurlMultiHandler constructor to apply numeric connection caps, or on the StreamHandler constructor to reject enabled response streaming, when providing a custom handler.');
67 103 } elseif ($transportSharingMode === \YoastSEO_Vendor\GuzzleHttp\TransportSharing::HANDLER_REQUIRE) {
68 104 throw new \YoastSEO_Vendor\GuzzleHttp\Exception\InvalidArgumentException('The "transport_sharing" client option can only require sharing when Guzzle creates the default handler. Configure the "transport_sharing" option on CurlHandler or CurlMultiHandler when providing a custom cURL handler.');
69 105 }
70 106 // Convert the base_uri to a UriInterface
@@ -82,8 +118,9 @@
82 118 * @deprecated Client::__call will be removed in guzzlehttp/guzzle:8.0.
83 119 */
84 120 public function __call($method, $args)
85 121 {
122 + \YoastSEO_Vendor\trigger_deprecation('guzzlehttp/guzzle', '7.1', '%s::%s() is deprecated and will be removed in 8.0.', __CLASS__, __FUNCTION__);
86 123 if (\count($args) < 1) {
87 124 throw new \YoastSEO_Vendor\GuzzleHttp\Exception\InvalidArgumentException('Magic request methods require a URI and optional options array');
88 125 }
89 126 $uri = $args[0];
@@ -89,9 +126,9 @@
89 126 $uri = $args[0];
90 127 $opts = $args[1] ?? [];
91 128 $isAsync = \substr($method, -5) === 'Async';
92 129 $method = $isAsync ? \substr($method, 0, -5) : $method;
93 - $method = \strtoupper($method);
130 + $method = \YoastSEO_Vendor\GuzzleHttp\Psr7\Utils::asciiToUpper($method);
94 131 return $isAsync ? $this->requestAsync($method, $uri, $opts) : $this->request($method, $uri, $opts);
95 132 }
96 133 /**
97 134 * Asynchronously send an HTTP request.
@@ -102,9 +139,9 @@
102 139 public function sendAsync(\YoastSEO_Vendor\Psr\Http\Message\RequestInterface $request, array $options = []) : \YoastSEO_Vendor\GuzzleHttp\Promise\PromiseInterface
103 140 {
104 141 // Merge the base URI into the request URI if needed.
105 142 $options = $this->prepareDefaults($options);
106 - return $this->transfer($request->withUri($this->buildUri($request->getUri(), $options), $request->hasHeader('Host')), $options);
143 + return $this->transfer($request->withUri($this->buildUri($request->getUri(), $options), self::shouldPreserveHost($request)), $options);
107 144 }
108 145 /**
109 146 * Send an HTTP request.
110 147 *
@@ -143,9 +180,9 @@
143 180 * @param array $options Request options to apply. See {@see RequestOptions}.
144 181 */
145 182 public function requestAsync(string $method, $uri = '', array $options = []) : \YoastSEO_Vendor\GuzzleHttp\Promise\PromiseInterface
146 183 {
147 - $normalizedMethod = \strtoupper($method);
184 + $normalizedMethod = \YoastSEO_Vendor\GuzzleHttp\Psr7\Utils::asciiToUpper($method);
148 185 if ($method !== $normalizedMethod) {
149 186 \YoastSEO_Vendor\trigger_deprecation('guzzlehttp/guzzle', '7.11', 'Passing a non-uppercase HTTP method to Client::requestAsync() is deprecated; guzzlehttp/guzzle 8.0 will preserve HTTP method casing. Pass an uppercase method explicitly if uppercase is required.');
150 187 $method = $normalizedMethod;
151 188 }
@@ -183,9 +220,9 @@
183 220 * @throws GuzzleException
184 221 */
185 222 public function request(string $method, $uri = '', array $options = []) : \YoastSEO_Vendor\Psr\Http\Message\ResponseInterface
186 223 {
187 - $normalizedMethod = \strtoupper($method);
224 + $normalizedMethod = \YoastSEO_Vendor\GuzzleHttp\Psr7\Utils::asciiToUpper($method);
188 225 if ($method !== $normalizedMethod) {
189 226 \YoastSEO_Vendor\trigger_deprecation('guzzlehttp/guzzle', '7.11', 'Passing a non-uppercase HTTP method to Client::request() is deprecated; guzzlehttp/guzzle 8.0 will preserve HTTP method casing. Pass an uppercase method explicitly if uppercase is required.');
190 227 $method = $normalizedMethod;
191 228 }
@@ -215,11 +252,34 @@
215 252 $idnOptions = \YoastSEO_Vendor\GuzzleHttp\Utils::normalizeIdnConversionOption($config['idn_conversion'] ?? null);
216 253 if ($idnOptions !== null) {
217 254 $uri = \YoastSEO_Vendor\GuzzleHttp\Utils::idnUriConvert($uri, $idnOptions);
218 255 }
219 - return $uri->getScheme() === '' && $uri->getHost() !== '' ? $uri->withScheme('http') : $uri;
256 + if ($uri->getScheme() === '' && $uri->getHost() !== '') {
257 + $uri = $uri->withScheme('http');
258 + }
259 + return $uri;
220 260 }
221 261 /**
262 + * Whether to preserve an existing Host header when the URI changes.
263 + *
264 + * A header matching the current URI carries no explicit override and is
265 + * regenerated after base URI resolution or IDN conversion. Other values
266 + * are preserved as deliberate overrides, as PSR-7 requires.
267 + */
268 + private static function shouldPreserveHost(\YoastSEO_Vendor\Psr\Http\Message\RequestInterface $request) : bool
269 + {
270 + if (!$request->hasHeader('Host')) {
271 + return \false;
272 + }
273 + $uri = $request->getUri();
274 + $host = $uri->getHost();
275 + $port = $uri->getPort();
276 + if ($port !== null) {
277 + $host .= ':' . $port;
278 + }
279 + return $host !== $request->getHeaderLine('Host');
280 + }
281 + /**
222 282 * Configures the default options for a client.
223 283 */
224 284 private function configureDefaults(array $config) : void
225 285 {
@@ -248,9 +308,9 @@
248 308 } else {
249 309 // Add the User-Agent header if one was not already set.
250 310 $hasUserAgent = \false;
251 311 foreach (\array_keys($this->config['headers']) as $name) {
252 - if (\strtolower((string) $name) === 'user-agent') {
312 + if (\YoastSEO_Vendor\GuzzleHttp\Psr7\Utils::asciiToLower((string) $name) === 'user-agent') {
253 313 $hasUserAgent = \true;
254 314 break;
255 315 }
256 316 }
@@ -296,10 +356,123 @@
296 356 unset($result[$k]);
297 357 }
298 358 }
299 359 self::warnAboutInvalidRequestOptionTypes($result);
300 - return $result;
360 + return self::normalizeDeprecatedRequestOptionValues($result);
301 361 }
362 + /**
363 + * Normalize values that guzzlehttp/guzzle 8.0 rejects only after the
364 + * corresponding 7.x deprecation has already been emitted.
365 + *
366 + * @param array<string, mixed> $options
367 + *
368 + * @return array<string, mixed>
369 + */
370 + private static function normalizeDeprecatedRequestOptionValues(array $options) : array
371 + {
372 + self::normalizeDeprecatedAuthOptionValues($options);
373 + self::normalizeDeprecatedTlsFileOptionValues($options, 'cert');
374 + self::normalizeDeprecatedTlsFileOptionValues($options, 'ssl_key');
375 + self::normalizeDeprecatedStringOptionValues($options);
376 + self::normalizeDeprecatedNumericOptionValues($options);
377 + self::normalizeDeprecatedIntegerOptionValues($options);
378 + return $options;
379 + }
380 + /**
381 + * @param mixed $value
382 + */
383 + private static function canStringifyDeprecatedValue($value) : bool
384 + {
385 + return $value === null || \is_scalar($value) || \is_object($value) && \method_exists($value, '__toString');
386 + }
387 + /**
388 + * @param mixed $value
389 + */
390 + private static function stringifyDeprecatedValue($value) : string
391 + {
392 + if (\is_float($value) && !\is_finite($value)) {
393 + return \is_nan($value) ? 'NAN' : ($value > 0 ? 'INF' : '-INF');
394 + }
395 + if ($value === null) {
396 + return '';
397 + }
398 + if (\is_scalar($value)) {
399 + return (string) $value;
400 + }
401 + if (\is_object($value) && \method_exists($value, '__toString')) {
402 + return $value->__toString();
403 + }
404 + throw new \LogicException('Value is not stringable.');
405 + }
406 + /**
407 + * @param array<string, mixed> $options
408 + */
409 + private static function normalizeDeprecatedAuthOptionValues(array &$options) : void
410 + {
411 + if (!isset($options['auth']) || !\is_array($options['auth']) || $options['auth'] === []) {
412 + return;
413 + }
414 + foreach ([0, 1] as $index) {
415 + if (\array_key_exists($index, $options['auth']) && !\is_string($options['auth'][$index]) && self::canStringifyDeprecatedValue($options['auth'][$index])) {
416 + $options['auth'][$index] = self::stringifyDeprecatedValue($options['auth'][$index]);
417 + }
418 + }
419 + if (\array_key_exists(2, $options['auth']) && $options['auth'][2] !== null && !\is_string($options['auth'][2]) && self::canStringifyDeprecatedValue($options['auth'][2])) {
420 + $options['auth'][2] = self::stringifyDeprecatedValue($options['auth'][2]);
421 + }
422 + }
423 + /**
424 + * @param array<string, mixed> $options
425 + */
426 + private static function normalizeDeprecatedTlsFileOptionValues(array &$options, string $option) : void
427 + {
428 + if (!isset($options[$option]) || !\is_array($options[$option])) {
429 + return;
430 + }
431 + foreach ([0, 1] as $index) {
432 + if (\array_key_exists($index, $options[$option]) && $options[$option][$index] !== null && !\is_string($options[$option][$index]) && self::canStringifyDeprecatedValue($options[$option][$index])) {
433 + $options[$option][$index] = self::stringifyDeprecatedValue($options[$option][$index]);
434 + }
435 + }
436 + }
437 + /**
438 + * @param array<string, mixed> $options
439 + */
440 + private static function normalizeDeprecatedStringOptionValues(array &$options) : void
441 + {
442 + foreach (['cert_type', 'force_ip_resolve', 'ssl_key_type'] as $option) {
443 + if (\array_key_exists($option, $options) && !\is_string($options[$option]) && self::canStringifyDeprecatedValue($options[$option])) {
444 + $options[$option] = self::stringifyDeprecatedValue($options[$option]);
445 + }
446 + }
447 + }
448 + /**
449 + * @param array<string, mixed> $options
450 + */
451 + private static function normalizeDeprecatedNumericOptionValues(array &$options) : void
452 + {
453 + foreach (['connect_timeout', 'delay', 'read_timeout', 'timeout'] as $option) {
454 + if (\array_key_exists($option, $options) && \is_string($options[$option]) && \is_numeric($options[$option])) {
455 + $options[$option] = $options[$option] + 0;
456 + }
457 + }
458 + }
459 + /**
460 + * @param array<string, mixed> $options
461 + */
462 + private static function normalizeDeprecatedIntegerOptionValues(array &$options) : void
463 + {
464 + foreach (['crypto_method', 'crypto_method_max', 'retries'] as $option) {
465 + if (!\array_key_exists($option, $options)) {
466 + continue;
467 + }
468 + if (\is_string($options[$option]) && \preg_match('/^-?\\d+$/D', $options[$option]) === 1) {
469 + $options[$option] = (int) $options[$option];
470 + } elseif (\is_float($options[$option]) && \is_finite($options[$option]) && $options[$option] === (float) (int) $options[$option]) {
471 + $options[$option] = (int) $options[$option];
472 + }
473 + }
474 + }
302 475 private static function warnAboutRequestLevelHandler(array $options) : void
303 476 {
304 477 if (!\array_key_exists('handler', $options)) {
305 478 return;
@@ -312,8 +485,10 @@
312 485 self::warnInvalidRequestOptionType('handler', 'callable', $options['handler']);
313 486 }
314 487 if (isset($options['allow_redirects']) && \is_array($options['allow_redirects'])) {
315 488 self::warnAboutInvalidAllowRedirectsOptionTypes($options['allow_redirects']);
489 + } elseif (isset($options['allow_redirects']) && !\is_bool($options['allow_redirects'])) {
490 + self::warnInvalidRequestOptionType('allow_redirects', 'bool|array', $options['allow_redirects'], '7.13');
316 491 }
317 492 if (isset($options['auth'])) {
318 493 self::warnAboutInvalidAuthOptionTypes($options['auth']);
319 494 }
@@ -323,11 +498,18 @@
323 498 self::warnAboutInvalidTlsFileOptionTypes($options, 'cert');
324 499 self::warnIfPresentAndNotString($options, 'cert_type');
325 500 self::warnIfPresentAndNotNumber($options, 'connect_timeout');
326 501 self::warnIfPresentAndNotInt($options, 'crypto_method');
502 + self::warnIfPresentAndNotInt($options, 'crypto_method_max', null, '7.13');
327 503 self::warnIfPresentAndNotBoolOrResource($options, 'debug');
328 504 self::warnIfPresentAndNotBoolOrString($options, 'decode_content');
329 505 self::warnIfPresentAndNotNumber($options, 'delay');
506 + if (isset($options['delay']) && \is_numeric($options['delay'])) {
507 + $delay = (float) $options['delay'];
508 + if (!\is_finite($delay) || $delay < 0.0) {
509 + self::warnInvalidRequestOptionType('delay', 'finite int|float greater than or equal to 0', $options['delay'], '7.13');
510 + }
511 + }
330 512 self::warnIfPresentAndNotBoolOrInt($options, 'expect');
331 513 if (isset($options['form_params'])) {
332 514 self::warnAboutInvalidFormParamTypes($options['form_params']);
333 515 }
@@ -333,8 +515,11 @@
333 515 }
334 516 if (isset($options['force_ip_resolve']) && !\is_string($options['force_ip_resolve'])) {
335 517 self::warnInvalidRequestOptionType('force_ip_resolve', 'string', $options['force_ip_resolve']);
336 518 }
519 + if (isset($options['force_ip_resolve']) && \is_string($options['force_ip_resolve']) && $options['force_ip_resolve'] !== 'v4' && $options['force_ip_resolve'] !== 'v6') {
520 + self::warnInvalidRequestOptionType('force_ip_resolve', '"v4"|"v6"', $options['force_ip_resolve'], '7.13');
521 + }
337 522 if (isset($options['headers'])) {
338 523 self::warnAboutInvalidHeaderOptionTypes($options['headers']);
339 524 }
340 525 self::warnIfPresentAndNotBool($options, 'http_errors');
@@ -342,10 +527,12 @@
342 527 self::warnAboutInvalidMultipartOptionTypes($options['multipart']);
343 528 }
344 529 self::warnIfPresentAndNotCallable($options, 'on_headers');
345 530 self::warnIfPresentAndNotCallable($options, 'on_stats');
531 + self::warnIfPresentAndNotCallable($options, 'on_trailers', null, '7.14');
346 532 self::warnIfPresentAndNotCallable($options, 'progress');
347 533 self::warnIfPresentAndNotStringArray($options, 'protocols', \true);
534 + self::warnAboutInvalidProtocolValues($options, 'protocols');
348 535 self::warnAboutInvalidProxyOptionTypes($options);
349 536 self::warnIfPresentAndNotNumber($options, 'read_timeout');
350 537 self::warnIfPresentAndNotInt($options, 'retries');
351 538 if (isset($options['sink']) && !\is_bool($options['sink']) && !\is_resource($options['sink']) && !\is_string($options['sink']) && !$options['sink'] instanceof \YoastSEO_Vendor\Psr\Http\Message\StreamInterface) {
@@ -362,8 +549,11 @@
362 549 self::warnIfPresentAndNotArray($options, 'curl', 'array<int|string, mixed>');
363 550 if (isset($options['cookies']) && $options['cookies'] === \true) {
364 551 self::warnInvalidRequestOptionType('cookies', 'false|CookieJarInterface', $options['cookies']);
365 552 }
553 + if (isset($options['cookies']) && $options['cookies'] !== \false && $options['cookies'] !== \true && !$options['cookies'] instanceof \YoastSEO_Vendor\GuzzleHttp\Cookie\CookieJarInterface) {
554 + self::warnInvalidRequestOptionType('cookies', 'false|CookieJarInterface', $options['cookies'], '7.13');
555 + }
366 556 }
367 557 private static function warnAboutInvalidAllowRedirectsOptionTypes(array $allowRedirects) : void
368 558 {
369 559 self::warnIfPresentAndNotInt($allowRedirects, 'max', 'allow_redirects.max');
@@ -369,8 +559,9 @@
369 559 self::warnIfPresentAndNotInt($allowRedirects, 'max', 'allow_redirects.max');
370 560 self::warnIfPresentAndNotBool($allowRedirects, 'strict', 'allow_redirects.strict');
371 561 self::warnIfPresentAndNotBool($allowRedirects, 'referer', 'allow_redirects.referer');
372 562 self::warnIfPresentAndNotStringArray($allowRedirects, 'protocols', \true, 'allow_redirects.protocols');
563 + self::warnAboutInvalidProtocolValues($allowRedirects, 'protocols', 'allow_redirects.protocols');
373 564 self::warnIfPresentAndNotCallable($allowRedirects, 'on_redirect', 'allow_redirects.on_redirect');
374 565 self::warnIfPresentAndNotBool($allowRedirects, 'track_redirects', 'allow_redirects.track_redirects');
375 566 }
376 567 /**
@@ -571,18 +762,18 @@
571 762 if (\array_key_exists($option, $options) && !\is_bool($options[$option]) && !\is_string($options[$option])) {
572 763 self::warnInvalidRequestOptionType($option, 'bool|string', $options[$option]);
573 764 }
574 765 }
575 - private static function warnIfPresentAndNotCallable(array $options, string $option, ?string $path = null) : void
766 + private static function warnIfPresentAndNotCallable(array $options, string $option, ?string $path = null, string $since = '7.11') : void
576 767 {
577 768 if (\array_key_exists($option, $options) && !\is_callable($options[$option])) {
578 - self::warnInvalidRequestOptionType($path ?? $option, 'callable', $options[$option]);
769 + self::warnInvalidRequestOptionType($path ?? $option, 'callable', $options[$option], $since);
579 770 }
580 771 }
581 - private static function warnIfPresentAndNotInt(array $options, string $option, ?string $path = null) : void
772 + private static function warnIfPresentAndNotInt(array $options, string $option, ?string $path = null, string $since = '7.11') : void
582 773 {
583 774 if (\array_key_exists($option, $options) && !\is_int($options[$option])) {
584 - self::warnInvalidRequestOptionType($path ?? $option, 'int', $options[$option]);
775 + self::warnInvalidRequestOptionType($path ?? $option, 'int', $options[$option], $since);
585 776 }
586 777 }
587 778 private static function warnIfPresentAndNotNumber(array $options, string $option) : void
588 779 {
@@ -613,8 +804,23 @@
613 804 return;
614 805 }
615 806 }
616 807 }
808 + /**
809 + * @param array<array-key, mixed> $options
810 + */
811 + private static function warnAboutInvalidProtocolValues(array $options, string $option, ?string $path = null) : void
812 + {
813 + if (!isset($options[$option]) || !\is_array($options[$option])) {
814 + return;
815 + }
816 + $path = $path ?? $option;
817 + foreach ($options[$option] as $index => $protocol) {
818 + if (\is_string($protocol) && $protocol !== 'http' && $protocol !== 'https') {
819 + self::warnInvalidRequestOptionType($path . '.' . (string) $index, '"http"|"https"', $protocol, '7.13');
820 + }
821 + }
822 + }
617 823 private static function warnIfPresentAndNotStringOrNumber(array $options, string $option) : void
618 824 {
619 825 if (\array_key_exists($option, $options) && !\is_string($options[$option]) && !\is_int($options[$option]) && !\is_float($options[$option])) {
620 826 self::warnInvalidRequestOptionType($option, 'string|int|float', $options[$option]);
@@ -622,11 +828,11 @@
622 828 }
623 829 /**
624 830 * @param mixed $value
625 831 */
626 - private static function warnInvalidRequestOptionType(string $option, string $expected, $value) : void
832 + private static function warnInvalidRequestOptionType(string $option, string $expected, $value, string $since = '7.11') : void
627 833 {
628 - \YoastSEO_Vendor\trigger_deprecation('guzzlehttp/guzzle', '7.11', 'Passing %s to request option "%s" is deprecated; guzzlehttp/guzzle 8.0 requires %s.', \get_debug_type($value), $option, $expected);
834 + \YoastSEO_Vendor\trigger_deprecation('guzzlehttp/guzzle', $since, 'Passing %s to request option "%s" is deprecated; guzzlehttp/guzzle 8.0 requires %s.', \get_debug_type($value), $option, $expected);
629 835 }
630 836 /**
631 837 * Transfers the given request and applies request options.
632 838 *
@@ -685,15 +891,20 @@
685 891 $options['body'] = new \YoastSEO_Vendor\GuzzleHttp\Psr7\MultipartStream($options['multipart']);
686 892 unset($options['multipart']);
687 893 }
688 894 if (isset($options['json'])) {
689 - $options['body'] = \YoastSEO_Vendor\GuzzleHttp\Utils::jsonEncode($options['json']);
895 + $json = \json_encode($options['json']);
896 + if (\JSON_ERROR_NONE !== \json_last_error()) {
897 + throw new \YoastSEO_Vendor\GuzzleHttp\Exception\InvalidArgumentException('json_encode error: ' . \json_last_error_msg());
898 + }
899 + /** @var non-empty-string $json */
900 + $options['body'] = $json;
690 901 unset($options['json']);
691 902 // Ensure that we don't have the header in different case and set the new value.
692 903 $options['_conditional'] = \YoastSEO_Vendor\GuzzleHttp\Psr7\Utils::caselessRemove(['Content-Type'], $options['_conditional']);
693 904 $options['_conditional']['Content-Type'] = 'application/json';
694 905 }
695 - if (!empty($options['decode_content']) && $options['decode_content'] !== \true) {
906 + if (isset($options['decode_content']) && \is_string($options['decode_content'])) {
696 907 // Ensure that we don't have the header in different case and set the new value.
697 908 $options['_conditional'] = \YoastSEO_Vendor\GuzzleHttp\Psr7\Utils::caselessRemove(['Accept-Encoding'], $options['_conditional']);
698 909 $modify['set_headers']['Accept-Encoding'] = (string) $options['decode_content'];
699 910 }
@@ -705,9 +916,9 @@
705 916 unset($options['body']);
706 917 }
707 918 if (!empty($options['auth']) && \is_array($options['auth'])) {
708 919 $value = $options['auth'];
709 - $type = isset($value[2]) ? \strtolower($value[2]) : 'basic';
920 + $type = isset($value[2]) ? \YoastSEO_Vendor\GuzzleHttp\Psr7\Utils::asciiToLower($value[2]) : 'basic';
710 921 switch ($type) {
711 922 case 'basic':
712 923 // Ensure that we don't have the header in different case and set the new value.
713 924 $modify['set_headers'] = \YoastSEO_Vendor\GuzzleHttp\Psr7\Utils::caselessRemove(['Authorization'], $modify['set_headers']);
@@ -718,9 +929,12 @@
718 929 $options['curl'][\CURLOPT_HTTPAUTH] = \CURLAUTH_DIGEST;
719 930 $options['curl'][\CURLOPT_USERPWD] = "{$value[0]}:{$value[1]}";
720 931 break;
721 932 case 'ntlm':
722 - \YoastSEO_Vendor\trigger_deprecation('guzzlehttp/guzzle', '7.12', 'Passing "ntlm" as the built-in auth type is deprecated; guzzlehttp/guzzle 8.0 will no longer apply NTLM through the "auth" request option. Configure NTLM with cURL HTTP authentication options instead.');
933 + \YoastSEO_Vendor\trigger_deprecation('guzzlehttp/guzzle', '7.12', 'Passing "ntlm" as the built-in auth type is deprecated; guzzlehttp/guzzle 8.0 will no longer apply NTLM through the "auth" request option. NTLM is also deprecated by curl/libcurl and may be unavailable in current or future libcurl builds. Avoid NTLM; if you must use it temporarily, configure cURL HTTP authentication options directly with a libcurl build that still supports NTLM.');
934 + if (!\YoastSEO_Vendor\GuzzleHttp\Handler\CurlVersion::supportsNtlm()) {
935 + throw new \YoastSEO_Vendor\GuzzleHttp\Exception\InvalidArgumentException('NTLM authentication is not available because the installed curl/libcurl build does not provide NTLM support.');
936 + }
723 937 $options['curl'][\CURLOPT_HTTPAUTH] = \CURLAUTH_NTLM;
724 938 $options['curl'][\CURLOPT_USERPWD] = "{$value[0]}:{$value[1]}";
725 939 break;
726 940 }