upgraded dependencies
This commit is contained in:
28
vendor/guzzlehttp/guzzle/src/BodySummarizer.php
vendored
Normal file
28
vendor/guzzlehttp/guzzle/src/BodySummarizer.php
vendored
Normal file
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace GuzzleHttp;
|
||||
|
||||
use Psr\Http\Message\MessageInterface;
|
||||
|
||||
final class BodySummarizer implements BodySummarizerInterface
|
||||
{
|
||||
/**
|
||||
* @var int|null
|
||||
*/
|
||||
private $truncateAt;
|
||||
|
||||
public function __construct(int $truncateAt = null)
|
||||
{
|
||||
$this->truncateAt = $truncateAt;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a summarized message body.
|
||||
*/
|
||||
public function summarize(MessageInterface $message): ?string
|
||||
{
|
||||
return $this->truncateAt === null
|
||||
? \GuzzleHttp\Psr7\Message::bodySummary($message)
|
||||
: \GuzzleHttp\Psr7\Message::bodySummary($message, $this->truncateAt);
|
||||
}
|
||||
}
|
||||
13
vendor/guzzlehttp/guzzle/src/BodySummarizerInterface.php
vendored
Normal file
13
vendor/guzzlehttp/guzzle/src/BodySummarizerInterface.php
vendored
Normal file
@@ -0,0 +1,13 @@
|
||||
<?php
|
||||
|
||||
namespace GuzzleHttp;
|
||||
|
||||
use Psr\Http\Message\MessageInterface;
|
||||
|
||||
interface BodySummarizerInterface
|
||||
{
|
||||
/**
|
||||
* Returns a summarized message body.
|
||||
*/
|
||||
public function summarize(MessageInterface $message): ?string;
|
||||
}
|
||||
236
vendor/guzzlehttp/guzzle/src/Client.php
vendored
236
vendor/guzzlehttp/guzzle/src/Client.php
vendored
@@ -1,31 +1,26 @@
|
||||
<?php
|
||||
|
||||
namespace GuzzleHttp;
|
||||
|
||||
use GuzzleHttp\Cookie\CookieJar;
|
||||
use GuzzleHttp\Exception\GuzzleException;
|
||||
use GuzzleHttp\Promise;
|
||||
use GuzzleHttp\Psr7;
|
||||
use GuzzleHttp\Exception\InvalidArgumentException;
|
||||
use GuzzleHttp\Promise as P;
|
||||
use GuzzleHttp\Promise\PromiseInterface;
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\UriInterface;
|
||||
|
||||
/**
|
||||
* @method ResponseInterface get(string|UriInterface $uri, array $options = [])
|
||||
* @method ResponseInterface head(string|UriInterface $uri, array $options = [])
|
||||
* @method ResponseInterface put(string|UriInterface $uri, array $options = [])
|
||||
* @method ResponseInterface post(string|UriInterface $uri, array $options = [])
|
||||
* @method ResponseInterface patch(string|UriInterface $uri, array $options = [])
|
||||
* @method ResponseInterface delete(string|UriInterface $uri, array $options = [])
|
||||
* @method Promise\PromiseInterface getAsync(string|UriInterface $uri, array $options = [])
|
||||
* @method Promise\PromiseInterface headAsync(string|UriInterface $uri, array $options = [])
|
||||
* @method Promise\PromiseInterface putAsync(string|UriInterface $uri, array $options = [])
|
||||
* @method Promise\PromiseInterface postAsync(string|UriInterface $uri, array $options = [])
|
||||
* @method Promise\PromiseInterface patchAsync(string|UriInterface $uri, array $options = [])
|
||||
* @method Promise\PromiseInterface deleteAsync(string|UriInterface $uri, array $options = [])
|
||||
* @final
|
||||
*/
|
||||
class Client implements ClientInterface
|
||||
class Client implements ClientInterface, \Psr\Http\Client\ClientInterface
|
||||
{
|
||||
/** @var array Default request options */
|
||||
use ClientTrait;
|
||||
|
||||
/**
|
||||
* @var array Default request options
|
||||
*/
|
||||
private $config;
|
||||
|
||||
/**
|
||||
@@ -63,13 +58,13 @@ class Client implements ClientInterface
|
||||
{
|
||||
if (!isset($config['handler'])) {
|
||||
$config['handler'] = HandlerStack::create();
|
||||
} elseif (!is_callable($config['handler'])) {
|
||||
throw new \InvalidArgumentException('handler must be a callable');
|
||||
} elseif (!\is_callable($config['handler'])) {
|
||||
throw new InvalidArgumentException('handler must be a callable');
|
||||
}
|
||||
|
||||
// Convert the base_uri to a UriInterface
|
||||
if (isset($config['base_uri'])) {
|
||||
$config['base_uri'] = Psr7\uri_for($config['base_uri']);
|
||||
$config['base_uri'] = Psr7\Utils::uriFor($config['base_uri']);
|
||||
}
|
||||
|
||||
$this->configureDefaults($config);
|
||||
@@ -79,19 +74,21 @@ class Client implements ClientInterface
|
||||
* @param string $method
|
||||
* @param array $args
|
||||
*
|
||||
* @return Promise\PromiseInterface
|
||||
* @return PromiseInterface|ResponseInterface
|
||||
*
|
||||
* @deprecated Client::__call will be removed in guzzlehttp/guzzle:8.0.
|
||||
*/
|
||||
public function __call($method, $args)
|
||||
{
|
||||
if (count($args) < 1) {
|
||||
throw new \InvalidArgumentException('Magic request methods require a URI and optional options array');
|
||||
if (\count($args) < 1) {
|
||||
throw new InvalidArgumentException('Magic request methods require a URI and optional options array');
|
||||
}
|
||||
|
||||
$uri = $args[0];
|
||||
$opts = isset($args[1]) ? $args[1] : [];
|
||||
$opts = $args[1] ?? [];
|
||||
|
||||
return substr($method, -5) === 'Async'
|
||||
? $this->requestAsync(substr($method, 0, -5), $uri, $opts)
|
||||
return \substr($method, -5) === 'Async'
|
||||
? $this->requestAsync(\substr($method, 0, -5), $uri, $opts)
|
||||
: $this->request($method, $uri, $opts);
|
||||
}
|
||||
|
||||
@@ -100,10 +97,8 @@ class Client implements ClientInterface
|
||||
*
|
||||
* @param array $options Request options to apply to the given
|
||||
* request and to the transfer. See \GuzzleHttp\RequestOptions.
|
||||
*
|
||||
* @return Promise\PromiseInterface
|
||||
*/
|
||||
public function sendAsync(RequestInterface $request, array $options = [])
|
||||
public function sendAsync(RequestInterface $request, array $options = []): PromiseInterface
|
||||
{
|
||||
// Merge the base URI into the request URI if needed.
|
||||
$options = $this->prepareDefaults($options);
|
||||
@@ -120,15 +115,28 @@ class Client implements ClientInterface
|
||||
* @param array $options Request options to apply to the given
|
||||
* request and to the transfer. See \GuzzleHttp\RequestOptions.
|
||||
*
|
||||
* @return ResponseInterface
|
||||
* @throws GuzzleException
|
||||
*/
|
||||
public function send(RequestInterface $request, array $options = [])
|
||||
public function send(RequestInterface $request, array $options = []): ResponseInterface
|
||||
{
|
||||
$options[RequestOptions::SYNCHRONOUS] = true;
|
||||
return $this->sendAsync($request, $options)->wait();
|
||||
}
|
||||
|
||||
/**
|
||||
* The HttpClient PSR (PSR-18) specify this method.
|
||||
*
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function sendRequest(RequestInterface $request): ResponseInterface
|
||||
{
|
||||
$options[RequestOptions::SYNCHRONOUS] = true;
|
||||
$options[RequestOptions::ALLOW_REDIRECTS] = false;
|
||||
$options[RequestOptions::HTTP_ERRORS] = false;
|
||||
|
||||
return $this->sendAsync($request, $options)->wait();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and send an asynchronous HTTP request.
|
||||
*
|
||||
@@ -140,20 +148,18 @@ class Client implements ClientInterface
|
||||
* @param string $method HTTP method
|
||||
* @param string|UriInterface $uri URI object or string.
|
||||
* @param array $options Request options to apply. See \GuzzleHttp\RequestOptions.
|
||||
*
|
||||
* @return Promise\PromiseInterface
|
||||
*/
|
||||
public function requestAsync($method, $uri = '', array $options = [])
|
||||
public function requestAsync(string $method, $uri = '', array $options = []): PromiseInterface
|
||||
{
|
||||
$options = $this->prepareDefaults($options);
|
||||
// Remove request modifying parameter because it can be done up-front.
|
||||
$headers = isset($options['headers']) ? $options['headers'] : [];
|
||||
$body = isset($options['body']) ? $options['body'] : null;
|
||||
$version = isset($options['version']) ? $options['version'] : '1.1';
|
||||
$headers = $options['headers'] ?? [];
|
||||
$body = $options['body'] ?? null;
|
||||
$version = $options['version'] ?? '1.1';
|
||||
// Merge the URI into the base URI.
|
||||
$uri = $this->buildUri($uri, $options);
|
||||
if (is_array($body)) {
|
||||
$this->invalidBody();
|
||||
$uri = $this->buildUri(Psr7\Utils::uriFor($uri), $options);
|
||||
if (\is_array($body)) {
|
||||
throw $this->invalidBody();
|
||||
}
|
||||
$request = new Psr7\Request($method, $uri, $headers, $body, $version);
|
||||
// Remove the option so that they are not doubly-applied.
|
||||
@@ -173,10 +179,9 @@ class Client implements ClientInterface
|
||||
* @param string|UriInterface $uri URI object or string.
|
||||
* @param array $options Request options to apply. See \GuzzleHttp\RequestOptions.
|
||||
*
|
||||
* @return ResponseInterface
|
||||
* @throws GuzzleException
|
||||
*/
|
||||
public function request($method, $uri = '', array $options = [])
|
||||
public function request(string $method, $uri = '', array $options = []): ResponseInterface
|
||||
{
|
||||
$options[RequestOptions::SYNCHRONOUS] = true;
|
||||
return $this->requestAsync($method, $uri, $options)->wait();
|
||||
@@ -192,30 +197,24 @@ class Client implements ClientInterface
|
||||
* @param string|null $option The config option to retrieve.
|
||||
*
|
||||
* @return mixed
|
||||
*
|
||||
* @deprecated Client::getConfig will be removed in guzzlehttp/guzzle:8.0.
|
||||
*/
|
||||
public function getConfig($option = null)
|
||||
public function getConfig(?string $option = null)
|
||||
{
|
||||
return $option === null
|
||||
? $this->config
|
||||
: (isset($this->config[$option]) ? $this->config[$option] : null);
|
||||
: ($this->config[$option] ?? null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|null $uri
|
||||
*
|
||||
* @return UriInterface
|
||||
*/
|
||||
private function buildUri($uri, array $config)
|
||||
private function buildUri(UriInterface $uri, array $config): UriInterface
|
||||
{
|
||||
// for BC we accept null which would otherwise fail in uri_for
|
||||
$uri = Psr7\uri_for($uri === null ? '' : $uri);
|
||||
|
||||
if (isset($config['base_uri'])) {
|
||||
$uri = Psr7\UriResolver::resolve(Psr7\uri_for($config['base_uri']), $uri);
|
||||
$uri = Psr7\UriResolver::resolve(Psr7\Utils::uriFor($config['base_uri']), $uri);
|
||||
}
|
||||
|
||||
if (isset($config['idn_conversion']) && ($config['idn_conversion'] !== false)) {
|
||||
$idnOptions = ($config['idn_conversion'] === true) ? IDNA_DEFAULT : $config['idn_conversion'];
|
||||
$idnOptions = ($config['idn_conversion'] === true) ? \IDNA_DEFAULT : $config['idn_conversion'];
|
||||
$uri = Utils::idnUriConvert($uri, $idnOptions);
|
||||
}
|
||||
|
||||
@@ -224,11 +223,8 @@ class Client implements ClientInterface
|
||||
|
||||
/**
|
||||
* Configures the default options for a client.
|
||||
*
|
||||
* @param array $config
|
||||
* @return void
|
||||
*/
|
||||
private function configureDefaults(array $config)
|
||||
private function configureDefaults(array $config): void
|
||||
{
|
||||
$defaults = [
|
||||
'allow_redirects' => RedirectMiddleware::$defaultSettings,
|
||||
@@ -236,7 +232,7 @@ class Client implements ClientInterface
|
||||
'decode_content' => true,
|
||||
'verify' => true,
|
||||
'cookies' => false,
|
||||
'idn_conversion' => true,
|
||||
'idn_conversion' => false,
|
||||
];
|
||||
|
||||
// Use the standard Linux HTTP_PROXY and HTTPS_PROXY if set.
|
||||
@@ -244,17 +240,17 @@ class Client implements ClientInterface
|
||||
// We can only trust the HTTP_PROXY environment variable in a CLI
|
||||
// process due to the fact that PHP has no reliable mechanism to
|
||||
// get environment variables that start with "HTTP_".
|
||||
if (php_sapi_name() === 'cli' && getenv('HTTP_PROXY')) {
|
||||
$defaults['proxy']['http'] = getenv('HTTP_PROXY');
|
||||
if (\PHP_SAPI === 'cli' && ($proxy = Utils::getenv('HTTP_PROXY'))) {
|
||||
$defaults['proxy']['http'] = $proxy;
|
||||
}
|
||||
|
||||
if ($proxy = getenv('HTTPS_PROXY')) {
|
||||
if ($proxy = Utils::getenv('HTTPS_PROXY')) {
|
||||
$defaults['proxy']['https'] = $proxy;
|
||||
}
|
||||
|
||||
if ($noProxy = getenv('NO_PROXY')) {
|
||||
$cleanedNoProxy = str_replace(' ', '', $noProxy);
|
||||
$defaults['proxy']['no'] = explode(',', $cleanedNoProxy);
|
||||
if ($noProxy = Utils::getenv('NO_PROXY')) {
|
||||
$cleanedNoProxy = \str_replace(' ', '', $noProxy);
|
||||
$defaults['proxy']['no'] = \explode(',', $cleanedNoProxy);
|
||||
}
|
||||
|
||||
$this->config = $config + $defaults;
|
||||
@@ -265,15 +261,15 @@ class Client implements ClientInterface
|
||||
|
||||
// Add the default user-agent header.
|
||||
if (!isset($this->config['headers'])) {
|
||||
$this->config['headers'] = ['User-Agent' => default_user_agent()];
|
||||
$this->config['headers'] = ['User-Agent' => Utils::defaultUserAgent()];
|
||||
} else {
|
||||
// Add the User-Agent header if one was not already set.
|
||||
foreach (array_keys($this->config['headers']) as $name) {
|
||||
if (strtolower($name) === 'user-agent') {
|
||||
foreach (\array_keys($this->config['headers']) as $name) {
|
||||
if (\strtolower($name) === 'user-agent') {
|
||||
return;
|
||||
}
|
||||
}
|
||||
$this->config['headers']['User-Agent'] = default_user_agent();
|
||||
$this->config['headers']['User-Agent'] = Utils::defaultUserAgent();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -281,10 +277,8 @@ class Client implements ClientInterface
|
||||
* Merges default options into the array.
|
||||
*
|
||||
* @param array $options Options to modify by reference
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function prepareDefaults(array $options)
|
||||
private function prepareDefaults(array $options): array
|
||||
{
|
||||
$defaults = $this->config;
|
||||
|
||||
@@ -296,13 +290,13 @@ class Client implements ClientInterface
|
||||
|
||||
// Special handling for headers is required as they are added as
|
||||
// conditional headers and as headers passed to a request ctor.
|
||||
if (array_key_exists('headers', $options)) {
|
||||
if (\array_key_exists('headers', $options)) {
|
||||
// Allows default headers to be unset.
|
||||
if ($options['headers'] === null) {
|
||||
$defaults['_conditional'] = [];
|
||||
unset($options['headers']);
|
||||
} elseif (!is_array($options['headers'])) {
|
||||
throw new \InvalidArgumentException('headers must be an array');
|
||||
} elseif (!\is_array($options['headers'])) {
|
||||
throw new InvalidArgumentException('headers must be an array');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -326,65 +320,49 @@ class Client implements ClientInterface
|
||||
* as-is without merging in default options.
|
||||
*
|
||||
* @param array $options See \GuzzleHttp\RequestOptions.
|
||||
*
|
||||
* @return Promise\PromiseInterface
|
||||
*/
|
||||
private function transfer(RequestInterface $request, array $options)
|
||||
private function transfer(RequestInterface $request, array $options): PromiseInterface
|
||||
{
|
||||
// save_to -> sink
|
||||
if (isset($options['save_to'])) {
|
||||
$options['sink'] = $options['save_to'];
|
||||
unset($options['save_to']);
|
||||
}
|
||||
|
||||
// exceptions -> http_errors
|
||||
if (isset($options['exceptions'])) {
|
||||
$options['http_errors'] = $options['exceptions'];
|
||||
unset($options['exceptions']);
|
||||
}
|
||||
|
||||
$request = $this->applyOptions($request, $options);
|
||||
/** @var HandlerStack $handler */
|
||||
$handler = $options['handler'];
|
||||
|
||||
try {
|
||||
return Promise\promise_for($handler($request, $options));
|
||||
return P\Create::promiseFor($handler($request, $options));
|
||||
} catch (\Exception $e) {
|
||||
return Promise\rejection_for($e);
|
||||
return P\Create::rejectionFor($e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the array of request options to a request.
|
||||
*
|
||||
* @param RequestInterface $request
|
||||
* @param array $options
|
||||
*
|
||||
* @return RequestInterface
|
||||
*/
|
||||
private function applyOptions(RequestInterface $request, array &$options)
|
||||
private function applyOptions(RequestInterface $request, array &$options): RequestInterface
|
||||
{
|
||||
$modify = [
|
||||
'set_headers' => [],
|
||||
];
|
||||
|
||||
if (isset($options['headers'])) {
|
||||
if (array_keys($options['headers']) === range(0, count($options['headers']) - 1)) {
|
||||
throw new InvalidArgumentException('The headers array must have header name as keys.');
|
||||
}
|
||||
$modify['set_headers'] = $options['headers'];
|
||||
unset($options['headers']);
|
||||
}
|
||||
|
||||
if (isset($options['form_params'])) {
|
||||
if (isset($options['multipart'])) {
|
||||
throw new \InvalidArgumentException('You cannot use '
|
||||
throw new InvalidArgumentException('You cannot use '
|
||||
. 'form_params and multipart at the same time. Use the '
|
||||
. 'form_params option if you want to send application/'
|
||||
. 'x-www-form-urlencoded requests, and the multipart '
|
||||
. 'option to send multipart/form-data requests.');
|
||||
}
|
||||
$options['body'] = http_build_query($options['form_params'], '', '&');
|
||||
$options['body'] = \http_build_query($options['form_params'], '', '&');
|
||||
unset($options['form_params']);
|
||||
// Ensure that we don't have the header in different case and set the new value.
|
||||
$options['_conditional'] = Psr7\_caseless_remove(['Content-Type'], $options['_conditional']);
|
||||
$options['_conditional'] = Psr7\Utils::caselessRemove(['Content-Type'], $options['_conditional']);
|
||||
$options['_conditional']['Content-Type'] = 'application/x-www-form-urlencoded';
|
||||
}
|
||||
|
||||
@@ -394,10 +372,10 @@ class Client implements ClientInterface
|
||||
}
|
||||
|
||||
if (isset($options['json'])) {
|
||||
$options['body'] = \GuzzleHttp\json_encode($options['json']);
|
||||
$options['body'] = Utils::jsonEncode($options['json']);
|
||||
unset($options['json']);
|
||||
// Ensure that we don't have the header in different case and set the new value.
|
||||
$options['_conditional'] = Psr7\_caseless_remove(['Content-Type'], $options['_conditional']);
|
||||
$options['_conditional'] = Psr7\Utils::caselessRemove(['Content-Type'], $options['_conditional']);
|
||||
$options['_conditional']['Content-Type'] = 'application/json';
|
||||
}
|
||||
|
||||
@@ -405,47 +383,47 @@ class Client implements ClientInterface
|
||||
&& $options['decode_content'] !== true
|
||||
) {
|
||||
// Ensure that we don't have the header in different case and set the new value.
|
||||
$options['_conditional'] = Psr7\_caseless_remove(['Accept-Encoding'], $options['_conditional']);
|
||||
$options['_conditional'] = Psr7\Utils::caselessRemove(['Accept-Encoding'], $options['_conditional']);
|
||||
$modify['set_headers']['Accept-Encoding'] = $options['decode_content'];
|
||||
}
|
||||
|
||||
if (isset($options['body'])) {
|
||||
if (is_array($options['body'])) {
|
||||
$this->invalidBody();
|
||||
if (\is_array($options['body'])) {
|
||||
throw $this->invalidBody();
|
||||
}
|
||||
$modify['body'] = Psr7\stream_for($options['body']);
|
||||
$modify['body'] = Psr7\Utils::streamFor($options['body']);
|
||||
unset($options['body']);
|
||||
}
|
||||
|
||||
if (!empty($options['auth']) && is_array($options['auth'])) {
|
||||
if (!empty($options['auth']) && \is_array($options['auth'])) {
|
||||
$value = $options['auth'];
|
||||
$type = isset($value[2]) ? strtolower($value[2]) : 'basic';
|
||||
$type = isset($value[2]) ? \strtolower($value[2]) : 'basic';
|
||||
switch ($type) {
|
||||
case 'basic':
|
||||
// Ensure that we don't have the header in different case and set the new value.
|
||||
$modify['set_headers'] = Psr7\_caseless_remove(['Authorization'], $modify['set_headers']);
|
||||
$modify['set_headers'] = Psr7\Utils::caselessRemove(['Authorization'], $modify['set_headers']);
|
||||
$modify['set_headers']['Authorization'] = 'Basic '
|
||||
. base64_encode("$value[0]:$value[1]");
|
||||
. \base64_encode("$value[0]:$value[1]");
|
||||
break;
|
||||
case 'digest':
|
||||
// @todo: Do not rely on curl
|
||||
$options['curl'][CURLOPT_HTTPAUTH] = CURLAUTH_DIGEST;
|
||||
$options['curl'][CURLOPT_USERPWD] = "$value[0]:$value[1]";
|
||||
$options['curl'][\CURLOPT_HTTPAUTH] = \CURLAUTH_DIGEST;
|
||||
$options['curl'][\CURLOPT_USERPWD] = "$value[0]:$value[1]";
|
||||
break;
|
||||
case 'ntlm':
|
||||
$options['curl'][CURLOPT_HTTPAUTH] = CURLAUTH_NTLM;
|
||||
$options['curl'][CURLOPT_USERPWD] = "$value[0]:$value[1]";
|
||||
$options['curl'][\CURLOPT_HTTPAUTH] = \CURLAUTH_NTLM;
|
||||
$options['curl'][\CURLOPT_USERPWD] = "$value[0]:$value[1]";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($options['query'])) {
|
||||
$value = $options['query'];
|
||||
if (is_array($value)) {
|
||||
$value = http_build_query($value, null, '&', PHP_QUERY_RFC3986);
|
||||
if (\is_array($value)) {
|
||||
$value = \http_build_query($value, '', '&', \PHP_QUERY_RFC3986);
|
||||
}
|
||||
if (!is_string($value)) {
|
||||
throw new \InvalidArgumentException('query must be a string or array');
|
||||
if (!\is_string($value)) {
|
||||
throw new InvalidArgumentException('query must be a string or array');
|
||||
}
|
||||
$modify['query'] = $value;
|
||||
unset($options['query']);
|
||||
@@ -454,16 +432,16 @@ class Client implements ClientInterface
|
||||
// Ensure that sink is not an invalid value.
|
||||
if (isset($options['sink'])) {
|
||||
// TODO: Add more sink validation?
|
||||
if (is_bool($options['sink'])) {
|
||||
throw new \InvalidArgumentException('sink must not be a boolean');
|
||||
if (\is_bool($options['sink'])) {
|
||||
throw new InvalidArgumentException('sink must not be a boolean');
|
||||
}
|
||||
}
|
||||
|
||||
$request = Psr7\modify_request($request, $modify);
|
||||
$request = Psr7\Utils::modifyRequest($request, $modify);
|
||||
if ($request->getBody() instanceof Psr7\MultipartStream) {
|
||||
// Use a multipart/form-data POST if a Content-Type is not set.
|
||||
// Ensure that we don't have the header in different case and set the new value.
|
||||
$options['_conditional'] = Psr7\_caseless_remove(['Content-Type'], $options['_conditional']);
|
||||
$options['_conditional'] = Psr7\Utils::caselessRemove(['Content-Type'], $options['_conditional']);
|
||||
$options['_conditional']['Content-Type'] = 'multipart/form-data; boundary='
|
||||
. $request->getBody()->getBoundary();
|
||||
}
|
||||
@@ -477,7 +455,7 @@ class Client implements ClientInterface
|
||||
$modify['set_headers'][$k] = $v;
|
||||
}
|
||||
}
|
||||
$request = Psr7\modify_request($request, $modify);
|
||||
$request = Psr7\Utils::modifyRequest($request, $modify);
|
||||
// Don't pass this internal value along to middleware/handlers.
|
||||
unset($options['_conditional']);
|
||||
}
|
||||
@@ -486,14 +464,12 @@ class Client implements ClientInterface
|
||||
}
|
||||
|
||||
/**
|
||||
* Throw Exception with pre-set message.
|
||||
* @return void
|
||||
* @throws \InvalidArgumentException Invalid body.
|
||||
* Return an InvalidArgumentException with pre-set message.
|
||||
*/
|
||||
private function invalidBody()
|
||||
private function invalidBody(): InvalidArgumentException
|
||||
{
|
||||
throw new \InvalidArgumentException('Passing in the "body" request '
|
||||
. 'option as an array to send a POST request has been deprecated. '
|
||||
return new InvalidArgumentException('Passing in the "body" request '
|
||||
. 'option as an array to send a request is not supported. '
|
||||
. 'Please use the "form_params" request option to send a '
|
||||
. 'application/x-www-form-urlencoded request, or the "multipart" '
|
||||
. 'request option to send a multipart/form-data request.');
|
||||
|
||||
23
vendor/guzzlehttp/guzzle/src/ClientInterface.php
vendored
23
vendor/guzzlehttp/guzzle/src/ClientInterface.php
vendored
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
namespace GuzzleHttp;
|
||||
|
||||
use GuzzleHttp\Exception\GuzzleException;
|
||||
@@ -13,9 +14,9 @@ use Psr\Http\Message\UriInterface;
|
||||
interface ClientInterface
|
||||
{
|
||||
/**
|
||||
* @deprecated Will be removed in Guzzle 7.0.0
|
||||
* The Guzzle major version.
|
||||
*/
|
||||
const VERSION = '6.5.5';
|
||||
public const MAJOR_VERSION = 7;
|
||||
|
||||
/**
|
||||
* Send an HTTP request.
|
||||
@@ -24,10 +25,9 @@ interface ClientInterface
|
||||
* @param array $options Request options to apply to the given
|
||||
* request and to the transfer.
|
||||
*
|
||||
* @return ResponseInterface
|
||||
* @throws GuzzleException
|
||||
*/
|
||||
public function send(RequestInterface $request, array $options = []);
|
||||
public function send(RequestInterface $request, array $options = []): ResponseInterface;
|
||||
|
||||
/**
|
||||
* Asynchronously send an HTTP request.
|
||||
@@ -35,10 +35,8 @@ interface ClientInterface
|
||||
* @param RequestInterface $request Request to send
|
||||
* @param array $options Request options to apply to the given
|
||||
* request and to the transfer.
|
||||
*
|
||||
* @return PromiseInterface
|
||||
*/
|
||||
public function sendAsync(RequestInterface $request, array $options = []);
|
||||
public function sendAsync(RequestInterface $request, array $options = []): PromiseInterface;
|
||||
|
||||
/**
|
||||
* Create and send an HTTP request.
|
||||
@@ -51,10 +49,9 @@ interface ClientInterface
|
||||
* @param string|UriInterface $uri URI object or string.
|
||||
* @param array $options Request options to apply.
|
||||
*
|
||||
* @return ResponseInterface
|
||||
* @throws GuzzleException
|
||||
*/
|
||||
public function request($method, $uri, array $options = []);
|
||||
public function request(string $method, $uri, array $options = []): ResponseInterface;
|
||||
|
||||
/**
|
||||
* Create and send an asynchronous HTTP request.
|
||||
@@ -67,10 +64,8 @@ interface ClientInterface
|
||||
* @param string $method HTTP method
|
||||
* @param string|UriInterface $uri URI object or string.
|
||||
* @param array $options Request options to apply.
|
||||
*
|
||||
* @return PromiseInterface
|
||||
*/
|
||||
public function requestAsync($method, $uri, array $options = []);
|
||||
public function requestAsync(string $method, $uri, array $options = []): PromiseInterface;
|
||||
|
||||
/**
|
||||
* Get a client configuration option.
|
||||
@@ -82,6 +77,8 @@ interface ClientInterface
|
||||
* @param string|null $option The config option to retrieve.
|
||||
*
|
||||
* @return mixed
|
||||
*
|
||||
* @deprecated ClientInterface::getConfig will be removed in guzzlehttp/guzzle:8.0.
|
||||
*/
|
||||
public function getConfig($option = null);
|
||||
public function getConfig(?string $option = null);
|
||||
}
|
||||
|
||||
241
vendor/guzzlehttp/guzzle/src/ClientTrait.php
vendored
Normal file
241
vendor/guzzlehttp/guzzle/src/ClientTrait.php
vendored
Normal file
@@ -0,0 +1,241 @@
|
||||
<?php
|
||||
|
||||
namespace GuzzleHttp;
|
||||
|
||||
use GuzzleHttp\Exception\GuzzleException;
|
||||
use GuzzleHttp\Promise\PromiseInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\UriInterface;
|
||||
|
||||
/**
|
||||
* Client interface for sending HTTP requests.
|
||||
*/
|
||||
trait ClientTrait
|
||||
{
|
||||
/**
|
||||
* Create and send an HTTP request.
|
||||
*
|
||||
* Use an absolute path to override the base path of the client, or a
|
||||
* relative path to append to the base path of the client. The URL can
|
||||
* contain the query string as well.
|
||||
*
|
||||
* @param string $method HTTP method.
|
||||
* @param string|UriInterface $uri URI object or string.
|
||||
* @param array $options Request options to apply.
|
||||
*
|
||||
* @throws GuzzleException
|
||||
*/
|
||||
abstract public function request(string $method, $uri, array $options = []): ResponseInterface;
|
||||
|
||||
/**
|
||||
* Create and send an HTTP GET request.
|
||||
*
|
||||
* Use an absolute path to override the base path of the client, or a
|
||||
* relative path to append to the base path of the client. The URL can
|
||||
* contain the query string as well.
|
||||
*
|
||||
* @param string|UriInterface $uri URI object or string.
|
||||
* @param array $options Request options to apply.
|
||||
*
|
||||
* @throws GuzzleException
|
||||
*/
|
||||
public function get($uri, array $options = []): ResponseInterface
|
||||
{
|
||||
return $this->request('GET', $uri, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and send an HTTP HEAD request.
|
||||
*
|
||||
* Use an absolute path to override the base path of the client, or a
|
||||
* relative path to append to the base path of the client. The URL can
|
||||
* contain the query string as well.
|
||||
*
|
||||
* @param string|UriInterface $uri URI object or string.
|
||||
* @param array $options Request options to apply.
|
||||
*
|
||||
* @throws GuzzleException
|
||||
*/
|
||||
public function head($uri, array $options = []): ResponseInterface
|
||||
{
|
||||
return $this->request('HEAD', $uri, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and send an HTTP PUT request.
|
||||
*
|
||||
* Use an absolute path to override the base path of the client, or a
|
||||
* relative path to append to the base path of the client. The URL can
|
||||
* contain the query string as well.
|
||||
*
|
||||
* @param string|UriInterface $uri URI object or string.
|
||||
* @param array $options Request options to apply.
|
||||
*
|
||||
* @throws GuzzleException
|
||||
*/
|
||||
public function put($uri, array $options = []): ResponseInterface
|
||||
{
|
||||
return $this->request('PUT', $uri, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and send an HTTP POST request.
|
||||
*
|
||||
* Use an absolute path to override the base path of the client, or a
|
||||
* relative path to append to the base path of the client. The URL can
|
||||
* contain the query string as well.
|
||||
*
|
||||
* @param string|UriInterface $uri URI object or string.
|
||||
* @param array $options Request options to apply.
|
||||
*
|
||||
* @throws GuzzleException
|
||||
*/
|
||||
public function post($uri, array $options = []): ResponseInterface
|
||||
{
|
||||
return $this->request('POST', $uri, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and send an HTTP PATCH request.
|
||||
*
|
||||
* Use an absolute path to override the base path of the client, or a
|
||||
* relative path to append to the base path of the client. The URL can
|
||||
* contain the query string as well.
|
||||
*
|
||||
* @param string|UriInterface $uri URI object or string.
|
||||
* @param array $options Request options to apply.
|
||||
*
|
||||
* @throws GuzzleException
|
||||
*/
|
||||
public function patch($uri, array $options = []): ResponseInterface
|
||||
{
|
||||
return $this->request('PATCH', $uri, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and send an HTTP DELETE request.
|
||||
*
|
||||
* Use an absolute path to override the base path of the client, or a
|
||||
* relative path to append to the base path of the client. The URL can
|
||||
* contain the query string as well.
|
||||
*
|
||||
* @param string|UriInterface $uri URI object or string.
|
||||
* @param array $options Request options to apply.
|
||||
*
|
||||
* @throws GuzzleException
|
||||
*/
|
||||
public function delete($uri, array $options = []): ResponseInterface
|
||||
{
|
||||
return $this->request('DELETE', $uri, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and send an asynchronous HTTP request.
|
||||
*
|
||||
* Use an absolute path to override the base path of the client, or a
|
||||
* relative path to append to the base path of the client. The URL can
|
||||
* contain the query string as well. Use an array to provide a URL
|
||||
* template and additional variables to use in the URL template expansion.
|
||||
*
|
||||
* @param string $method HTTP method
|
||||
* @param string|UriInterface $uri URI object or string.
|
||||
* @param array $options Request options to apply.
|
||||
*/
|
||||
abstract public function requestAsync(string $method, $uri, array $options = []): PromiseInterface;
|
||||
|
||||
/**
|
||||
* Create and send an asynchronous HTTP GET request.
|
||||
*
|
||||
* Use an absolute path to override the base path of the client, or a
|
||||
* relative path to append to the base path of the client. The URL can
|
||||
* contain the query string as well. Use an array to provide a URL
|
||||
* template and additional variables to use in the URL template expansion.
|
||||
*
|
||||
* @param string|UriInterface $uri URI object or string.
|
||||
* @param array $options Request options to apply.
|
||||
*/
|
||||
public function getAsync($uri, array $options = []): PromiseInterface
|
||||
{
|
||||
return $this->requestAsync('GET', $uri, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and send an asynchronous HTTP HEAD request.
|
||||
*
|
||||
* Use an absolute path to override the base path of the client, or a
|
||||
* relative path to append to the base path of the client. The URL can
|
||||
* contain the query string as well. Use an array to provide a URL
|
||||
* template and additional variables to use in the URL template expansion.
|
||||
*
|
||||
* @param string|UriInterface $uri URI object or string.
|
||||
* @param array $options Request options to apply.
|
||||
*/
|
||||
public function headAsync($uri, array $options = []): PromiseInterface
|
||||
{
|
||||
return $this->requestAsync('HEAD', $uri, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and send an asynchronous HTTP PUT request.
|
||||
*
|
||||
* Use an absolute path to override the base path of the client, or a
|
||||
* relative path to append to the base path of the client. The URL can
|
||||
* contain the query string as well. Use an array to provide a URL
|
||||
* template and additional variables to use in the URL template expansion.
|
||||
*
|
||||
* @param string|UriInterface $uri URI object or string.
|
||||
* @param array $options Request options to apply.
|
||||
*/
|
||||
public function putAsync($uri, array $options = []): PromiseInterface
|
||||
{
|
||||
return $this->requestAsync('PUT', $uri, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and send an asynchronous HTTP POST request.
|
||||
*
|
||||
* Use an absolute path to override the base path of the client, or a
|
||||
* relative path to append to the base path of the client. The URL can
|
||||
* contain the query string as well. Use an array to provide a URL
|
||||
* template and additional variables to use in the URL template expansion.
|
||||
*
|
||||
* @param string|UriInterface $uri URI object or string.
|
||||
* @param array $options Request options to apply.
|
||||
*/
|
||||
public function postAsync($uri, array $options = []): PromiseInterface
|
||||
{
|
||||
return $this->requestAsync('POST', $uri, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and send an asynchronous HTTP PATCH request.
|
||||
*
|
||||
* Use an absolute path to override the base path of the client, or a
|
||||
* relative path to append to the base path of the client. The URL can
|
||||
* contain the query string as well. Use an array to provide a URL
|
||||
* template and additional variables to use in the URL template expansion.
|
||||
*
|
||||
* @param string|UriInterface $uri URI object or string.
|
||||
* @param array $options Request options to apply.
|
||||
*/
|
||||
public function patchAsync($uri, array $options = []): PromiseInterface
|
||||
{
|
||||
return $this->requestAsync('PATCH', $uri, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and send an asynchronous HTTP DELETE request.
|
||||
*
|
||||
* Use an absolute path to override the base path of the client, or a
|
||||
* relative path to append to the base path of the client. The URL can
|
||||
* contain the query string as well. Use an array to provide a URL
|
||||
* template and additional variables to use in the URL template expansion.
|
||||
*
|
||||
* @param string|UriInterface $uri URI object or string.
|
||||
* @param array $options Request options to apply.
|
||||
*/
|
||||
public function deleteAsync($uri, array $options = []): PromiseInterface
|
||||
{
|
||||
return $this->requestAsync('DELETE', $uri, $options);
|
||||
}
|
||||
}
|
||||
130
vendor/guzzlehttp/guzzle/src/Cookie/CookieJar.php
vendored
130
vendor/guzzlehttp/guzzle/src/Cookie/CookieJar.php
vendored
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
namespace GuzzleHttp\Cookie;
|
||||
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
@@ -9,20 +10,24 @@ use Psr\Http\Message\ResponseInterface;
|
||||
*/
|
||||
class CookieJar implements CookieJarInterface
|
||||
{
|
||||
/** @var SetCookie[] Loaded cookie data */
|
||||
/**
|
||||
* @var SetCookie[] Loaded cookie data
|
||||
*/
|
||||
private $cookies = [];
|
||||
|
||||
/** @var bool */
|
||||
/**
|
||||
* @var bool
|
||||
*/
|
||||
private $strictMode;
|
||||
|
||||
/**
|
||||
* @param bool $strictMode Set to true to throw exceptions when invalid
|
||||
* @param bool $strictMode Set to true to throw exceptions when invalid
|
||||
* cookies are added to the cookie jar.
|
||||
* @param array $cookieArray Array of SetCookie objects or a hash of
|
||||
* arrays that can be used with the SetCookie
|
||||
* constructor
|
||||
*/
|
||||
public function __construct($strictMode = false, $cookieArray = [])
|
||||
public function __construct(bool $strictMode = false, array $cookieArray = [])
|
||||
{
|
||||
$this->strictMode = $strictMode;
|
||||
|
||||
@@ -39,10 +44,8 @@ class CookieJar implements CookieJarInterface
|
||||
*
|
||||
* @param array $cookies Cookies to create the jar from
|
||||
* @param string $domain Domain to set the cookies to
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public static function fromArray(array $cookies, $domain)
|
||||
public static function fromArray(array $cookies, string $domain): self
|
||||
{
|
||||
$cookieJar = new self();
|
||||
foreach ($cookies as $name => $value) {
|
||||
@@ -57,26 +60,15 @@ class CookieJar implements CookieJarInterface
|
||||
return $cookieJar;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
public static function getCookieValue($value)
|
||||
{
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluate if this cookie should be persisted to storage
|
||||
* that survives between requests.
|
||||
*
|
||||
* @param SetCookie $cookie Being evaluated.
|
||||
* @param bool $allowSessionCookies If we should persist session cookies
|
||||
* @return bool
|
||||
* @param SetCookie $cookie Being evaluated.
|
||||
* @param bool $allowSessionCookies If we should persist session cookies
|
||||
*/
|
||||
public static function shouldPersist(
|
||||
SetCookie $cookie,
|
||||
$allowSessionCookies = false
|
||||
) {
|
||||
public static function shouldPersist(SetCookie $cookie, bool $allowSessionCookies = false): bool
|
||||
{
|
||||
if ($cookie->getExpires() || $allowSessionCookies) {
|
||||
if (!$cookie->getDiscard()) {
|
||||
return true;
|
||||
@@ -90,16 +82,13 @@ class CookieJar implements CookieJarInterface
|
||||
* Finds and returns the cookie based on the name
|
||||
*
|
||||
* @param string $name cookie name to search for
|
||||
*
|
||||
* @return SetCookie|null cookie that was found or null if not found
|
||||
*/
|
||||
public function getCookieByName($name)
|
||||
public function getCookieByName(string $name): ?SetCookie
|
||||
{
|
||||
// don't allow a non string name
|
||||
if ($name === null || !is_scalar($name)) {
|
||||
return null;
|
||||
}
|
||||
foreach ($this->cookies as $cookie) {
|
||||
if ($cookie->getName() !== null && strcasecmp($cookie->getName(), $name) === 0) {
|
||||
if ($cookie->getName() !== null && \strcasecmp($cookie->getName(), $name) === 0) {
|
||||
return $cookie;
|
||||
}
|
||||
}
|
||||
@@ -107,37 +96,43 @@ class CookieJar implements CookieJarInterface
|
||||
return null;
|
||||
}
|
||||
|
||||
public function toArray()
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function toArray(): array
|
||||
{
|
||||
return array_map(function (SetCookie $cookie) {
|
||||
return \array_map(static function (SetCookie $cookie): array {
|
||||
return $cookie->toArray();
|
||||
}, $this->getIterator()->getArrayCopy());
|
||||
}
|
||||
|
||||
public function clear($domain = null, $path = null, $name = null)
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function clear(?string $domain = null, ?string $path = null, ?string $name = null): void
|
||||
{
|
||||
if (!$domain) {
|
||||
$this->cookies = [];
|
||||
return;
|
||||
} elseif (!$path) {
|
||||
$this->cookies = array_filter(
|
||||
$this->cookies = \array_filter(
|
||||
$this->cookies,
|
||||
function (SetCookie $cookie) use ($domain) {
|
||||
static function (SetCookie $cookie) use ($domain): bool {
|
||||
return !$cookie->matchesDomain($domain);
|
||||
}
|
||||
);
|
||||
} elseif (!$name) {
|
||||
$this->cookies = array_filter(
|
||||
$this->cookies = \array_filter(
|
||||
$this->cookies,
|
||||
function (SetCookie $cookie) use ($path, $domain) {
|
||||
static function (SetCookie $cookie) use ($path, $domain): bool {
|
||||
return !($cookie->matchesPath($path) &&
|
||||
$cookie->matchesDomain($domain));
|
||||
}
|
||||
);
|
||||
} else {
|
||||
$this->cookies = array_filter(
|
||||
$this->cookies = \array_filter(
|
||||
$this->cookies,
|
||||
function (SetCookie $cookie) use ($path, $domain, $name) {
|
||||
static function (SetCookie $cookie) use ($path, $domain, $name) {
|
||||
return !($cookie->getName() == $name &&
|
||||
$cookie->matchesPath($path) &&
|
||||
$cookie->matchesDomain($domain));
|
||||
@@ -146,17 +141,23 @@ class CookieJar implements CookieJarInterface
|
||||
}
|
||||
}
|
||||
|
||||
public function clearSessionCookies()
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function clearSessionCookies(): void
|
||||
{
|
||||
$this->cookies = array_filter(
|
||||
$this->cookies = \array_filter(
|
||||
$this->cookies,
|
||||
function (SetCookie $cookie) {
|
||||
static function (SetCookie $cookie): bool {
|
||||
return !$cookie->getDiscard() && $cookie->getExpires();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public function setCookie(SetCookie $cookie)
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function setCookie(SetCookie $cookie): bool
|
||||
{
|
||||
// If the name string is empty (but not 0), ignore the set-cookie
|
||||
// string entirely.
|
||||
@@ -170,15 +171,13 @@ class CookieJar implements CookieJarInterface
|
||||
if ($result !== true) {
|
||||
if ($this->strictMode) {
|
||||
throw new \RuntimeException('Invalid cookie: ' . $result);
|
||||
} else {
|
||||
$this->removeCookieIfEmpty($cookie);
|
||||
return false;
|
||||
}
|
||||
$this->removeCookieIfEmpty($cookie);
|
||||
return false;
|
||||
}
|
||||
|
||||
// Resolve conflicts with previously set cookies
|
||||
foreach ($this->cookies as $i => $c) {
|
||||
|
||||
// Two cookies are identical, when their path, and domain are
|
||||
// identical.
|
||||
if ($c->getPath() != $cookie->getPath() ||
|
||||
@@ -217,27 +216,28 @@ class CookieJar implements CookieJarInterface
|
||||
return true;
|
||||
}
|
||||
|
||||
public function count()
|
||||
public function count(): int
|
||||
{
|
||||
return count($this->cookies);
|
||||
return \count($this->cookies);
|
||||
}
|
||||
|
||||
public function getIterator()
|
||||
/**
|
||||
* @return \ArrayIterator<int, SetCookie>
|
||||
*/
|
||||
public function getIterator(): \ArrayIterator
|
||||
{
|
||||
return new \ArrayIterator(array_values($this->cookies));
|
||||
return new \ArrayIterator(\array_values($this->cookies));
|
||||
}
|
||||
|
||||
public function extractCookies(
|
||||
RequestInterface $request,
|
||||
ResponseInterface $response
|
||||
) {
|
||||
public function extractCookies(RequestInterface $request, ResponseInterface $response): void
|
||||
{
|
||||
if ($cookieHeader = $response->getHeader('Set-Cookie')) {
|
||||
foreach ($cookieHeader as $cookie) {
|
||||
$sc = SetCookie::fromString($cookie);
|
||||
if (!$sc->getDomain()) {
|
||||
$sc->setDomain($request->getUri()->getHost());
|
||||
}
|
||||
if (0 !== strpos($sc->getPath(), '/')) {
|
||||
if (0 !== \strpos($sc->getPath(), '/')) {
|
||||
$sc->setPath($this->getCookiePathFromRequest($request));
|
||||
}
|
||||
if (!$sc->matchesDomain($request->getUri()->getHost())) {
|
||||
@@ -254,30 +254,28 @@ class CookieJar implements CookieJarInterface
|
||||
* Computes cookie path following RFC 6265 section 5.1.4
|
||||
*
|
||||
* @link https://tools.ietf.org/html/rfc6265#section-5.1.4
|
||||
*
|
||||
* @param RequestInterface $request
|
||||
* @return string
|
||||
*/
|
||||
private function getCookiePathFromRequest(RequestInterface $request)
|
||||
private function getCookiePathFromRequest(RequestInterface $request): string
|
||||
{
|
||||
$uriPath = $request->getUri()->getPath();
|
||||
if ('' === $uriPath) {
|
||||
if ('' === $uriPath) {
|
||||
return '/';
|
||||
}
|
||||
if (0 !== strpos($uriPath, '/')) {
|
||||
if (0 !== \strpos($uriPath, '/')) {
|
||||
return '/';
|
||||
}
|
||||
if ('/' === $uriPath) {
|
||||
return '/';
|
||||
}
|
||||
if (0 === $lastSlashPos = strrpos($uriPath, '/')) {
|
||||
$lastSlashPos = \strrpos($uriPath, '/');
|
||||
if (0 === $lastSlashPos || false === $lastSlashPos) {
|
||||
return '/';
|
||||
}
|
||||
|
||||
return substr($uriPath, 0, $lastSlashPos);
|
||||
return \substr($uriPath, 0, $lastSlashPos);
|
||||
}
|
||||
|
||||
public function withCookieHeader(RequestInterface $request)
|
||||
public function withCookieHeader(RequestInterface $request): RequestInterface
|
||||
{
|
||||
$values = [];
|
||||
$uri = $request->getUri();
|
||||
@@ -297,17 +295,15 @@ class CookieJar implements CookieJarInterface
|
||||
}
|
||||
|
||||
return $values
|
||||
? $request->withHeader('Cookie', implode('; ', $values))
|
||||
? $request->withHeader('Cookie', \implode('; ', $values))
|
||||
: $request;
|
||||
}
|
||||
|
||||
/**
|
||||
* If a cookie already exists and the server asks to set it again with a
|
||||
* null value, the cookie must be deleted.
|
||||
*
|
||||
* @param SetCookie $cookie
|
||||
*/
|
||||
private function removeCookieIfEmpty(SetCookie $cookie)
|
||||
private function removeCookieIfEmpty(SetCookie $cookie): void
|
||||
{
|
||||
$cookieValue = $cookie->getValue();
|
||||
if ($cookieValue === null || $cookieValue === '') {
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
namespace GuzzleHttp\Cookie;
|
||||
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
@@ -12,7 +13,8 @@ use Psr\Http\Message\ResponseInterface;
|
||||
* necessary. Subclasses are also responsible for storing and retrieving
|
||||
* cookies from a file, database, etc.
|
||||
*
|
||||
* @link http://docs.python.org/2/library/cookielib.html Inspiration
|
||||
* @link https://docs.python.org/2/library/cookielib.html Inspiration
|
||||
* @extends \IteratorAggregate<SetCookie>
|
||||
*/
|
||||
interface CookieJarInterface extends \Countable, \IteratorAggregate
|
||||
{
|
||||
@@ -26,7 +28,7 @@ interface CookieJarInterface extends \Countable, \IteratorAggregate
|
||||
*
|
||||
* @return RequestInterface returns the modified request.
|
||||
*/
|
||||
public function withCookieHeader(RequestInterface $request);
|
||||
public function withCookieHeader(RequestInterface $request): RequestInterface;
|
||||
|
||||
/**
|
||||
* Extract cookies from an HTTP response and store them in the CookieJar.
|
||||
@@ -34,10 +36,7 @@ interface CookieJarInterface extends \Countable, \IteratorAggregate
|
||||
* @param RequestInterface $request Request that was sent
|
||||
* @param ResponseInterface $response Response that was received
|
||||
*/
|
||||
public function extractCookies(
|
||||
RequestInterface $request,
|
||||
ResponseInterface $response
|
||||
);
|
||||
public function extractCookies(RequestInterface $request, ResponseInterface $response): void;
|
||||
|
||||
/**
|
||||
* Sets a cookie in the cookie jar.
|
||||
@@ -46,7 +45,7 @@ interface CookieJarInterface extends \Countable, \IteratorAggregate
|
||||
*
|
||||
* @return bool Returns true on success or false on failure
|
||||
*/
|
||||
public function setCookie(SetCookie $cookie);
|
||||
public function setCookie(SetCookie $cookie): bool;
|
||||
|
||||
/**
|
||||
* Remove cookies currently held in the cookie jar.
|
||||
@@ -61,10 +60,8 @@ interface CookieJarInterface extends \Countable, \IteratorAggregate
|
||||
* @param string|null $domain Clears cookies matching a domain
|
||||
* @param string|null $path Clears cookies matching a domain and path
|
||||
* @param string|null $name Clears cookies matching a domain, path, and name
|
||||
*
|
||||
* @return CookieJarInterface
|
||||
*/
|
||||
public function clear($domain = null, $path = null, $name = null);
|
||||
public function clear(?string $domain = null, ?string $path = null, ?string $name = null): void;
|
||||
|
||||
/**
|
||||
* Discard all sessions cookies.
|
||||
@@ -73,12 +70,10 @@ interface CookieJarInterface extends \Countable, \IteratorAggregate
|
||||
* field set to true. To be called when the user agent shuts down according
|
||||
* to RFC 2965.
|
||||
*/
|
||||
public function clearSessionCookies();
|
||||
public function clearSessionCookies(): void;
|
||||
|
||||
/**
|
||||
* Converts the cookie jar to an array.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function toArray();
|
||||
public function toArray(): array;
|
||||
}
|
||||
|
||||
@@ -1,33 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace GuzzleHttp\Cookie;
|
||||
|
||||
use GuzzleHttp\Utils;
|
||||
|
||||
/**
|
||||
* Persists non-session cookies using a JSON formatted file
|
||||
*/
|
||||
class FileCookieJar extends CookieJar
|
||||
{
|
||||
/** @var string filename */
|
||||
/**
|
||||
* @var string filename
|
||||
*/
|
||||
private $filename;
|
||||
|
||||
/** @var bool Control whether to persist session cookies or not. */
|
||||
/**
|
||||
* @var bool Control whether to persist session cookies or not.
|
||||
*/
|
||||
private $storeSessionCookies;
|
||||
|
||||
/**
|
||||
* Create a new FileCookieJar object
|
||||
*
|
||||
* @param string $cookieFile File to store the cookie data
|
||||
* @param bool $storeSessionCookies Set to true to store session cookies
|
||||
* in the cookie jar.
|
||||
* @param string $cookieFile File to store the cookie data
|
||||
* @param bool $storeSessionCookies Set to true to store session cookies
|
||||
* in the cookie jar.
|
||||
*
|
||||
* @throws \RuntimeException if the file cannot be found or created
|
||||
*/
|
||||
public function __construct($cookieFile, $storeSessionCookies = false)
|
||||
public function __construct(string $cookieFile, bool $storeSessionCookies = false)
|
||||
{
|
||||
parent::__construct();
|
||||
$this->filename = $cookieFile;
|
||||
$this->storeSessionCookies = $storeSessionCookies;
|
||||
|
||||
if (file_exists($cookieFile)) {
|
||||
if (\file_exists($cookieFile)) {
|
||||
$this->load($cookieFile);
|
||||
}
|
||||
}
|
||||
@@ -44,20 +51,21 @@ class FileCookieJar extends CookieJar
|
||||
* Saves the cookies to a file.
|
||||
*
|
||||
* @param string $filename File to save
|
||||
*
|
||||
* @throws \RuntimeException if the file cannot be found or created
|
||||
*/
|
||||
public function save($filename)
|
||||
public function save(string $filename): void
|
||||
{
|
||||
$json = [];
|
||||
/** @var SetCookie $cookie */
|
||||
foreach ($this as $cookie) {
|
||||
/** @var SetCookie $cookie */
|
||||
if (CookieJar::shouldPersist($cookie, $this->storeSessionCookies)) {
|
||||
$json[] = $cookie->toArray();
|
||||
}
|
||||
}
|
||||
|
||||
$jsonStr = \GuzzleHttp\json_encode($json);
|
||||
if (false === file_put_contents($filename, $jsonStr, LOCK_EX)) {
|
||||
$jsonStr = Utils::jsonEncode($json);
|
||||
if (false === \file_put_contents($filename, $jsonStr, \LOCK_EX)) {
|
||||
throw new \RuntimeException("Unable to save file {$filename}");
|
||||
}
|
||||
}
|
||||
@@ -68,23 +76,25 @@ class FileCookieJar extends CookieJar
|
||||
* Old cookies are kept unless overwritten by newly loaded ones.
|
||||
*
|
||||
* @param string $filename Cookie file to load.
|
||||
*
|
||||
* @throws \RuntimeException if the file cannot be loaded.
|
||||
*/
|
||||
public function load($filename)
|
||||
public function load(string $filename): void
|
||||
{
|
||||
$json = file_get_contents($filename);
|
||||
$json = \file_get_contents($filename);
|
||||
if (false === $json) {
|
||||
throw new \RuntimeException("Unable to load file {$filename}");
|
||||
} elseif ($json === '') {
|
||||
}
|
||||
if ($json === '') {
|
||||
return;
|
||||
}
|
||||
|
||||
$data = \GuzzleHttp\json_decode($json, true);
|
||||
if (is_array($data)) {
|
||||
foreach (json_decode($json, true) as $cookie) {
|
||||
$data = Utils::jsonDecode($json, true);
|
||||
if (\is_array($data)) {
|
||||
foreach ($data as $cookie) {
|
||||
$this->setCookie(new SetCookie($cookie));
|
||||
}
|
||||
} elseif (strlen($data)) {
|
||||
} elseif (\is_scalar($data) && !empty($data)) {
|
||||
throw new \RuntimeException("Invalid cookie file: {$filename}");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
namespace GuzzleHttp\Cookie;
|
||||
|
||||
/**
|
||||
@@ -6,21 +7,25 @@ namespace GuzzleHttp\Cookie;
|
||||
*/
|
||||
class SessionCookieJar extends CookieJar
|
||||
{
|
||||
/** @var string session key */
|
||||
/**
|
||||
* @var string session key
|
||||
*/
|
||||
private $sessionKey;
|
||||
|
||||
/** @var bool Control whether to persist session cookies or not. */
|
||||
|
||||
/**
|
||||
* @var bool Control whether to persist session cookies or not.
|
||||
*/
|
||||
private $storeSessionCookies;
|
||||
|
||||
/**
|
||||
* Create a new SessionCookieJar object
|
||||
*
|
||||
* @param string $sessionKey Session key name to store the cookie
|
||||
* data in session
|
||||
* @param bool $storeSessionCookies Set to true to store session cookies
|
||||
* in the cookie jar.
|
||||
* @param string $sessionKey Session key name to store the cookie
|
||||
* data in session
|
||||
* @param bool $storeSessionCookies Set to true to store session cookies
|
||||
* in the cookie jar.
|
||||
*/
|
||||
public function __construct($sessionKey, $storeSessionCookies = false)
|
||||
public function __construct(string $sessionKey, bool $storeSessionCookies = false)
|
||||
{
|
||||
parent::__construct();
|
||||
$this->sessionKey = $sessionKey;
|
||||
@@ -39,33 +44,33 @@ class SessionCookieJar extends CookieJar
|
||||
/**
|
||||
* Save cookies to the client session
|
||||
*/
|
||||
public function save()
|
||||
public function save(): void
|
||||
{
|
||||
$json = [];
|
||||
/** @var SetCookie $cookie */
|
||||
foreach ($this as $cookie) {
|
||||
/** @var SetCookie $cookie */
|
||||
if (CookieJar::shouldPersist($cookie, $this->storeSessionCookies)) {
|
||||
$json[] = $cookie->toArray();
|
||||
}
|
||||
}
|
||||
|
||||
$_SESSION[$this->sessionKey] = json_encode($json);
|
||||
$_SESSION[$this->sessionKey] = \json_encode($json);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the contents of the client session into the data array
|
||||
*/
|
||||
protected function load()
|
||||
protected function load(): void
|
||||
{
|
||||
if (!isset($_SESSION[$this->sessionKey])) {
|
||||
return;
|
||||
}
|
||||
$data = json_decode($_SESSION[$this->sessionKey], true);
|
||||
if (is_array($data)) {
|
||||
$data = \json_decode($_SESSION[$this->sessionKey], true);
|
||||
if (\is_array($data)) {
|
||||
foreach ($data as $cookie) {
|
||||
$this->setCookie(new SetCookie($cookie));
|
||||
}
|
||||
} elseif (strlen($data)) {
|
||||
} elseif (\strlen($data)) {
|
||||
throw new \RuntimeException("Invalid cookie data");
|
||||
}
|
||||
}
|
||||
|
||||
232
vendor/guzzlehttp/guzzle/src/Cookie/SetCookie.php
vendored
232
vendor/guzzlehttp/guzzle/src/Cookie/SetCookie.php
vendored
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
namespace GuzzleHttp\Cookie;
|
||||
|
||||
/**
|
||||
@@ -6,7 +7,9 @@ namespace GuzzleHttp\Cookie;
|
||||
*/
|
||||
class SetCookie
|
||||
{
|
||||
/** @var array */
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private static $defaults = [
|
||||
'Name' => null,
|
||||
'Value' => null,
|
||||
@@ -19,42 +22,42 @@ class SetCookie
|
||||
'HttpOnly' => false
|
||||
];
|
||||
|
||||
/** @var array Cookie data */
|
||||
/**
|
||||
* @var array Cookie data
|
||||
*/
|
||||
private $data;
|
||||
|
||||
/**
|
||||
* Create a new SetCookie object from a string
|
||||
* Create a new SetCookie object from a string.
|
||||
*
|
||||
* @param string $cookie Set-Cookie header string
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public static function fromString($cookie)
|
||||
public static function fromString(string $cookie): self
|
||||
{
|
||||
// Create the default return array
|
||||
$data = self::$defaults;
|
||||
// Explode the cookie string using a series of semicolons
|
||||
$pieces = array_filter(array_map('trim', explode(';', $cookie)));
|
||||
$pieces = \array_filter(\array_map('trim', \explode(';', $cookie)));
|
||||
// The name of the cookie (first kvp) must exist and include an equal sign.
|
||||
if (empty($pieces[0]) || !strpos($pieces[0], '=')) {
|
||||
if (!isset($pieces[0]) || \strpos($pieces[0], '=') === false) {
|
||||
return new self($data);
|
||||
}
|
||||
|
||||
// Add the cookie pieces into the parsed data array
|
||||
foreach ($pieces as $part) {
|
||||
$cookieParts = explode('=', $part, 2);
|
||||
$key = trim($cookieParts[0]);
|
||||
$cookieParts = \explode('=', $part, 2);
|
||||
$key = \trim($cookieParts[0]);
|
||||
$value = isset($cookieParts[1])
|
||||
? trim($cookieParts[1], " \n\r\t\0\x0B")
|
||||
? \trim($cookieParts[1], " \n\r\t\0\x0B")
|
||||
: true;
|
||||
|
||||
// Only check for non-cookies when cookies have been found
|
||||
if (empty($data['Name'])) {
|
||||
if (!isset($data['Name'])) {
|
||||
$data['Name'] = $key;
|
||||
$data['Value'] = $value;
|
||||
} else {
|
||||
foreach (array_keys(self::$defaults) as $search) {
|
||||
if (!strcasecmp($search, $key)) {
|
||||
foreach (\array_keys(self::$defaults) as $search) {
|
||||
if (!\strcasecmp($search, $key)) {
|
||||
$data[$search] = $value;
|
||||
continue 2;
|
||||
}
|
||||
@@ -71,39 +74,45 @@ class SetCookie
|
||||
*/
|
||||
public function __construct(array $data = [])
|
||||
{
|
||||
$this->data = array_replace(self::$defaults, $data);
|
||||
/** @var array|null $replaced will be null in case of replace error */
|
||||
$replaced = \array_replace(self::$defaults, $data);
|
||||
if ($replaced === null) {
|
||||
throw new \InvalidArgumentException('Unable to replace the default values for the Cookie.');
|
||||
}
|
||||
|
||||
$this->data = $replaced;
|
||||
// Extract the Expires value and turn it into a UNIX timestamp if needed
|
||||
if (!$this->getExpires() && $this->getMaxAge()) {
|
||||
// Calculate the Expires date
|
||||
$this->setExpires(time() + $this->getMaxAge());
|
||||
} elseif ($this->getExpires() && !is_numeric($this->getExpires())) {
|
||||
$this->setExpires($this->getExpires());
|
||||
$this->setExpires(\time() + $this->getMaxAge());
|
||||
} elseif (null !== ($expires = $this->getExpires()) && !\is_numeric($expires)) {
|
||||
$this->setExpires($expires);
|
||||
}
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
$str = $this->data['Name'] . '=' . $this->data['Value'] . '; ';
|
||||
$str = $this->data['Name'] . '=' . ($this->data['Value'] ?? '') . '; ';
|
||||
foreach ($this->data as $k => $v) {
|
||||
if ($k !== 'Name' && $k !== 'Value' && $v !== null && $v !== false) {
|
||||
if ($k === 'Expires') {
|
||||
$str .= 'Expires=' . gmdate('D, d M Y H:i:s \G\M\T', $v) . '; ';
|
||||
$str .= 'Expires=' . \gmdate('D, d M Y H:i:s \G\M\T', $v) . '; ';
|
||||
} else {
|
||||
$str .= ($v === true ? $k : "{$k}={$v}") . '; ';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rtrim($str, '; ');
|
||||
return \rtrim($str, '; ');
|
||||
}
|
||||
|
||||
public function toArray()
|
||||
public function toArray(): array
|
||||
{
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the cookie name
|
||||
* Get the cookie name.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
@@ -113,19 +122,23 @@ class SetCookie
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the cookie name
|
||||
* Set the cookie name.
|
||||
*
|
||||
* @param string $name Cookie name
|
||||
*/
|
||||
public function setName($name)
|
||||
public function setName($name): void
|
||||
{
|
||||
$this->data['Name'] = $name;
|
||||
if (!is_string($name)) {
|
||||
trigger_deprecation('guzzlehttp/guzzle', '7.4', 'Not passing a string to %s::%s() is deprecated and will cause an error in 8.0.', __CLASS__, __FUNCTION__);
|
||||
}
|
||||
|
||||
$this->data['Name'] = (string) $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the cookie value
|
||||
* Get the cookie value.
|
||||
*
|
||||
* @return string
|
||||
* @return string|null
|
||||
*/
|
||||
public function getValue()
|
||||
{
|
||||
@@ -133,17 +146,21 @@ class SetCookie
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the cookie value
|
||||
* Set the cookie value.
|
||||
*
|
||||
* @param string $value Cookie value
|
||||
*/
|
||||
public function setValue($value)
|
||||
public function setValue($value): void
|
||||
{
|
||||
$this->data['Value'] = $value;
|
||||
if (!is_string($value)) {
|
||||
trigger_deprecation('guzzlehttp/guzzle', '7.4', 'Not passing a string to %s::%s() is deprecated and will cause an error in 8.0.', __CLASS__, __FUNCTION__);
|
||||
}
|
||||
|
||||
$this->data['Value'] = (string) $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the domain
|
||||
* Get the domain.
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
@@ -153,17 +170,21 @@ class SetCookie
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the domain of the cookie
|
||||
* Set the domain of the cookie.
|
||||
*
|
||||
* @param string $domain
|
||||
* @param string|null $domain
|
||||
*/
|
||||
public function setDomain($domain)
|
||||
public function setDomain($domain): void
|
||||
{
|
||||
$this->data['Domain'] = $domain;
|
||||
if (!is_string($domain) && null !== $domain) {
|
||||
trigger_deprecation('guzzlehttp/guzzle', '7.4', 'Not passing a string or null to %s::%s() is deprecated and will cause an error in 8.0.', __CLASS__, __FUNCTION__);
|
||||
}
|
||||
|
||||
$this->data['Domain'] = null === $domain ? null : (string) $domain;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the path
|
||||
* Get the path.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
@@ -173,39 +194,47 @@ class SetCookie
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the path of the cookie
|
||||
* Set the path of the cookie.
|
||||
*
|
||||
* @param string $path Path of the cookie
|
||||
*/
|
||||
public function setPath($path)
|
||||
public function setPath($path): void
|
||||
{
|
||||
$this->data['Path'] = $path;
|
||||
if (!is_string($path)) {
|
||||
trigger_deprecation('guzzlehttp/guzzle', '7.4', 'Not passing a string to %s::%s() is deprecated and will cause an error in 8.0.', __CLASS__, __FUNCTION__);
|
||||
}
|
||||
|
||||
$this->data['Path'] = (string) $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maximum lifetime of the cookie in seconds
|
||||
* Maximum lifetime of the cookie in seconds.
|
||||
*
|
||||
* @return int|null
|
||||
*/
|
||||
public function getMaxAge()
|
||||
{
|
||||
return $this->data['Max-Age'];
|
||||
return null === $this->data['Max-Age'] ? null : (int) $this->data['Max-Age'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the max-age of the cookie
|
||||
* Set the max-age of the cookie.
|
||||
*
|
||||
* @param int $maxAge Max age of the cookie in seconds
|
||||
* @param int|null $maxAge Max age of the cookie in seconds
|
||||
*/
|
||||
public function setMaxAge($maxAge)
|
||||
public function setMaxAge($maxAge): void
|
||||
{
|
||||
$this->data['Max-Age'] = $maxAge;
|
||||
if (!is_int($maxAge) && null !== $maxAge) {
|
||||
trigger_deprecation('guzzlehttp/guzzle', '7.4', 'Not passing an int or null to %s::%s() is deprecated and will cause an error in 8.0.', __CLASS__, __FUNCTION__);
|
||||
}
|
||||
|
||||
$this->data['Max-Age'] = $maxAge === null ? null : (int) $maxAge;
|
||||
}
|
||||
|
||||
/**
|
||||
* The UNIX timestamp when the cookie Expires
|
||||
* The UNIX timestamp when the cookie Expires.
|
||||
*
|
||||
* @return mixed
|
||||
* @return string|int|null
|
||||
*/
|
||||
public function getExpires()
|
||||
{
|
||||
@@ -213,21 +242,23 @@ class SetCookie
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the unix timestamp for which the cookie will expire
|
||||
* Set the unix timestamp for which the cookie will expire.
|
||||
*
|
||||
* @param int $timestamp Unix timestamp
|
||||
* @param int|string|null $timestamp Unix timestamp or any English textual datetime description.
|
||||
*/
|
||||
public function setExpires($timestamp)
|
||||
public function setExpires($timestamp): void
|
||||
{
|
||||
$this->data['Expires'] = is_numeric($timestamp)
|
||||
? (int) $timestamp
|
||||
: strtotime($timestamp);
|
||||
if (!is_int($timestamp) && !is_string($timestamp) && null !== $timestamp) {
|
||||
trigger_deprecation('guzzlehttp/guzzle', '7.4', 'Not passing an int, string or null to %s::%s() is deprecated and will cause an error in 8.0.', __CLASS__, __FUNCTION__);
|
||||
}
|
||||
|
||||
$this->data['Expires'] = null === $timestamp ? null : (\is_numeric($timestamp) ? (int) $timestamp : \strtotime((string) $timestamp));
|
||||
}
|
||||
|
||||
/**
|
||||
* Get whether or not this is a secure cookie
|
||||
* Get whether or not this is a secure cookie.
|
||||
*
|
||||
* @return bool|null
|
||||
* @return bool
|
||||
*/
|
||||
public function getSecure()
|
||||
{
|
||||
@@ -235,17 +266,21 @@ class SetCookie
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether or not the cookie is secure
|
||||
* Set whether or not the cookie is secure.
|
||||
*
|
||||
* @param bool $secure Set to true or false if secure
|
||||
*/
|
||||
public function setSecure($secure)
|
||||
public function setSecure($secure): void
|
||||
{
|
||||
$this->data['Secure'] = $secure;
|
||||
if (!is_bool($secure)) {
|
||||
trigger_deprecation('guzzlehttp/guzzle', '7.4', 'Not passing a bool to %s::%s() is deprecated and will cause an error in 8.0.', __CLASS__, __FUNCTION__);
|
||||
}
|
||||
|
||||
$this->data['Secure'] = (bool) $secure;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get whether or not this is a session cookie
|
||||
* Get whether or not this is a session cookie.
|
||||
*
|
||||
* @return bool|null
|
||||
*/
|
||||
@@ -255,17 +290,21 @@ class SetCookie
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether or not this is a session cookie
|
||||
* Set whether or not this is a session cookie.
|
||||
*
|
||||
* @param bool $discard Set to true or false if this is a session cookie
|
||||
*/
|
||||
public function setDiscard($discard)
|
||||
public function setDiscard($discard): void
|
||||
{
|
||||
$this->data['Discard'] = $discard;
|
||||
if (!is_bool($discard)) {
|
||||
trigger_deprecation('guzzlehttp/guzzle', '7.4', 'Not passing a bool to %s::%s() is deprecated and will cause an error in 8.0.', __CLASS__, __FUNCTION__);
|
||||
}
|
||||
|
||||
$this->data['Discard'] = (bool) $discard;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get whether or not this is an HTTP only cookie
|
||||
* Get whether or not this is an HTTP only cookie.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
@@ -275,13 +314,17 @@ class SetCookie
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether or not this is an HTTP only cookie
|
||||
* Set whether or not this is an HTTP only cookie.
|
||||
*
|
||||
* @param bool $httpOnly Set to true or false if this is HTTP only
|
||||
*/
|
||||
public function setHttpOnly($httpOnly)
|
||||
public function setHttpOnly($httpOnly): void
|
||||
{
|
||||
$this->data['HttpOnly'] = $httpOnly;
|
||||
if (!is_bool($httpOnly)) {
|
||||
trigger_deprecation('guzzlehttp/guzzle', '7.4', 'Not passing a bool to %s::%s() is deprecated and will cause an error in 8.0.', __CLASS__, __FUNCTION__);
|
||||
}
|
||||
|
||||
$this->data['HttpOnly'] = (bool) $httpOnly;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -298,10 +341,8 @@ class SetCookie
|
||||
* path is a %x2F ("/") character.
|
||||
*
|
||||
* @param string $requestPath Path to check against
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function matchesPath($requestPath)
|
||||
public function matchesPath(string $requestPath): bool
|
||||
{
|
||||
$cookiePath = $this->getPath();
|
||||
|
||||
@@ -311,27 +352,25 @@ class SetCookie
|
||||
}
|
||||
|
||||
// Ensure that the cookie-path is a prefix of the request path.
|
||||
if (0 !== strpos($requestPath, $cookiePath)) {
|
||||
if (0 !== \strpos($requestPath, $cookiePath)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Match if the last character of the cookie-path is "/"
|
||||
if (substr($cookiePath, -1, 1) === '/') {
|
||||
if (\substr($cookiePath, -1, 1) === '/') {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Match if the first character not included in cookie path is "/"
|
||||
return substr($requestPath, strlen($cookiePath), 1) === '/';
|
||||
return \substr($requestPath, \strlen($cookiePath), 1) === '/';
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the cookie matches a domain value
|
||||
* Check if the cookie matches a domain value.
|
||||
*
|
||||
* @param string $domain Domain to check against
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function matchesDomain($domain)
|
||||
public function matchesDomain(string $domain): bool
|
||||
{
|
||||
$cookieDomain = $this->getDomain();
|
||||
if (null === $cookieDomain) {
|
||||
@@ -339,10 +378,10 @@ class SetCookie
|
||||
}
|
||||
|
||||
// Remove the leading '.' as per spec in RFC 6265.
|
||||
// http://tools.ietf.org/html/rfc6265#section-5.2.3
|
||||
$cookieDomain = ltrim(strtolower($cookieDomain), '.');
|
||||
// https://tools.ietf.org/html/rfc6265#section-5.2.3
|
||||
$cookieDomain = \ltrim(\strtolower($cookieDomain), '.');
|
||||
|
||||
$domain = strtolower($domain);
|
||||
$domain = \strtolower($domain);
|
||||
|
||||
// Domain not set or exact match.
|
||||
if ('' === $cookieDomain || $domain === $cookieDomain) {
|
||||
@@ -350,39 +389,36 @@ class SetCookie
|
||||
}
|
||||
|
||||
// Matching the subdomain according to RFC 6265.
|
||||
// http://tools.ietf.org/html/rfc6265#section-5.1.3
|
||||
if (filter_var($domain, FILTER_VALIDATE_IP)) {
|
||||
// https://tools.ietf.org/html/rfc6265#section-5.1.3
|
||||
if (\filter_var($domain, \FILTER_VALIDATE_IP)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (bool) preg_match('/\.' . preg_quote($cookieDomain, '/') . '$/', $domain);
|
||||
return (bool) \preg_match('/\.' . \preg_quote($cookieDomain, '/') . '$/', $domain);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the cookie is expired
|
||||
*
|
||||
* @return bool
|
||||
* Check if the cookie is expired.
|
||||
*/
|
||||
public function isExpired()
|
||||
public function isExpired(): bool
|
||||
{
|
||||
return $this->getExpires() !== null && time() > $this->getExpires();
|
||||
return $this->getExpires() !== null && \time() > $this->getExpires();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the cookie is valid according to RFC 6265
|
||||
* Check if the cookie is valid according to RFC 6265.
|
||||
*
|
||||
* @return bool|string Returns true if valid or an error message if invalid
|
||||
*/
|
||||
public function validate()
|
||||
{
|
||||
// Names must not be empty, but can be 0
|
||||
$name = $this->getName();
|
||||
if (empty($name) && !is_numeric($name)) {
|
||||
if ($name === '') {
|
||||
return 'The cookie name must not be empty';
|
||||
}
|
||||
|
||||
// Check if any of the invalid characters are present in the cookie name
|
||||
if (preg_match(
|
||||
if (\preg_match(
|
||||
'/[\x00-\x20\x22\x28-\x29\x2c\x2f\x3a-\x40\x5c\x7b\x7d\x7f]/',
|
||||
$name
|
||||
)) {
|
||||
@@ -391,17 +427,17 @@ class SetCookie
|
||||
. 'following characters: ()<>@,;:\"/?={}';
|
||||
}
|
||||
|
||||
// Value must not be empty, but can be 0
|
||||
// Value must not be null. 0 and empty string are valid. Empty strings
|
||||
// are technically against RFC 6265, but known to happen in the wild.
|
||||
$value = $this->getValue();
|
||||
if (empty($value) && !is_numeric($value)) {
|
||||
if ($value === null) {
|
||||
return 'The cookie value must not be empty';
|
||||
}
|
||||
|
||||
// Domains must not be empty, but can be 0
|
||||
// A "0" is not a valid internet domain, but may be used as server name
|
||||
// in a private network.
|
||||
// Domains must not be empty, but can be 0. "0" is not a valid internet
|
||||
// domain, but may be used as server name in a private network.
|
||||
$domain = $this->getDomain();
|
||||
if (empty($domain) && !is_numeric($domain)) {
|
||||
if ($domain === null || $domain === '') {
|
||||
return 'The cookie domain must not be empty';
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
namespace GuzzleHttp\Exception;
|
||||
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
@@ -10,18 +11,29 @@ use Psr\Http\Message\ResponseInterface;
|
||||
class BadResponseException extends RequestException
|
||||
{
|
||||
public function __construct(
|
||||
$message,
|
||||
string $message,
|
||||
RequestInterface $request,
|
||||
ResponseInterface $response = null,
|
||||
\Exception $previous = null,
|
||||
ResponseInterface $response,
|
||||
\Throwable $previous = null,
|
||||
array $handlerContext = []
|
||||
) {
|
||||
if (null === $response) {
|
||||
@trigger_error(
|
||||
'Instantiating the ' . __CLASS__ . ' class without a Response is deprecated since version 6.3 and will be removed in 7.0.',
|
||||
E_USER_DEPRECATED
|
||||
);
|
||||
}
|
||||
parent::__construct($message, $request, $response, $previous, $handlerContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* Current exception and the ones that extend it will always have a response.
|
||||
*/
|
||||
public function hasResponse(): bool
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function narrows the return type from the parent class and does not allow it to be nullable.
|
||||
*/
|
||||
public function getResponse(): ResponseInterface
|
||||
{
|
||||
/** @var ResponseInterface */
|
||||
return parent::getResponse();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
namespace GuzzleHttp\Exception;
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace GuzzleHttp\Exception;
|
||||
|
||||
use Psr\Http\Client\NetworkExceptionInterface;
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
|
||||
/**
|
||||
@@ -8,30 +10,47 @@ use Psr\Http\Message\RequestInterface;
|
||||
*
|
||||
* Note that no response is present for a ConnectException
|
||||
*/
|
||||
class ConnectException extends RequestException
|
||||
class ConnectException extends TransferException implements NetworkExceptionInterface
|
||||
{
|
||||
/**
|
||||
* @var RequestInterface
|
||||
*/
|
||||
private $request;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $handlerContext;
|
||||
|
||||
public function __construct(
|
||||
$message,
|
||||
string $message,
|
||||
RequestInterface $request,
|
||||
\Exception $previous = null,
|
||||
\Throwable $previous = null,
|
||||
array $handlerContext = []
|
||||
) {
|
||||
parent::__construct($message, $request, null, $previous, $handlerContext);
|
||||
parent::__construct($message, 0, $previous);
|
||||
$this->request = $request;
|
||||
$this->handlerContext = $handlerContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return null
|
||||
* Get the request that caused the exception
|
||||
*/
|
||||
public function getResponse()
|
||||
public function getRequest(): RequestInterface
|
||||
{
|
||||
return null;
|
||||
return $this->request;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
* Get contextual information about the error from the underlying handler.
|
||||
*
|
||||
* The contents of this array will vary depending on which handler you are
|
||||
* using. It may also be just an empty array. Relying on this data will
|
||||
* couple you to a specific handler, but can give more debug information
|
||||
* when needed.
|
||||
*/
|
||||
public function hasResponse()
|
||||
public function getHandlerContext(): array
|
||||
{
|
||||
return false;
|
||||
return $this->handlerContext;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,23 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace GuzzleHttp\Exception;
|
||||
|
||||
use Throwable;
|
||||
use Psr\Http\Client\ClientExceptionInterface;
|
||||
|
||||
if (interface_exists(Throwable::class)) {
|
||||
interface GuzzleException extends Throwable
|
||||
{
|
||||
}
|
||||
} else {
|
||||
/**
|
||||
* @method string getMessage()
|
||||
* @method \Throwable|null getPrevious()
|
||||
* @method mixed getCode()
|
||||
* @method string getFile()
|
||||
* @method int getLine()
|
||||
* @method array getTrace()
|
||||
* @method string getTraceAsString()
|
||||
*/
|
||||
interface GuzzleException
|
||||
{
|
||||
}
|
||||
interface GuzzleException extends ClientExceptionInterface
|
||||
{
|
||||
}
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace GuzzleHttp\Exception;
|
||||
|
||||
use GuzzleHttp\Promise\PromiseInterface;
|
||||
use GuzzleHttp\BodySummarizer;
|
||||
use GuzzleHttp\BodySummarizerInterface;
|
||||
use Psr\Http\Client\RequestExceptionInterface;
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\UriInterface;
|
||||
@@ -9,28 +12,32 @@ use Psr\Http\Message\UriInterface;
|
||||
/**
|
||||
* HTTP Request exception
|
||||
*/
|
||||
class RequestException extends TransferException
|
||||
class RequestException extends TransferException implements RequestExceptionInterface
|
||||
{
|
||||
/** @var RequestInterface */
|
||||
/**
|
||||
* @var RequestInterface
|
||||
*/
|
||||
private $request;
|
||||
|
||||
/** @var ResponseInterface|null */
|
||||
/**
|
||||
* @var ResponseInterface|null
|
||||
*/
|
||||
private $response;
|
||||
|
||||
/** @var array */
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $handlerContext;
|
||||
|
||||
public function __construct(
|
||||
$message,
|
||||
string $message,
|
||||
RequestInterface $request,
|
||||
ResponseInterface $response = null,
|
||||
\Exception $previous = null,
|
||||
\Throwable $previous = null,
|
||||
array $handlerContext = []
|
||||
) {
|
||||
// Set the code of the exception if the response is set and not future.
|
||||
$code = $response && !($response instanceof PromiseInterface)
|
||||
? $response->getStatusCode()
|
||||
: 0;
|
||||
$code = $response ? $response->getStatusCode() : 0;
|
||||
parent::__construct($message, $code, $previous);
|
||||
$this->request = $request;
|
||||
$this->response = $response;
|
||||
@@ -39,46 +46,39 @@ class RequestException extends TransferException
|
||||
|
||||
/**
|
||||
* Wrap non-RequestExceptions with a RequestException
|
||||
*
|
||||
* @param RequestInterface $request
|
||||
* @param \Exception $e
|
||||
*
|
||||
* @return RequestException
|
||||
*/
|
||||
public static function wrapException(RequestInterface $request, \Exception $e)
|
||||
public static function wrapException(RequestInterface $request, \Throwable $e): RequestException
|
||||
{
|
||||
return $e instanceof RequestException
|
||||
? $e
|
||||
: new RequestException($e->getMessage(), $request, null, $e);
|
||||
return $e instanceof RequestException ? $e : new RequestException($e->getMessage(), $request, null, $e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method to create a new exception with a normalized error message
|
||||
*
|
||||
* @param RequestInterface $request Request
|
||||
* @param ResponseInterface $response Response received
|
||||
* @param \Exception $previous Previous exception
|
||||
* @param array $ctx Optional handler context.
|
||||
*
|
||||
* @return self
|
||||
* @param RequestInterface $request Request sent
|
||||
* @param ResponseInterface $response Response received
|
||||
* @param \Throwable|null $previous Previous exception
|
||||
* @param array $handlerContext Optional handler context
|
||||
* @param BodySummarizerInterface|null $bodySummarizer Optional body summarizer
|
||||
*/
|
||||
public static function create(
|
||||
RequestInterface $request,
|
||||
ResponseInterface $response = null,
|
||||
\Exception $previous = null,
|
||||
array $ctx = []
|
||||
) {
|
||||
\Throwable $previous = null,
|
||||
array $handlerContext = [],
|
||||
BodySummarizerInterface $bodySummarizer = null
|
||||
): self {
|
||||
if (!$response) {
|
||||
return new self(
|
||||
'Error completing request',
|
||||
$request,
|
||||
null,
|
||||
$previous,
|
||||
$ctx
|
||||
$handlerContext
|
||||
);
|
||||
}
|
||||
|
||||
$level = (int) floor($response->getStatusCode() / 100);
|
||||
$level = (int) \floor($response->getStatusCode() / 100);
|
||||
if ($level === 4) {
|
||||
$label = 'Client error';
|
||||
$className = ClientException::class;
|
||||
@@ -95,51 +95,33 @@ class RequestException extends TransferException
|
||||
|
||||
// Client Error: `GET /` resulted in a `404 Not Found` response:
|
||||
// <html> ... (truncated)
|
||||
$message = sprintf(
|
||||
$message = \sprintf(
|
||||
'%s: `%s %s` resulted in a `%s %s` response',
|
||||
$label,
|
||||
$request->getMethod(),
|
||||
$uri,
|
||||
$uri->__toString(),
|
||||
$response->getStatusCode(),
|
||||
$response->getReasonPhrase()
|
||||
);
|
||||
|
||||
$summary = static::getResponseBodySummary($response);
|
||||
$summary = ($bodySummarizer ?? new BodySummarizer())->summarize($response);
|
||||
|
||||
if ($summary !== null) {
|
||||
$message .= ":\n{$summary}\n";
|
||||
}
|
||||
|
||||
return new $className($message, $request, $response, $previous, $ctx);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a short summary of the response
|
||||
*
|
||||
* Will return `null` if the response is not printable.
|
||||
*
|
||||
* @param ResponseInterface $response
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public static function getResponseBodySummary(ResponseInterface $response)
|
||||
{
|
||||
return \GuzzleHttp\Psr7\get_message_body_summary($response);
|
||||
return new $className($message, $request, $response, $previous, $handlerContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obfuscates URI if there is a username and a password present
|
||||
*
|
||||
* @param UriInterface $uri
|
||||
*
|
||||
* @return UriInterface
|
||||
*/
|
||||
private static function obfuscateUri(UriInterface $uri)
|
||||
private static function obfuscateUri(UriInterface $uri): UriInterface
|
||||
{
|
||||
$userInfo = $uri->getUserInfo();
|
||||
|
||||
if (false !== ($pos = strpos($userInfo, ':'))) {
|
||||
return $uri->withUserInfo(substr($userInfo, 0, $pos), '***');
|
||||
if (false !== ($pos = \strpos($userInfo, ':'))) {
|
||||
return $uri->withUserInfo(\substr($userInfo, 0, $pos), '***');
|
||||
}
|
||||
|
||||
return $uri;
|
||||
@@ -147,30 +129,24 @@ class RequestException extends TransferException
|
||||
|
||||
/**
|
||||
* Get the request that caused the exception
|
||||
*
|
||||
* @return RequestInterface
|
||||
*/
|
||||
public function getRequest()
|
||||
public function getRequest(): RequestInterface
|
||||
{
|
||||
return $this->request;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the associated response
|
||||
*
|
||||
* @return ResponseInterface|null
|
||||
*/
|
||||
public function getResponse()
|
||||
public function getResponse(): ?ResponseInterface
|
||||
{
|
||||
return $this->response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a response was received
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasResponse()
|
||||
public function hasResponse(): bool
|
||||
{
|
||||
return $this->response !== null;
|
||||
}
|
||||
@@ -182,10 +158,8 @@ class RequestException extends TransferException
|
||||
* using. It may also be just an empty array. Relying on this data will
|
||||
* couple you to a specific handler, but can give more debug information
|
||||
* when needed.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getHandlerContext()
|
||||
public function getHandlerContext(): array
|
||||
{
|
||||
return $this->handlerContext;
|
||||
}
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
<?php
|
||||
namespace GuzzleHttp\Exception;
|
||||
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
|
||||
/**
|
||||
* Exception thrown when a seek fails on a stream.
|
||||
*/
|
||||
class SeekException extends \RuntimeException implements GuzzleException
|
||||
{
|
||||
private $stream;
|
||||
|
||||
public function __construct(StreamInterface $stream, $pos = 0, $msg = '')
|
||||
{
|
||||
$this->stream = $stream;
|
||||
$msg = $msg ?: 'Could not seek the stream to position ' . $pos;
|
||||
parent::__construct($msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return StreamInterface
|
||||
*/
|
||||
public function getStream()
|
||||
{
|
||||
return $this->stream;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
namespace GuzzleHttp\Exception;
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
namespace GuzzleHttp\Exception;
|
||||
|
||||
class TooManyRedirectsException extends RequestException
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
namespace GuzzleHttp\Exception;
|
||||
|
||||
class TransferException extends \RuntimeException implements GuzzleException
|
||||
|
||||
412
vendor/guzzlehttp/guzzle/src/Handler/CurlFactory.php
vendored
412
vendor/guzzlehttp/guzzle/src/Handler/CurlFactory.php
vendored
@@ -1,37 +1,50 @@
|
||||
<?php
|
||||
|
||||
namespace GuzzleHttp\Handler;
|
||||
|
||||
use GuzzleHttp\Exception\ConnectException;
|
||||
use GuzzleHttp\Exception\RequestException;
|
||||
use GuzzleHttp\Promise as P;
|
||||
use GuzzleHttp\Promise\FulfilledPromise;
|
||||
use GuzzleHttp\Psr7;
|
||||
use GuzzleHttp\Promise\PromiseInterface;
|
||||
use GuzzleHttp\Psr7\LazyOpenStream;
|
||||
use GuzzleHttp\TransferStats;
|
||||
use GuzzleHttp\Utils;
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
|
||||
/**
|
||||
* Creates curl resources from a request
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class CurlFactory implements CurlFactoryInterface
|
||||
{
|
||||
const CURL_VERSION_STR = 'curl_version';
|
||||
const LOW_CURL_VERSION_NUMBER = '7.21.2';
|
||||
public const CURL_VERSION_STR = 'curl_version';
|
||||
|
||||
/** @var array */
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
public const LOW_CURL_VERSION_NUMBER = '7.21.2';
|
||||
|
||||
/**
|
||||
* @var resource[]|\CurlHandle[]
|
||||
*/
|
||||
private $handles = [];
|
||||
|
||||
/** @var int Total number of idle handles to keep in cache */
|
||||
/**
|
||||
* @var int Total number of idle handles to keep in cache
|
||||
*/
|
||||
private $maxHandles;
|
||||
|
||||
/**
|
||||
* @param int $maxHandles Maximum number of idle handles.
|
||||
*/
|
||||
public function __construct($maxHandles)
|
||||
public function __construct(int $maxHandles)
|
||||
{
|
||||
$this->maxHandles = $maxHandles;
|
||||
}
|
||||
|
||||
public function create(RequestInterface $request, array $options)
|
||||
public function create(RequestInterface $request, array $options): EasyHandle
|
||||
{
|
||||
if (isset($options['curl']['body_as_string'])) {
|
||||
$options['_body_as_string'] = $options['curl']['body_as_string'];
|
||||
@@ -49,35 +62,33 @@ class CurlFactory implements CurlFactoryInterface
|
||||
|
||||
// Add handler options from the request configuration options
|
||||
if (isset($options['curl'])) {
|
||||
$conf = array_replace($conf, $options['curl']);
|
||||
$conf = \array_replace($conf, $options['curl']);
|
||||
}
|
||||
|
||||
$conf[CURLOPT_HEADERFUNCTION] = $this->createHeaderFn($easy);
|
||||
$easy->handle = $this->handles
|
||||
? array_pop($this->handles)
|
||||
: curl_init();
|
||||
$conf[\CURLOPT_HEADERFUNCTION] = $this->createHeaderFn($easy);
|
||||
$easy->handle = $this->handles ? \array_pop($this->handles) : \curl_init();
|
||||
curl_setopt_array($easy->handle, $conf);
|
||||
|
||||
return $easy;
|
||||
}
|
||||
|
||||
public function release(EasyHandle $easy)
|
||||
public function release(EasyHandle $easy): void
|
||||
{
|
||||
$resource = $easy->handle;
|
||||
unset($easy->handle);
|
||||
|
||||
if (count($this->handles) >= $this->maxHandles) {
|
||||
curl_close($resource);
|
||||
if (\count($this->handles) >= $this->maxHandles) {
|
||||
\curl_close($resource);
|
||||
} else {
|
||||
// Remove all callback functions as they can hold onto references
|
||||
// and are not cleaned up by curl_reset. Using curl_setopt_array
|
||||
// does not work for some reason, so removing each one
|
||||
// individually.
|
||||
curl_setopt($resource, CURLOPT_HEADERFUNCTION, null);
|
||||
curl_setopt($resource, CURLOPT_READFUNCTION, null);
|
||||
curl_setopt($resource, CURLOPT_WRITEFUNCTION, null);
|
||||
curl_setopt($resource, CURLOPT_PROGRESSFUNCTION, null);
|
||||
curl_reset($resource);
|
||||
\curl_setopt($resource, \CURLOPT_HEADERFUNCTION, null);
|
||||
\curl_setopt($resource, \CURLOPT_READFUNCTION, null);
|
||||
\curl_setopt($resource, \CURLOPT_WRITEFUNCTION, null);
|
||||
\curl_setopt($resource, \CURLOPT_PROGRESSFUNCTION, null);
|
||||
\curl_reset($resource);
|
||||
$this->handles[] = $resource;
|
||||
}
|
||||
}
|
||||
@@ -86,17 +97,11 @@ class CurlFactory implements CurlFactoryInterface
|
||||
* Completes a cURL transaction, either returning a response promise or a
|
||||
* rejected promise.
|
||||
*
|
||||
* @param callable $handler
|
||||
* @param EasyHandle $easy
|
||||
* @param CurlFactoryInterface $factory Dictates how the handle is released
|
||||
*
|
||||
* @return \GuzzleHttp\Promise\PromiseInterface
|
||||
* @param callable(RequestInterface, array): PromiseInterface $handler
|
||||
* @param CurlFactoryInterface $factory Dictates how the handle is released
|
||||
*/
|
||||
public static function finish(
|
||||
callable $handler,
|
||||
EasyHandle $easy,
|
||||
CurlFactoryInterface $factory
|
||||
) {
|
||||
public static function finish(callable $handler, EasyHandle $easy, CurlFactoryInterface $factory): PromiseInterface
|
||||
{
|
||||
if (isset($easy->options['on_stats'])) {
|
||||
self::invokeStats($easy);
|
||||
}
|
||||
@@ -117,10 +122,10 @@ class CurlFactory implements CurlFactoryInterface
|
||||
return new FulfilledPromise($easy->response);
|
||||
}
|
||||
|
||||
private static function invokeStats(EasyHandle $easy)
|
||||
private static function invokeStats(EasyHandle $easy): void
|
||||
{
|
||||
$curlStats = curl_getinfo($easy->handle);
|
||||
$curlStats['appconnect_time'] = curl_getinfo($easy->handle, CURLINFO_APPCONNECT_TIME);
|
||||
$curlStats = \curl_getinfo($easy->handle);
|
||||
$curlStats['appconnect_time'] = \curl_getinfo($easy->handle, \CURLINFO_APPCONNECT_TIME);
|
||||
$stats = new TransferStats(
|
||||
$easy->request,
|
||||
$easy->response,
|
||||
@@ -128,47 +133,57 @@ class CurlFactory implements CurlFactoryInterface
|
||||
$easy->errno,
|
||||
$curlStats
|
||||
);
|
||||
call_user_func($easy->options['on_stats'], $stats);
|
||||
($easy->options['on_stats'])($stats);
|
||||
}
|
||||
|
||||
private static function finishError(
|
||||
callable $handler,
|
||||
EasyHandle $easy,
|
||||
CurlFactoryInterface $factory
|
||||
) {
|
||||
/**
|
||||
* @param callable(RequestInterface, array): PromiseInterface $handler
|
||||
*/
|
||||
private static function finishError(callable $handler, EasyHandle $easy, CurlFactoryInterface $factory): PromiseInterface
|
||||
{
|
||||
// Get error information and release the handle to the factory.
|
||||
$ctx = [
|
||||
'errno' => $easy->errno,
|
||||
'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'];
|
||||
'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'];
|
||||
$factory->release($easy);
|
||||
|
||||
// Retry when nothing is present or when curl failed to rewind.
|
||||
if (empty($easy->options['_err_message'])
|
||||
&& (!$easy->errno || $easy->errno == 65)
|
||||
) {
|
||||
if (empty($easy->options['_err_message']) && (!$easy->errno || $easy->errno == 65)) {
|
||||
return self::retryFailedRewind($handler, $easy, $ctx);
|
||||
}
|
||||
|
||||
return self::createRejection($easy, $ctx);
|
||||
}
|
||||
|
||||
private static function createRejection(EasyHandle $easy, array $ctx)
|
||||
private static function createRejection(EasyHandle $easy, array $ctx): PromiseInterface
|
||||
{
|
||||
static $connectionErrors = [
|
||||
CURLE_OPERATION_TIMEOUTED => true,
|
||||
CURLE_COULDNT_RESOLVE_HOST => true,
|
||||
CURLE_COULDNT_CONNECT => true,
|
||||
CURLE_SSL_CONNECT_ERROR => true,
|
||||
CURLE_GOT_NOTHING => true,
|
||||
\CURLE_OPERATION_TIMEOUTED => true,
|
||||
\CURLE_COULDNT_RESOLVE_HOST => true,
|
||||
\CURLE_COULDNT_CONNECT => true,
|
||||
\CURLE_SSL_CONNECT_ERROR => true,
|
||||
\CURLE_GOT_NOTHING => true,
|
||||
];
|
||||
|
||||
if ($easy->createResponseException) {
|
||||
return P\Create::rejectionFor(
|
||||
new RequestException(
|
||||
'An error was encountered while creating the response',
|
||||
$easy->request,
|
||||
$easy->response,
|
||||
$easy->createResponseException,
|
||||
$ctx
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// If an exception was encountered during the onHeaders event, then
|
||||
// return a rejected promise that wraps that exception.
|
||||
if ($easy->onHeadersException) {
|
||||
return \GuzzleHttp\Promise\rejection_for(
|
||||
return P\Create::rejectionFor(
|
||||
new RequestException(
|
||||
'An error was encountered during the on_headers event',
|
||||
$easy->request,
|
||||
@@ -178,21 +193,16 @@ class CurlFactory implements CurlFactoryInterface
|
||||
)
|
||||
);
|
||||
}
|
||||
if (version_compare($ctx[self::CURL_VERSION_STR], self::LOW_CURL_VERSION_NUMBER)) {
|
||||
$message = sprintf(
|
||||
'cURL error %s: %s (%s)',
|
||||
$ctx['errno'],
|
||||
$ctx['error'],
|
||||
'see https://curl.haxx.se/libcurl/c/libcurl-errors.html'
|
||||
);
|
||||
} else {
|
||||
$message = sprintf(
|
||||
'cURL error %s: %s (%s) for %s',
|
||||
$ctx['errno'],
|
||||
$ctx['error'],
|
||||
'see https://curl.haxx.se/libcurl/c/libcurl-errors.html',
|
||||
$easy->request->getUri()
|
||||
);
|
||||
|
||||
$message = \sprintf(
|
||||
'cURL error %s: %s (%s)',
|
||||
$ctx['errno'],
|
||||
$ctx['error'],
|
||||
'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);
|
||||
}
|
||||
|
||||
// Create a connection exception if it was a specific error code.
|
||||
@@ -200,37 +210,40 @@ class CurlFactory implements CurlFactoryInterface
|
||||
? new ConnectException($message, $easy->request, null, $ctx)
|
||||
: new RequestException($message, $easy->request, $easy->response, null, $ctx);
|
||||
|
||||
return \GuzzleHttp\Promise\rejection_for($error);
|
||||
return P\Create::rejectionFor($error);
|
||||
}
|
||||
|
||||
private function getDefaultConf(EasyHandle $easy)
|
||||
/**
|
||||
* @return array<int|string, mixed>
|
||||
*/
|
||||
private function getDefaultConf(EasyHandle $easy): array
|
||||
{
|
||||
$conf = [
|
||||
'_headers' => $easy->request->getHeaders(),
|
||||
CURLOPT_CUSTOMREQUEST => $easy->request->getMethod(),
|
||||
CURLOPT_URL => (string) $easy->request->getUri()->withFragment(''),
|
||||
CURLOPT_RETURNTRANSFER => false,
|
||||
CURLOPT_HEADER => false,
|
||||
CURLOPT_CONNECTTIMEOUT => 150,
|
||||
'_headers' => $easy->request->getHeaders(),
|
||||
\CURLOPT_CUSTOMREQUEST => $easy->request->getMethod(),
|
||||
\CURLOPT_URL => (string) $easy->request->getUri()->withFragment(''),
|
||||
\CURLOPT_RETURNTRANSFER => false,
|
||||
\CURLOPT_HEADER => false,
|
||||
\CURLOPT_CONNECTTIMEOUT => 150,
|
||||
];
|
||||
|
||||
if (defined('CURLOPT_PROTOCOLS')) {
|
||||
$conf[CURLOPT_PROTOCOLS] = CURLPROTO_HTTP | CURLPROTO_HTTPS;
|
||||
if (\defined('CURLOPT_PROTOCOLS')) {
|
||||
$conf[\CURLOPT_PROTOCOLS] = \CURLPROTO_HTTP | \CURLPROTO_HTTPS;
|
||||
}
|
||||
|
||||
$version = $easy->request->getProtocolVersion();
|
||||
if ($version == 1.1) {
|
||||
$conf[CURLOPT_HTTP_VERSION] = CURL_HTTP_VERSION_1_1;
|
||||
$conf[\CURLOPT_HTTP_VERSION] = \CURL_HTTP_VERSION_1_1;
|
||||
} elseif ($version == 2.0) {
|
||||
$conf[CURLOPT_HTTP_VERSION] = CURL_HTTP_VERSION_2_0;
|
||||
$conf[\CURLOPT_HTTP_VERSION] = \CURL_HTTP_VERSION_2_0;
|
||||
} else {
|
||||
$conf[CURLOPT_HTTP_VERSION] = CURL_HTTP_VERSION_1_0;
|
||||
$conf[\CURLOPT_HTTP_VERSION] = \CURL_HTTP_VERSION_1_0;
|
||||
}
|
||||
|
||||
return $conf;
|
||||
}
|
||||
|
||||
private function applyMethod(EasyHandle $easy, array &$conf)
|
||||
private function applyMethod(EasyHandle $easy, array &$conf): void
|
||||
{
|
||||
$body = $easy->request->getBody();
|
||||
$size = $body->getSize();
|
||||
@@ -242,22 +255,22 @@ class CurlFactory implements CurlFactoryInterface
|
||||
|
||||
$method = $easy->request->getMethod();
|
||||
if ($method === 'PUT' || $method === 'POST') {
|
||||
// See http://tools.ietf.org/html/rfc7230#section-3.3.2
|
||||
// See https://tools.ietf.org/html/rfc7230#section-3.3.2
|
||||
if (!$easy->request->hasHeader('Content-Length')) {
|
||||
$conf[CURLOPT_HTTPHEADER][] = 'Content-Length: 0';
|
||||
$conf[\CURLOPT_HTTPHEADER][] = 'Content-Length: 0';
|
||||
}
|
||||
} elseif ($method === 'HEAD') {
|
||||
$conf[CURLOPT_NOBODY] = true;
|
||||
$conf[\CURLOPT_NOBODY] = true;
|
||||
unset(
|
||||
$conf[CURLOPT_WRITEFUNCTION],
|
||||
$conf[CURLOPT_READFUNCTION],
|
||||
$conf[CURLOPT_FILE],
|
||||
$conf[CURLOPT_INFILE]
|
||||
$conf[\CURLOPT_WRITEFUNCTION],
|
||||
$conf[\CURLOPT_READFUNCTION],
|
||||
$conf[\CURLOPT_FILE],
|
||||
$conf[\CURLOPT_INFILE]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private function applyBody(RequestInterface $request, array $options, array &$conf)
|
||||
private function applyBody(RequestInterface $request, array $options, array &$conf): void
|
||||
{
|
||||
$size = $request->hasHeader('Content-Length')
|
||||
? (int) $request->getHeaderLine('Content-Length')
|
||||
@@ -265,40 +278,38 @@ class CurlFactory implements CurlFactoryInterface
|
||||
|
||||
// Send the body as a string if the size is less than 1MB OR if the
|
||||
// [curl][body_as_string] request value is set.
|
||||
if (($size !== null && $size < 1000000) ||
|
||||
!empty($options['_body_as_string'])
|
||||
) {
|
||||
$conf[CURLOPT_POSTFIELDS] = (string) $request->getBody();
|
||||
if (($size !== null && $size < 1000000) || !empty($options['_body_as_string'])) {
|
||||
$conf[\CURLOPT_POSTFIELDS] = (string) $request->getBody();
|
||||
// Don't duplicate the Content-Length header
|
||||
$this->removeHeader('Content-Length', $conf);
|
||||
$this->removeHeader('Transfer-Encoding', $conf);
|
||||
} else {
|
||||
$conf[CURLOPT_UPLOAD] = true;
|
||||
$conf[\CURLOPT_UPLOAD] = true;
|
||||
if ($size !== null) {
|
||||
$conf[CURLOPT_INFILESIZE] = $size;
|
||||
$conf[\CURLOPT_INFILESIZE] = $size;
|
||||
$this->removeHeader('Content-Length', $conf);
|
||||
}
|
||||
$body = $request->getBody();
|
||||
if ($body->isSeekable()) {
|
||||
$body->rewind();
|
||||
}
|
||||
$conf[CURLOPT_READFUNCTION] = function ($ch, $fd, $length) use ($body) {
|
||||
$conf[\CURLOPT_READFUNCTION] = static function ($ch, $fd, $length) use ($body) {
|
||||
return $body->read($length);
|
||||
};
|
||||
}
|
||||
|
||||
// If the Expect header is not present, prevent curl from adding it
|
||||
if (!$request->hasHeader('Expect')) {
|
||||
$conf[CURLOPT_HTTPHEADER][] = 'Expect:';
|
||||
$conf[\CURLOPT_HTTPHEADER][] = 'Expect:';
|
||||
}
|
||||
|
||||
// cURL sometimes adds a content-type by default. Prevent this.
|
||||
if (!$request->hasHeader('Content-Type')) {
|
||||
$conf[CURLOPT_HTTPHEADER][] = 'Content-Type:';
|
||||
$conf[\CURLOPT_HTTPHEADER][] = 'Content-Type:';
|
||||
}
|
||||
}
|
||||
|
||||
private function applyHeaders(EasyHandle $easy, array &$conf)
|
||||
private function applyHeaders(EasyHandle $easy, array &$conf): void
|
||||
{
|
||||
foreach ($conf['_headers'] as $name => $values) {
|
||||
foreach ($values as $value) {
|
||||
@@ -306,16 +317,16 @@ class CurlFactory implements CurlFactoryInterface
|
||||
if ($value === '') {
|
||||
// cURL requires a special format for empty headers.
|
||||
// See https://github.com/guzzle/guzzle/issues/1882 for more details.
|
||||
$conf[CURLOPT_HTTPHEADER][] = "$name;";
|
||||
$conf[\CURLOPT_HTTPHEADER][] = "$name;";
|
||||
} else {
|
||||
$conf[CURLOPT_HTTPHEADER][] = "$name: $value";
|
||||
$conf[\CURLOPT_HTTPHEADER][] = "$name: $value";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Remove the Accept header if one was not set
|
||||
if (!$easy->request->hasHeader('Accept')) {
|
||||
$conf[CURLOPT_HTTPHEADER][] = 'Accept:';
|
||||
$conf[\CURLOPT_HTTPHEADER][] = 'Accept:';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -325,115 +336,115 @@ class CurlFactory implements CurlFactoryInterface
|
||||
* @param string $name Case-insensitive header to remove
|
||||
* @param array $options Array of options to modify
|
||||
*/
|
||||
private function removeHeader($name, array &$options)
|
||||
private function removeHeader(string $name, array &$options): void
|
||||
{
|
||||
foreach (array_keys($options['_headers']) as $key) {
|
||||
if (!strcasecmp($key, $name)) {
|
||||
foreach (\array_keys($options['_headers']) as $key) {
|
||||
if (!\strcasecmp($key, $name)) {
|
||||
unset($options['_headers'][$key]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function applyHandlerOptions(EasyHandle $easy, array &$conf)
|
||||
private function applyHandlerOptions(EasyHandle $easy, array &$conf): void
|
||||
{
|
||||
$options = $easy->options;
|
||||
if (isset($options['verify'])) {
|
||||
if ($options['verify'] === false) {
|
||||
unset($conf[CURLOPT_CAINFO]);
|
||||
$conf[CURLOPT_SSL_VERIFYHOST] = 0;
|
||||
$conf[CURLOPT_SSL_VERIFYPEER] = false;
|
||||
unset($conf[\CURLOPT_CAINFO]);
|
||||
$conf[\CURLOPT_SSL_VERIFYHOST] = 0;
|
||||
$conf[\CURLOPT_SSL_VERIFYPEER] = false;
|
||||
} else {
|
||||
$conf[CURLOPT_SSL_VERIFYHOST] = 2;
|
||||
$conf[CURLOPT_SSL_VERIFYPEER] = true;
|
||||
if (is_string($options['verify'])) {
|
||||
$conf[\CURLOPT_SSL_VERIFYHOST] = 2;
|
||||
$conf[\CURLOPT_SSL_VERIFYPEER] = true;
|
||||
if (\is_string($options['verify'])) {
|
||||
// Throw an error if the file/folder/link path is not valid or doesn't exist.
|
||||
if (!file_exists($options['verify'])) {
|
||||
throw new \InvalidArgumentException(
|
||||
"SSL CA bundle not found: {$options['verify']}"
|
||||
);
|
||||
if (!\file_exists($options['verify'])) {
|
||||
throw new \InvalidArgumentException("SSL CA bundle not found: {$options['verify']}");
|
||||
}
|
||||
// If it's a directory or a link to a directory use CURLOPT_CAPATH.
|
||||
// If not, it's probably a file, or a link to a file, so use CURLOPT_CAINFO.
|
||||
if (is_dir($options['verify']) ||
|
||||
(is_link($options['verify']) && is_dir(readlink($options['verify'])))) {
|
||||
$conf[CURLOPT_CAPATH] = $options['verify'];
|
||||
if (
|
||||
\is_dir($options['verify']) ||
|
||||
(
|
||||
\is_link($options['verify']) === true &&
|
||||
($verifyLink = \readlink($options['verify'])) !== false &&
|
||||
\is_dir($verifyLink)
|
||||
)
|
||||
) {
|
||||
$conf[\CURLOPT_CAPATH] = $options['verify'];
|
||||
} else {
|
||||
$conf[CURLOPT_CAINFO] = $options['verify'];
|
||||
$conf[\CURLOPT_CAINFO] = $options['verify'];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($options['decode_content'])) {
|
||||
if (!isset($options['curl'][\CURLOPT_ENCODING]) && !empty($options['decode_content'])) {
|
||||
$accept = $easy->request->getHeaderLine('Accept-Encoding');
|
||||
if ($accept) {
|
||||
$conf[CURLOPT_ENCODING] = $accept;
|
||||
$conf[\CURLOPT_ENCODING] = $accept;
|
||||
} else {
|
||||
$conf[CURLOPT_ENCODING] = '';
|
||||
// Don't let curl send the header over the wire
|
||||
$conf[CURLOPT_HTTPHEADER][] = 'Accept-Encoding:';
|
||||
// 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.
|
||||
$conf[\CURLOPT_HTTPHEADER][] = 'Accept-Encoding:';
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($options['sink'])) {
|
||||
$sink = $options['sink'];
|
||||
if (!is_string($sink)) {
|
||||
$sink = \GuzzleHttp\Psr7\stream_for($sink);
|
||||
} elseif (!is_dir(dirname($sink))) {
|
||||
// Ensure that the directory exists before failing in curl.
|
||||
throw new \RuntimeException(sprintf(
|
||||
'Directory %s does not exist for sink value of %s',
|
||||
dirname($sink),
|
||||
$sink
|
||||
));
|
||||
} else {
|
||||
$sink = new LazyOpenStream($sink, 'w+');
|
||||
}
|
||||
$easy->sink = $sink;
|
||||
$conf[CURLOPT_WRITEFUNCTION] = function ($ch, $write) use ($sink) {
|
||||
return $sink->write($write);
|
||||
};
|
||||
} else {
|
||||
if (!isset($options['sink'])) {
|
||||
// Use a default temp stream if no sink was set.
|
||||
$conf[CURLOPT_FILE] = fopen('php://temp', 'w+');
|
||||
$easy->sink = Psr7\stream_for($conf[CURLOPT_FILE]);
|
||||
$options['sink'] = \GuzzleHttp\Psr7\Utils::tryFopen('php://temp', 'w+');
|
||||
}
|
||||
$sink = $options['sink'];
|
||||
if (!\is_string($sink)) {
|
||||
$sink = \GuzzleHttp\Psr7\Utils::streamFor($sink);
|
||||
} elseif (!\is_dir(\dirname($sink))) {
|
||||
// Ensure that the directory exists before failing in curl.
|
||||
throw new \RuntimeException(\sprintf('Directory %s does not exist for sink value of %s', \dirname($sink), $sink));
|
||||
} else {
|
||||
$sink = new LazyOpenStream($sink, 'w+');
|
||||
}
|
||||
$easy->sink = $sink;
|
||||
$conf[\CURLOPT_WRITEFUNCTION] = static function ($ch, $write) use ($sink): int {
|
||||
return $sink->write($write);
|
||||
};
|
||||
|
||||
$timeoutRequiresNoSignal = false;
|
||||
if (isset($options['timeout'])) {
|
||||
$timeoutRequiresNoSignal |= $options['timeout'] < 1;
|
||||
$conf[CURLOPT_TIMEOUT_MS] = $options['timeout'] * 1000;
|
||||
$conf[\CURLOPT_TIMEOUT_MS] = $options['timeout'] * 1000;
|
||||
}
|
||||
|
||||
// CURL default value is CURL_IPRESOLVE_WHATEVER
|
||||
if (isset($options['force_ip_resolve'])) {
|
||||
if ('v4' === $options['force_ip_resolve']) {
|
||||
$conf[CURLOPT_IPRESOLVE] = CURL_IPRESOLVE_V4;
|
||||
$conf[\CURLOPT_IPRESOLVE] = \CURL_IPRESOLVE_V4;
|
||||
} elseif ('v6' === $options['force_ip_resolve']) {
|
||||
$conf[CURLOPT_IPRESOLVE] = CURL_IPRESOLVE_V6;
|
||||
$conf[\CURLOPT_IPRESOLVE] = \CURL_IPRESOLVE_V6;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($options['connect_timeout'])) {
|
||||
$timeoutRequiresNoSignal |= $options['connect_timeout'] < 1;
|
||||
$conf[CURLOPT_CONNECTTIMEOUT_MS] = $options['connect_timeout'] * 1000;
|
||||
$conf[\CURLOPT_CONNECTTIMEOUT_MS] = $options['connect_timeout'] * 1000;
|
||||
}
|
||||
|
||||
if ($timeoutRequiresNoSignal && strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN') {
|
||||
$conf[CURLOPT_NOSIGNAL] = true;
|
||||
if ($timeoutRequiresNoSignal && \strtoupper(\substr(\PHP_OS, 0, 3)) !== 'WIN') {
|
||||
$conf[\CURLOPT_NOSIGNAL] = true;
|
||||
}
|
||||
|
||||
if (isset($options['proxy'])) {
|
||||
if (!is_array($options['proxy'])) {
|
||||
$conf[CURLOPT_PROXY] = $options['proxy'];
|
||||
if (!\is_array($options['proxy'])) {
|
||||
$conf[\CURLOPT_PROXY] = $options['proxy'];
|
||||
} else {
|
||||
$scheme = $easy->request->getUri()->getScheme();
|
||||
if (isset($options['proxy'][$scheme])) {
|
||||
$host = $easy->request->getUri()->getHost();
|
||||
if (!isset($options['proxy']['no']) ||
|
||||
!\GuzzleHttp\is_host_in_noproxy($host, $options['proxy']['no'])
|
||||
) {
|
||||
$conf[CURLOPT_PROXY] = $options['proxy'][$scheme];
|
||||
if (!isset($options['proxy']['no']) || !Utils::isHostInNoProxy($host, $options['proxy']['no'])) {
|
||||
$conf[\CURLOPT_PROXY] = $options['proxy'][$scheme];
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -441,58 +452,53 @@ class CurlFactory implements CurlFactoryInterface
|
||||
|
||||
if (isset($options['cert'])) {
|
||||
$cert = $options['cert'];
|
||||
if (is_array($cert)) {
|
||||
$conf[CURLOPT_SSLCERTPASSWD] = $cert[1];
|
||||
if (\is_array($cert)) {
|
||||
$conf[\CURLOPT_SSLCERTPASSWD] = $cert[1];
|
||||
$cert = $cert[0];
|
||||
}
|
||||
if (!file_exists($cert)) {
|
||||
throw new \InvalidArgumentException(
|
||||
"SSL certificate not found: {$cert}"
|
||||
);
|
||||
if (!\file_exists($cert)) {
|
||||
throw new \InvalidArgumentException("SSL certificate not found: {$cert}");
|
||||
}
|
||||
$conf[CURLOPT_SSLCERT] = $cert;
|
||||
# OpenSSL (versions 0.9.3 and later) also support "P12" for PKCS#12-encoded files.
|
||||
# see https://curl.se/libcurl/c/CURLOPT_SSLCERTTYPE.html
|
||||
$ext = pathinfo($cert, \PATHINFO_EXTENSION);
|
||||
if (preg_match('#^(der|p12)$#i', $ext)) {
|
||||
$conf[\CURLOPT_SSLCERTTYPE] = strtoupper($ext);
|
||||
}
|
||||
$conf[\CURLOPT_SSLCERT] = $cert;
|
||||
}
|
||||
|
||||
if (isset($options['ssl_key'])) {
|
||||
if (is_array($options['ssl_key'])) {
|
||||
if (count($options['ssl_key']) === 2) {
|
||||
list($sslKey, $conf[CURLOPT_SSLKEYPASSWD]) = $options['ssl_key'];
|
||||
if (\is_array($options['ssl_key'])) {
|
||||
if (\count($options['ssl_key']) === 2) {
|
||||
[$sslKey, $conf[\CURLOPT_SSLKEYPASSWD]] = $options['ssl_key'];
|
||||
} else {
|
||||
list($sslKey) = $options['ssl_key'];
|
||||
[$sslKey] = $options['ssl_key'];
|
||||
}
|
||||
}
|
||||
|
||||
$sslKey = isset($sslKey) ? $sslKey: $options['ssl_key'];
|
||||
$sslKey = $sslKey ?? $options['ssl_key'];
|
||||
|
||||
if (!file_exists($sslKey)) {
|
||||
throw new \InvalidArgumentException(
|
||||
"SSL private key not found: {$sslKey}"
|
||||
);
|
||||
if (!\file_exists($sslKey)) {
|
||||
throw new \InvalidArgumentException("SSL private key not found: {$sslKey}");
|
||||
}
|
||||
$conf[CURLOPT_SSLKEY] = $sslKey;
|
||||
$conf[\CURLOPT_SSLKEY] = $sslKey;
|
||||
}
|
||||
|
||||
if (isset($options['progress'])) {
|
||||
$progress = $options['progress'];
|
||||
if (!is_callable($progress)) {
|
||||
throw new \InvalidArgumentException(
|
||||
'progress client option must be callable'
|
||||
);
|
||||
if (!\is_callable($progress)) {
|
||||
throw new \InvalidArgumentException('progress client option must be callable');
|
||||
}
|
||||
$conf[CURLOPT_NOPROGRESS] = false;
|
||||
$conf[CURLOPT_PROGRESSFUNCTION] = function () use ($progress) {
|
||||
$args = func_get_args();
|
||||
// PHP 5.5 pushed the handle onto the start of the args
|
||||
if (is_resource($args[0])) {
|
||||
array_shift($args);
|
||||
}
|
||||
call_user_func_array($progress, $args);
|
||||
$conf[\CURLOPT_NOPROGRESS] = false;
|
||||
$conf[\CURLOPT_PROGRESSFUNCTION] = static function ($resource, int $downloadSize, int $downloaded, int $uploadSize, int $uploaded) use ($progress) {
|
||||
$progress($downloadSize, $downloaded, $uploadSize, $uploaded);
|
||||
};
|
||||
}
|
||||
|
||||
if (!empty($options['debug'])) {
|
||||
$conf[CURLOPT_STDERR] = \GuzzleHttp\debug_resource($options['debug']);
|
||||
$conf[CURLOPT_VERBOSE] = true;
|
||||
$conf[\CURLOPT_STDERR] = Utils::debugResource($options['debug']);
|
||||
$conf[\CURLOPT_VERBOSE] = true;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -504,12 +510,11 @@ class CurlFactory implements CurlFactoryInterface
|
||||
* stream, and then encountered a "necessary data rewind wasn't possible"
|
||||
* error, causing the request to be sent through curl_multi_info_read()
|
||||
* without an error status.
|
||||
*
|
||||
* @param callable(RequestInterface, array): PromiseInterface $handler
|
||||
*/
|
||||
private static function retryFailedRewind(
|
||||
callable $handler,
|
||||
EasyHandle $easy,
|
||||
array $ctx
|
||||
) {
|
||||
private static function retryFailedRewind(callable $handler, EasyHandle $easy, array $ctx): PromiseInterface
|
||||
{
|
||||
try {
|
||||
// Only rewind if the body has been read from.
|
||||
$body = $easy->request->getBody();
|
||||
@@ -542,27 +547,32 @@ class CurlFactory implements CurlFactoryInterface
|
||||
return $handler($easy->request, $easy->options);
|
||||
}
|
||||
|
||||
private function createHeaderFn(EasyHandle $easy)
|
||||
private function createHeaderFn(EasyHandle $easy): callable
|
||||
{
|
||||
if (isset($easy->options['on_headers'])) {
|
||||
$onHeaders = $easy->options['on_headers'];
|
||||
|
||||
if (!is_callable($onHeaders)) {
|
||||
if (!\is_callable($onHeaders)) {
|
||||
throw new \InvalidArgumentException('on_headers must be callable');
|
||||
}
|
||||
} else {
|
||||
$onHeaders = null;
|
||||
}
|
||||
|
||||
return function ($ch, $h) use (
|
||||
return static function ($ch, $h) use (
|
||||
$onHeaders,
|
||||
$easy,
|
||||
&$startingResponse
|
||||
) {
|
||||
$value = trim($h);
|
||||
$value = \trim($h);
|
||||
if ($value === '') {
|
||||
$startingResponse = true;
|
||||
$easy->createResponse();
|
||||
try {
|
||||
$easy->createResponse();
|
||||
} catch (\Exception $e) {
|
||||
$easy->createResponseException = $e;
|
||||
return -1;
|
||||
}
|
||||
if ($onHeaders !== null) {
|
||||
try {
|
||||
$onHeaders($easy->response);
|
||||
@@ -579,7 +589,7 @@ class CurlFactory implements CurlFactoryInterface
|
||||
} else {
|
||||
$easy->headers[] = $value;
|
||||
}
|
||||
return strlen($h);
|
||||
return \strlen($h);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
namespace GuzzleHttp\Handler;
|
||||
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
@@ -11,17 +12,14 @@ interface CurlFactoryInterface
|
||||
* @param RequestInterface $request Request
|
||||
* @param array $options Transfer options
|
||||
*
|
||||
* @return EasyHandle
|
||||
* @throws \RuntimeException when an option cannot be applied
|
||||
*/
|
||||
public function create(RequestInterface $request, array $options);
|
||||
public function create(RequestInterface $request, array $options): EasyHandle;
|
||||
|
||||
/**
|
||||
* Release an easy handle, allowing it to be reused or closed.
|
||||
*
|
||||
* This function must call unset on the easy handle's "handle" property.
|
||||
*
|
||||
* @param EasyHandle $easy
|
||||
*/
|
||||
public function release(EasyHandle $easy);
|
||||
public function release(EasyHandle $easy): void;
|
||||
}
|
||||
|
||||
@@ -1,7 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace GuzzleHttp\Handler;
|
||||
|
||||
use GuzzleHttp\Psr7;
|
||||
use GuzzleHttp\Promise\PromiseInterface;
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
|
||||
/**
|
||||
@@ -10,35 +11,38 @@ use Psr\Http\Message\RequestInterface;
|
||||
* When using the CurlHandler, custom curl options can be specified as an
|
||||
* associative array of curl option constants mapping to values in the
|
||||
* **curl** key of the "client" key of the request.
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class CurlHandler
|
||||
{
|
||||
/** @var CurlFactoryInterface */
|
||||
/**
|
||||
* @var CurlFactoryInterface
|
||||
*/
|
||||
private $factory;
|
||||
|
||||
/**
|
||||
* Accepts an associative array of options:
|
||||
*
|
||||
* - factory: Optional curl factory used to create cURL handles.
|
||||
* - handle_factory: Optional curl factory used to create cURL handles.
|
||||
*
|
||||
* @param array $options Array of options to use with the handler
|
||||
* @param array{handle_factory?: ?CurlFactoryInterface} $options Array of options to use with the handler
|
||||
*/
|
||||
public function __construct(array $options = [])
|
||||
{
|
||||
$this->factory = isset($options['handle_factory'])
|
||||
? $options['handle_factory']
|
||||
: new CurlFactory(3);
|
||||
$this->factory = $options['handle_factory']
|
||||
?? new CurlFactory(3);
|
||||
}
|
||||
|
||||
public function __invoke(RequestInterface $request, array $options)
|
||||
public function __invoke(RequestInterface $request, array $options): PromiseInterface
|
||||
{
|
||||
if (isset($options['delay'])) {
|
||||
usleep($options['delay'] * 1000);
|
||||
\usleep($options['delay'] * 1000);
|
||||
}
|
||||
|
||||
$easy = $this->factory->create($request, $options);
|
||||
curl_exec($easy->handle);
|
||||
$easy->errno = curl_errno($easy->handle);
|
||||
\curl_exec($easy->handle);
|
||||
$easy->errno = \curl_errno($easy->handle);
|
||||
|
||||
return CurlFactory::finish($this, $easy, $this->factory);
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace GuzzleHttp\Handler;
|
||||
|
||||
use GuzzleHttp\Promise as P;
|
||||
use GuzzleHttp\Promise\Promise;
|
||||
use GuzzleHttp\Promise\PromiseInterface;
|
||||
use GuzzleHttp\Utils;
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
|
||||
@@ -13,16 +15,45 @@ use Psr\Http\Message\RequestInterface;
|
||||
* associative array of curl option constants mapping to values in the
|
||||
* **curl** key of the provided request options.
|
||||
*
|
||||
* @property resource $_mh Internal use only. Lazy loaded multi-handle.
|
||||
* @property resource|\CurlMultiHandle $_mh Internal use only. Lazy loaded multi-handle.
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
#[\AllowDynamicProperties]
|
||||
class CurlMultiHandler
|
||||
{
|
||||
/** @var CurlFactoryInterface */
|
||||
/**
|
||||
* @var CurlFactoryInterface
|
||||
*/
|
||||
private $factory;
|
||||
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private $selectTimeout;
|
||||
private $active;
|
||||
|
||||
/**
|
||||
* @var int Will be higher than 0 when `curl_multi_exec` is still running.
|
||||
*/
|
||||
private $active = 0;
|
||||
|
||||
/**
|
||||
* @var array Request entry handles, indexed by handle id in `addRequest`.
|
||||
*
|
||||
* @see CurlMultiHandler::addRequest
|
||||
*/
|
||||
private $handles = [];
|
||||
|
||||
/**
|
||||
* @var array<int, float> An array of delay times, indexed by handle id in `addRequest`.
|
||||
*
|
||||
* @see CurlMultiHandler::addRequest
|
||||
*/
|
||||
private $delays = [];
|
||||
|
||||
/**
|
||||
* @var array<mixed> An associative array of CURLMOPT_* options and corresponding values for curl_multi_setopt()
|
||||
*/
|
||||
private $options = [];
|
||||
|
||||
/**
|
||||
@@ -33,52 +64,62 @@ class CurlMultiHandler
|
||||
* out while selecting curl handles. Defaults to 1 second.
|
||||
* - options: An associative array of CURLMOPT_* options and
|
||||
* corresponding values for curl_multi_setopt()
|
||||
*
|
||||
* @param array $options
|
||||
*/
|
||||
public function __construct(array $options = [])
|
||||
{
|
||||
$this->factory = isset($options['handle_factory'])
|
||||
? $options['handle_factory'] : new CurlFactory(50);
|
||||
$this->factory = $options['handle_factory'] ?? new CurlFactory(50);
|
||||
|
||||
if (isset($options['select_timeout'])) {
|
||||
$this->selectTimeout = $options['select_timeout'];
|
||||
} elseif ($selectTimeout = getenv('GUZZLE_CURL_SELECT_TIMEOUT')) {
|
||||
$this->selectTimeout = $selectTimeout;
|
||||
} elseif ($selectTimeout = Utils::getenv('GUZZLE_CURL_SELECT_TIMEOUT')) {
|
||||
@trigger_error('Since guzzlehttp/guzzle 7.2.0: Using environment variable GUZZLE_CURL_SELECT_TIMEOUT is deprecated. Use option "select_timeout" instead.', \E_USER_DEPRECATED);
|
||||
$this->selectTimeout = (int) $selectTimeout;
|
||||
} else {
|
||||
$this->selectTimeout = 1;
|
||||
}
|
||||
|
||||
$this->options = isset($options['options']) ? $options['options'] : [];
|
||||
$this->options = $options['options'] ?? [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
*
|
||||
* @return resource|\CurlMultiHandle
|
||||
*
|
||||
* @throws \BadMethodCallException when another field as `_mh` will be gotten
|
||||
* @throws \RuntimeException when curl can not initialize a multi handle
|
||||
*/
|
||||
public function __get($name)
|
||||
{
|
||||
if ($name === '_mh') {
|
||||
$this->_mh = curl_multi_init();
|
||||
|
||||
foreach ($this->options as $option => $value) {
|
||||
// A warning is raised in case of a wrong option.
|
||||
curl_multi_setopt($this->_mh, $option, $value);
|
||||
}
|
||||
|
||||
// Further calls to _mh will return the value directly, without entering the
|
||||
// __get() method at all.
|
||||
return $this->_mh;
|
||||
if ($name !== '_mh') {
|
||||
throw new \BadMethodCallException("Can not get other property as '_mh'.");
|
||||
}
|
||||
|
||||
throw new \BadMethodCallException();
|
||||
$multiHandle = \curl_multi_init();
|
||||
|
||||
if (false === $multiHandle) {
|
||||
throw new \RuntimeException('Can not initialize curl multi handle.');
|
||||
}
|
||||
|
||||
$this->_mh = $multiHandle;
|
||||
|
||||
foreach ($this->options as $option => $value) {
|
||||
// A warning is raised in case of a wrong option.
|
||||
curl_multi_setopt($this->_mh, $option, $value);
|
||||
}
|
||||
|
||||
return $this->_mh;
|
||||
}
|
||||
|
||||
public function __destruct()
|
||||
{
|
||||
if (isset($this->_mh)) {
|
||||
curl_multi_close($this->_mh);
|
||||
\curl_multi_close($this->_mh);
|
||||
unset($this->_mh);
|
||||
}
|
||||
}
|
||||
|
||||
public function __invoke(RequestInterface $request, array $options)
|
||||
public function __invoke(RequestInterface $request, array $options): PromiseInterface
|
||||
{
|
||||
$easy = $this->factory->create($request, $options);
|
||||
$id = (int) $easy->handle;
|
||||
@@ -98,7 +139,7 @@ class CurlMultiHandler
|
||||
/**
|
||||
* Ticks the curl event loop.
|
||||
*/
|
||||
public function tick()
|
||||
public function tick(): void
|
||||
{
|
||||
// Add any delayed handles if needed.
|
||||
if ($this->delays) {
|
||||
@@ -106,7 +147,7 @@ class CurlMultiHandler
|
||||
foreach ($this->delays as $id => $delay) {
|
||||
if ($currentTime >= $delay) {
|
||||
unset($this->delays[$id]);
|
||||
curl_multi_add_handle(
|
||||
\curl_multi_add_handle(
|
||||
$this->_mh,
|
||||
$this->handles[$id]['easy']->handle
|
||||
);
|
||||
@@ -115,17 +156,15 @@ class CurlMultiHandler
|
||||
}
|
||||
|
||||
// Step through the task queue which may add additional requests.
|
||||
P\queue()->run();
|
||||
P\Utils::queue()->run();
|
||||
|
||||
if ($this->active &&
|
||||
curl_multi_select($this->_mh, $this->selectTimeout) === -1
|
||||
) {
|
||||
if ($this->active && \curl_multi_select($this->_mh, $this->selectTimeout) === -1) {
|
||||
// Perform a usleep if a select returns -1.
|
||||
// See: https://bugs.php.net/bug.php?id=61141
|
||||
usleep(250);
|
||||
\usleep(250);
|
||||
}
|
||||
|
||||
while (curl_multi_exec($this->_mh, $this->active) === CURLM_CALL_MULTI_PERFORM);
|
||||
while (\curl_multi_exec($this->_mh, $this->active) === \CURLM_CALL_MULTI_PERFORM);
|
||||
|
||||
$this->processMessages();
|
||||
}
|
||||
@@ -133,26 +172,26 @@ class CurlMultiHandler
|
||||
/**
|
||||
* Runs until all outstanding connections have completed.
|
||||
*/
|
||||
public function execute()
|
||||
public function execute(): void
|
||||
{
|
||||
$queue = P\queue();
|
||||
$queue = P\Utils::queue();
|
||||
|
||||
while ($this->handles || !$queue->isEmpty()) {
|
||||
// If there are no transfers, then sleep for the next delay
|
||||
if (!$this->active && $this->delays) {
|
||||
usleep($this->timeToNext());
|
||||
\usleep($this->timeToNext());
|
||||
}
|
||||
$this->tick();
|
||||
}
|
||||
}
|
||||
|
||||
private function addRequest(array $entry)
|
||||
private function addRequest(array $entry): void
|
||||
{
|
||||
$easy = $entry['easy'];
|
||||
$id = (int) $easy->handle;
|
||||
$this->handles[$id] = $entry;
|
||||
if (empty($easy->options['delay'])) {
|
||||
curl_multi_add_handle($this->_mh, $easy->handle);
|
||||
\curl_multi_add_handle($this->_mh, $easy->handle);
|
||||
} else {
|
||||
$this->delays[$id] = Utils::currentTime() + ($easy->options['delay'] / 1000);
|
||||
}
|
||||
@@ -165,8 +204,12 @@ class CurlMultiHandler
|
||||
*
|
||||
* @return bool True on success, false on failure.
|
||||
*/
|
||||
private function cancel($id)
|
||||
private function cancel($id): bool
|
||||
{
|
||||
if (!is_int($id)) {
|
||||
trigger_deprecation('guzzlehttp/guzzle', '7.4', 'Not passing an integer to %s::%s() is deprecated and will cause an error in 8.0.', __CLASS__, __FUNCTION__);
|
||||
}
|
||||
|
||||
// Cannot cancel if it has been processed.
|
||||
if (!isset($this->handles[$id])) {
|
||||
return false;
|
||||
@@ -174,17 +217,21 @@ class CurlMultiHandler
|
||||
|
||||
$handle = $this->handles[$id]['easy']->handle;
|
||||
unset($this->delays[$id], $this->handles[$id]);
|
||||
curl_multi_remove_handle($this->_mh, $handle);
|
||||
curl_close($handle);
|
||||
\curl_multi_remove_handle($this->_mh, $handle);
|
||||
\curl_close($handle);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function processMessages()
|
||||
private function processMessages(): void
|
||||
{
|
||||
while ($done = curl_multi_info_read($this->_mh)) {
|
||||
while ($done = \curl_multi_info_read($this->_mh)) {
|
||||
if ($done['msg'] !== \CURLMSG_DONE) {
|
||||
// if it's not done, then it would be premature to remove the handle. ref https://github.com/guzzle/guzzle/pull/2892#issuecomment-945150216
|
||||
continue;
|
||||
}
|
||||
$id = (int) $done['handle'];
|
||||
curl_multi_remove_handle($this->_mh, $done['handle']);
|
||||
\curl_multi_remove_handle($this->_mh, $done['handle']);
|
||||
|
||||
if (!isset($this->handles[$id])) {
|
||||
// Probably was cancelled.
|
||||
@@ -195,25 +242,21 @@ class CurlMultiHandler
|
||||
unset($this->handles[$id], $this->delays[$id]);
|
||||
$entry['easy']->errno = $done['result'];
|
||||
$entry['deferred']->resolve(
|
||||
CurlFactory::finish(
|
||||
$this,
|
||||
$entry['easy'],
|
||||
$this->factory
|
||||
)
|
||||
CurlFactory::finish($this, $entry['easy'], $this->factory)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private function timeToNext()
|
||||
private function timeToNext(): int
|
||||
{
|
||||
$currentTime = Utils::currentTime();
|
||||
$nextTime = PHP_INT_MAX;
|
||||
$nextTime = \PHP_INT_MAX;
|
||||
foreach ($this->delays as $time) {
|
||||
if ($time < $nextTime) {
|
||||
$nextTime = $time;
|
||||
}
|
||||
}
|
||||
|
||||
return max(0, $nextTime - $currentTime) * 1000000;
|
||||
return ((int) \max(0, $nextTime - $currentTime)) * 1000000;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
<?php
|
||||
|
||||
namespace GuzzleHttp\Handler;
|
||||
|
||||
use GuzzleHttp\Psr7\Response;
|
||||
use GuzzleHttp\Utils;
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
@@ -13,55 +15,68 @@ use Psr\Http\Message\StreamInterface;
|
||||
*/
|
||||
final class EasyHandle
|
||||
{
|
||||
/** @var resource cURL resource */
|
||||
/**
|
||||
* @var resource|\CurlHandle cURL resource
|
||||
*/
|
||||
public $handle;
|
||||
|
||||
/** @var StreamInterface Where data is being written */
|
||||
/**
|
||||
* @var StreamInterface Where data is being written
|
||||
*/
|
||||
public $sink;
|
||||
|
||||
/** @var array Received HTTP headers so far */
|
||||
/**
|
||||
* @var array Received HTTP headers so far
|
||||
*/
|
||||
public $headers = [];
|
||||
|
||||
/** @var ResponseInterface Received response (if any) */
|
||||
/**
|
||||
* @var ResponseInterface|null Received response (if any)
|
||||
*/
|
||||
public $response;
|
||||
|
||||
/** @var RequestInterface Request being sent */
|
||||
/**
|
||||
* @var RequestInterface Request being sent
|
||||
*/
|
||||
public $request;
|
||||
|
||||
/** @var array Request options */
|
||||
/**
|
||||
* @var array Request options
|
||||
*/
|
||||
public $options = [];
|
||||
|
||||
/** @var int cURL error number (if any) */
|
||||
/**
|
||||
* @var int cURL error number (if any)
|
||||
*/
|
||||
public $errno = 0;
|
||||
|
||||
/** @var \Exception Exception during on_headers (if any) */
|
||||
/**
|
||||
* @var \Throwable|null Exception during on_headers (if any)
|
||||
*/
|
||||
public $onHeadersException;
|
||||
|
||||
/**
|
||||
* @var \Exception|null Exception during createResponse (if any)
|
||||
*/
|
||||
public $createResponseException;
|
||||
|
||||
/**
|
||||
* Attach a response to the easy handle based on the received headers.
|
||||
*
|
||||
* @throws \RuntimeException if no headers have been received.
|
||||
* @throws \RuntimeException if no headers have been received or the first
|
||||
* header line is invalid.
|
||||
*/
|
||||
public function createResponse()
|
||||
public function createResponse(): void
|
||||
{
|
||||
if (empty($this->headers)) {
|
||||
throw new \RuntimeException('No headers have been received');
|
||||
}
|
||||
[$ver, $status, $reason, $headers] = HeaderProcessor::parseHeaders($this->headers);
|
||||
|
||||
// HTTP-version SP status-code SP reason-phrase
|
||||
$startLine = explode(' ', array_shift($this->headers), 3);
|
||||
$headers = \GuzzleHttp\headers_from_lines($this->headers);
|
||||
$normalizedKeys = \GuzzleHttp\normalize_header_keys($headers);
|
||||
$normalizedKeys = Utils::normalizeHeaderKeys($headers);
|
||||
|
||||
if (!empty($this->options['decode_content'])
|
||||
&& isset($normalizedKeys['content-encoding'])
|
||||
) {
|
||||
$headers['x-encoded-content-encoding']
|
||||
= $headers[$normalizedKeys['content-encoding']];
|
||||
if (!empty($this->options['decode_content']) && isset($normalizedKeys['content-encoding'])) {
|
||||
$headers['x-encoded-content-encoding'] = $headers[$normalizedKeys['content-encoding']];
|
||||
unset($headers[$normalizedKeys['content-encoding']]);
|
||||
if (isset($normalizedKeys['content-length'])) {
|
||||
$headers['x-encoded-content-length']
|
||||
= $headers[$normalizedKeys['content-length']];
|
||||
$headers['x-encoded-content-length'] = $headers[$normalizedKeys['content-length']];
|
||||
|
||||
$bodyLength = (int) $this->sink->getSize();
|
||||
if ($bodyLength) {
|
||||
@@ -74,19 +89,24 @@ final class EasyHandle
|
||||
|
||||
// Attach a response to the easy handle with the parsed headers.
|
||||
$this->response = new Response(
|
||||
$startLine[1],
|
||||
$status,
|
||||
$headers,
|
||||
$this->sink,
|
||||
substr($startLine[0], 5),
|
||||
isset($startLine[2]) ? (string) $startLine[2] : null
|
||||
$ver,
|
||||
$reason
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @throws \BadMethodCallException
|
||||
*/
|
||||
public function __get($name)
|
||||
{
|
||||
$msg = $name === 'handle'
|
||||
? 'The EasyHandle has been released'
|
||||
: 'Invalid property: ' . $name;
|
||||
$msg = $name === 'handle' ? 'The EasyHandle has been released' : 'Invalid property: ' . $name;
|
||||
throw new \BadMethodCallException($msg);
|
||||
}
|
||||
}
|
||||
|
||||
42
vendor/guzzlehttp/guzzle/src/Handler/HeaderProcessor.php
vendored
Normal file
42
vendor/guzzlehttp/guzzle/src/Handler/HeaderProcessor.php
vendored
Normal file
@@ -0,0 +1,42 @@
|
||||
<?php
|
||||
|
||||
namespace GuzzleHttp\Handler;
|
||||
|
||||
use GuzzleHttp\Utils;
|
||||
|
||||
/**
|
||||
* @internal
|
||||
*/
|
||||
final class HeaderProcessor
|
||||
{
|
||||
/**
|
||||
* Returns the HTTP version, status code, reason phrase, and headers.
|
||||
*
|
||||
* @param string[] $headers
|
||||
*
|
||||
* @throws \RuntimeException
|
||||
*
|
||||
* @return array{0:string, 1:int, 2:?string, 3:array}
|
||||
*/
|
||||
public static function parseHeaders(array $headers): array
|
||||
{
|
||||
if ($headers === []) {
|
||||
throw new \RuntimeException('Expected a non-empty array of header data');
|
||||
}
|
||||
|
||||
$parts = \explode(' ', \array_shift($headers), 3);
|
||||
$version = \explode('/', $parts[0])[1] ?? null;
|
||||
|
||||
if ($version === null) {
|
||||
throw new \RuntimeException('HTTP version missing from header data');
|
||||
}
|
||||
|
||||
$status = $parts[1] ?? null;
|
||||
|
||||
if ($status === null) {
|
||||
throw new \RuntimeException('HTTP status code missing from header data');
|
||||
}
|
||||
|
||||
return [$version, (int) $status, $parts[2] ?? null, Utils::headersFromLines($headers)];
|
||||
}
|
||||
}
|
||||
140
vendor/guzzlehttp/guzzle/src/Handler/MockHandler.php
vendored
140
vendor/guzzlehttp/guzzle/src/Handler/MockHandler.php
vendored
@@ -1,81 +1,98 @@
|
||||
<?php
|
||||
|
||||
namespace GuzzleHttp\Handler;
|
||||
|
||||
use GuzzleHttp\Exception\RequestException;
|
||||
use GuzzleHttp\HandlerStack;
|
||||
use GuzzleHttp\Promise as P;
|
||||
use GuzzleHttp\Promise\PromiseInterface;
|
||||
use GuzzleHttp\Promise\RejectedPromise;
|
||||
use GuzzleHttp\TransferStats;
|
||||
use GuzzleHttp\Utils;
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
|
||||
/**
|
||||
* Handler that returns responses or throw exceptions from a queue.
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class MockHandler implements \Countable
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $queue = [];
|
||||
|
||||
/**
|
||||
* @var RequestInterface|null
|
||||
*/
|
||||
private $lastRequest;
|
||||
private $lastOptions;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $lastOptions = [];
|
||||
|
||||
/**
|
||||
* @var callable|null
|
||||
*/
|
||||
private $onFulfilled;
|
||||
|
||||
/**
|
||||
* @var callable|null
|
||||
*/
|
||||
private $onRejected;
|
||||
|
||||
/**
|
||||
* Creates a new MockHandler that uses the default handler stack list of
|
||||
* middlewares.
|
||||
*
|
||||
* @param array $queue Array of responses, callables, or exceptions.
|
||||
* @param callable $onFulfilled Callback to invoke when the return value is fulfilled.
|
||||
* @param callable $onRejected Callback to invoke when the return value is rejected.
|
||||
*
|
||||
* @return HandlerStack
|
||||
* @param array|null $queue Array of responses, callables, or exceptions.
|
||||
* @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
|
||||
) {
|
||||
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 Psr7\Http\Message\ResponseInterface} objects, Exceptions,
|
||||
* {@see \Psr\Http\Message\ResponseInterface} objects, Exceptions,
|
||||
* callables, or Promises.
|
||||
*
|
||||
* @param array $queue
|
||||
* @param callable $onFulfilled Callback to invoke when the return value is fulfilled.
|
||||
* @param callable $onRejected Callback to invoke when the return value is rejected.
|
||||
* @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;
|
||||
|
||||
if ($queue) {
|
||||
call_user_func_array([$this, 'append'], $queue);
|
||||
// array_values included for BC
|
||||
$this->append(...array_values($queue));
|
||||
}
|
||||
}
|
||||
|
||||
public function __invoke(RequestInterface $request, array $options)
|
||||
public function __invoke(RequestInterface $request, array $options): PromiseInterface
|
||||
{
|
||||
if (!$this->queue) {
|
||||
throw new \OutOfBoundsException('Mock queue is empty');
|
||||
}
|
||||
|
||||
if (isset($options['delay']) && is_numeric($options['delay'])) {
|
||||
usleep($options['delay'] * 1000);
|
||||
if (isset($options['delay']) && \is_numeric($options['delay'])) {
|
||||
\usleep((int) $options['delay'] * 1000);
|
||||
}
|
||||
|
||||
$this->lastRequest = $request;
|
||||
$this->lastOptions = $options;
|
||||
$response = array_shift($this->queue);
|
||||
$response = \array_shift($this->queue);
|
||||
|
||||
if (isset($options['on_headers'])) {
|
||||
if (!is_callable($options['on_headers'])) {
|
||||
if (!\is_callable($options['on_headers'])) {
|
||||
throw new \InvalidArgumentException('on_headers must be callable');
|
||||
}
|
||||
try {
|
||||
@@ -86,29 +103,30 @@ class MockHandler implements \Countable
|
||||
}
|
||||
}
|
||||
|
||||
if (is_callable($response)) {
|
||||
$response = call_user_func($response, $request, $options);
|
||||
if (\is_callable($response)) {
|
||||
$response = $response($request, $options);
|
||||
}
|
||||
|
||||
$response = $response instanceof \Exception
|
||||
? \GuzzleHttp\Promise\rejection_for($response)
|
||||
: \GuzzleHttp\Promise\promise_for($response);
|
||||
$response = $response instanceof \Throwable
|
||||
? P\Create::rejectionFor($response)
|
||||
: P\Create::promiseFor($response);
|
||||
|
||||
return $response->then(
|
||||
function ($value) use ($request, $options) {
|
||||
function (?ResponseInterface $value) use ($request, $options) {
|
||||
$this->invokeStats($request, $options, $value);
|
||||
if ($this->onFulfilled) {
|
||||
call_user_func($this->onFulfilled, $value);
|
||||
($this->onFulfilled)($value);
|
||||
}
|
||||
if (isset($options['sink'])) {
|
||||
|
||||
if ($value !== null && isset($options['sink'])) {
|
||||
$contents = (string) $value->getBody();
|
||||
$sink = $options['sink'];
|
||||
|
||||
if (is_resource($sink)) {
|
||||
fwrite($sink, $contents);
|
||||
} elseif (is_string($sink)) {
|
||||
file_put_contents($sink, $contents);
|
||||
} elseif ($sink instanceof \Psr\Http\Message\StreamInterface) {
|
||||
if (\is_resource($sink)) {
|
||||
\fwrite($sink, $contents);
|
||||
} elseif (\is_string($sink)) {
|
||||
\file_put_contents($sink, $contents);
|
||||
} elseif ($sink instanceof StreamInterface) {
|
||||
$sink->write($contents);
|
||||
}
|
||||
}
|
||||
@@ -118,9 +136,9 @@ class MockHandler implements \Countable
|
||||
function ($reason) use ($request, $options) {
|
||||
$this->invokeStats($request, $options, null, $reason);
|
||||
if ($this->onRejected) {
|
||||
call_user_func($this->onRejected, $reason);
|
||||
($this->onRejected)($reason);
|
||||
}
|
||||
return \GuzzleHttp\Promise\rejection_for($reason);
|
||||
return P\Create::rejectionFor($reason);
|
||||
}
|
||||
);
|
||||
}
|
||||
@@ -128,68 +146,66 @@ class MockHandler implements \Countable
|
||||
/**
|
||||
* Adds one or more variadic requests, exceptions, callables, or promises
|
||||
* to the queue.
|
||||
*
|
||||
* @param mixed ...$values
|
||||
*/
|
||||
public function append()
|
||||
public function append(...$values): void
|
||||
{
|
||||
foreach (func_get_args() as $value) {
|
||||
foreach ($values as $value) {
|
||||
if ($value instanceof ResponseInterface
|
||||
|| $value instanceof \Exception
|
||||
|| $value instanceof \Throwable
|
||||
|| $value instanceof PromiseInterface
|
||||
|| is_callable($value)
|
||||
|| \is_callable($value)
|
||||
) {
|
||||
$this->queue[] = $value;
|
||||
} else {
|
||||
throw new \InvalidArgumentException('Expected a response or '
|
||||
. 'exception. Found ' . \GuzzleHttp\describe_type($value));
|
||||
throw new \TypeError('Expected a Response, Promise, Throwable or callable. Found ' . Utils::describeType($value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the last received request.
|
||||
*
|
||||
* @return RequestInterface
|
||||
*/
|
||||
public function getLastRequest()
|
||||
public function getLastRequest(): ?RequestInterface
|
||||
{
|
||||
return $this->lastRequest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the last received request options.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getLastOptions()
|
||||
public function getLastOptions(): array
|
||||
{
|
||||
return $this->lastOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of remaining items in the queue.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function count()
|
||||
public function count(): int
|
||||
{
|
||||
return count($this->queue);
|
||||
return \count($this->queue);
|
||||
}
|
||||
|
||||
public function reset()
|
||||
public function reset(): void
|
||||
{
|
||||
$this->queue = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $reason Promise or reason.
|
||||
*/
|
||||
private function invokeStats(
|
||||
RequestInterface $request,
|
||||
array $options,
|
||||
ResponseInterface $response = null,
|
||||
$reason = null
|
||||
) {
|
||||
): void {
|
||||
if (isset($options['on_stats'])) {
|
||||
$transferTime = isset($options['transfer_time']) ? $options['transfer_time'] : 0;
|
||||
$transferTime = $options['transfer_time'] ?? 0;
|
||||
$stats = new TransferStats($request, $response, $transferTime, $reason);
|
||||
call_user_func($options['on_stats'], $stats);
|
||||
($options['on_stats'])($stats);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
40
vendor/guzzlehttp/guzzle/src/Handler/Proxy.php
vendored
40
vendor/guzzlehttp/guzzle/src/Handler/Proxy.php
vendored
@@ -1,11 +1,15 @@
|
||||
<?php
|
||||
|
||||
namespace GuzzleHttp\Handler;
|
||||
|
||||
use GuzzleHttp\Promise\PromiseInterface;
|
||||
use GuzzleHttp\RequestOptions;
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
|
||||
/**
|
||||
* Provides basic proxies for handlers.
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class Proxy
|
||||
{
|
||||
@@ -13,19 +17,15 @@ class Proxy
|
||||
* Sends synchronous requests to a specific handler while sending all other
|
||||
* requests to another handler.
|
||||
*
|
||||
* @param callable $default Handler used for normal responses
|
||||
* @param callable $sync Handler used for synchronous responses.
|
||||
* @param callable(\Psr\Http\Message\RequestInterface, array): \GuzzleHttp\Promise\PromiseInterface $default Handler used for normal responses
|
||||
* @param callable(\Psr\Http\Message\RequestInterface, array): \GuzzleHttp\Promise\PromiseInterface $sync Handler used for synchronous responses.
|
||||
*
|
||||
* @return callable Returns the composed handler.
|
||||
* @return callable(\Psr\Http\Message\RequestInterface, array): \GuzzleHttp\Promise\PromiseInterface Returns the composed handler.
|
||||
*/
|
||||
public static function wrapSync(
|
||||
callable $default,
|
||||
callable $sync
|
||||
) {
|
||||
return function (RequestInterface $request, array $options) use ($default, $sync) {
|
||||
return empty($options[RequestOptions::SYNCHRONOUS])
|
||||
? $default($request, $options)
|
||||
: $sync($request, $options);
|
||||
public static function wrapSync(callable $default, callable $sync): callable
|
||||
{
|
||||
return static function (RequestInterface $request, array $options) use ($default, $sync): PromiseInterface {
|
||||
return empty($options[RequestOptions::SYNCHRONOUS]) ? $default($request, $options) : $sync($request, $options);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -37,19 +37,15 @@ class Proxy
|
||||
* performance benefits of curl while still supporting true streaming
|
||||
* through the StreamHandler.
|
||||
*
|
||||
* @param callable $default Handler used for non-streaming responses
|
||||
* @param callable $streaming Handler used for streaming responses
|
||||
* @param callable(\Psr\Http\Message\RequestInterface, array): \GuzzleHttp\Promise\PromiseInterface $default Handler used for non-streaming responses
|
||||
* @param callable(\Psr\Http\Message\RequestInterface, array): \GuzzleHttp\Promise\PromiseInterface $streaming Handler used for streaming responses
|
||||
*
|
||||
* @return callable Returns the composed handler.
|
||||
* @return callable(\Psr\Http\Message\RequestInterface, array): \GuzzleHttp\Promise\PromiseInterface Returns the composed handler.
|
||||
*/
|
||||
public static function wrapStreaming(
|
||||
callable $default,
|
||||
callable $streaming
|
||||
) {
|
||||
return function (RequestInterface $request, array $options) use ($default, $streaming) {
|
||||
return empty($options['stream'])
|
||||
? $default($request, $options)
|
||||
: $streaming($request, $options);
|
||||
public static function wrapStreaming(callable $default, callable $streaming): callable
|
||||
{
|
||||
return static function (RequestInterface $request, array $options) use ($default, $streaming): PromiseInterface {
|
||||
return empty($options['stream']) ? $default($request, $options) : $streaming($request, $options);
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace GuzzleHttp\Handler;
|
||||
|
||||
use GuzzleHttp\Exception\ConnectException;
|
||||
use GuzzleHttp\Exception\RequestException;
|
||||
use GuzzleHttp\Promise as P;
|
||||
use GuzzleHttp\Promise\FulfilledPromise;
|
||||
use GuzzleHttp\Promise\PromiseInterface;
|
||||
use GuzzleHttp\Psr7;
|
||||
@@ -11,12 +13,18 @@ use GuzzleHttp\Utils;
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
use Psr\Http\Message\UriInterface;
|
||||
|
||||
/**
|
||||
* HTTP handler that uses PHP's HTTP stream wrapper.
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class StreamHandler
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $lastHeaders = [];
|
||||
|
||||
/**
|
||||
@@ -24,14 +32,12 @@ class StreamHandler
|
||||
*
|
||||
* @param RequestInterface $request Request to send.
|
||||
* @param array $options Request transfer options.
|
||||
*
|
||||
* @return PromiseInterface
|
||||
*/
|
||||
public function __invoke(RequestInterface $request, array $options)
|
||||
public function __invoke(RequestInterface $request, array $options): PromiseInterface
|
||||
{
|
||||
// Sleep if there is a delay specified.
|
||||
if (isset($options['delay'])) {
|
||||
usleep($options['delay'] * 1000);
|
||||
\usleep($options['delay'] * 1000);
|
||||
}
|
||||
|
||||
$startTime = isset($options['on_stats']) ? Utils::currentTime() : null;
|
||||
@@ -58,80 +64,80 @@ class StreamHandler
|
||||
// Determine if the error was a networking error.
|
||||
$message = $e->getMessage();
|
||||
// This list can probably get more comprehensive.
|
||||
if (strpos($message, 'getaddrinfo') // DNS lookup failed
|
||||
|| strpos($message, 'Connection refused')
|
||||
|| strpos($message, "couldn't connect to host") // error on HHVM
|
||||
|| strpos($message, "connection attempt failed")
|
||||
if (false !== \strpos($message, 'getaddrinfo') // DNS lookup failed
|
||||
|| false !== \strpos($message, 'Connection refused')
|
||||
|| false !== \strpos($message, "couldn't connect to host") // error on HHVM
|
||||
|| false !== \strpos($message, "connection attempt failed")
|
||||
) {
|
||||
$e = new ConnectException($e->getMessage(), $request, $e);
|
||||
} else {
|
||||
$e = RequestException::wrapException($request, $e);
|
||||
}
|
||||
$e = RequestException::wrapException($request, $e);
|
||||
$this->invokeStats($options, $request, $startTime, null, $e);
|
||||
|
||||
return \GuzzleHttp\Promise\rejection_for($e);
|
||||
return P\Create::rejectionFor($e);
|
||||
}
|
||||
}
|
||||
|
||||
private function invokeStats(
|
||||
array $options,
|
||||
RequestInterface $request,
|
||||
$startTime,
|
||||
?float $startTime,
|
||||
ResponseInterface $response = null,
|
||||
$error = null
|
||||
) {
|
||||
\Throwable $error = null
|
||||
): void {
|
||||
if (isset($options['on_stats'])) {
|
||||
$stats = new TransferStats(
|
||||
$request,
|
||||
$response,
|
||||
Utils::currentTime() - $startTime,
|
||||
$error,
|
||||
[]
|
||||
);
|
||||
call_user_func($options['on_stats'], $stats);
|
||||
$stats = new TransferStats($request, $response, Utils::currentTime() - $startTime, $error, []);
|
||||
($options['on_stats'])($stats);
|
||||
}
|
||||
}
|
||||
|
||||
private function createResponse(
|
||||
RequestInterface $request,
|
||||
array $options,
|
||||
$stream,
|
||||
$startTime
|
||||
) {
|
||||
/**
|
||||
* @param resource $stream
|
||||
*/
|
||||
private function createResponse(RequestInterface $request, array $options, $stream, ?float $startTime): PromiseInterface
|
||||
{
|
||||
$hdrs = $this->lastHeaders;
|
||||
$this->lastHeaders = [];
|
||||
$parts = explode(' ', array_shift($hdrs), 3);
|
||||
$ver = explode('/', $parts[0])[1];
|
||||
$status = $parts[1];
|
||||
$reason = isset($parts[2]) ? $parts[2] : null;
|
||||
$headers = \GuzzleHttp\headers_from_lines($hdrs);
|
||||
list($stream, $headers) = $this->checkDecode($options, $headers, $stream);
|
||||
$stream = Psr7\stream_for($stream);
|
||||
|
||||
try {
|
||||
[$ver, $status, $reason, $headers] = HeaderProcessor::parseHeaders($hdrs);
|
||||
} catch (\Exception $e) {
|
||||
return P\Create::rejectionFor(
|
||||
new RequestException('An error was encountered while creating the response', $request, null, $e)
|
||||
);
|
||||
}
|
||||
|
||||
[$stream, $headers] = $this->checkDecode($options, $headers, $stream);
|
||||
$stream = Psr7\Utils::streamFor($stream);
|
||||
$sink = $stream;
|
||||
|
||||
if (strcasecmp('HEAD', $request->getMethod())) {
|
||||
if (\strcasecmp('HEAD', $request->getMethod())) {
|
||||
$sink = $this->createSink($stream, $options);
|
||||
}
|
||||
|
||||
$response = new Psr7\Response($status, $headers, $sink, $ver, $reason);
|
||||
try {
|
||||
$response = new Psr7\Response($status, $headers, $sink, $ver, $reason);
|
||||
} catch (\Exception $e) {
|
||||
return P\Create::rejectionFor(
|
||||
new RequestException('An error was encountered while creating the response', $request, null, $e)
|
||||
);
|
||||
}
|
||||
|
||||
if (isset($options['on_headers'])) {
|
||||
try {
|
||||
$options['on_headers']($response);
|
||||
} catch (\Exception $e) {
|
||||
$msg = 'An error was encountered during the on_headers event';
|
||||
$ex = new RequestException($msg, $request, $response, $e);
|
||||
return \GuzzleHttp\Promise\rejection_for($ex);
|
||||
return P\Create::rejectionFor(
|
||||
new RequestException('An error was encountered during the on_headers event', $request, $response, $e)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Do not drain when the request is a HEAD request because they have
|
||||
// no body.
|
||||
if ($sink !== $stream) {
|
||||
$this->drain(
|
||||
$stream,
|
||||
$sink,
|
||||
$response->getHeaderLine('Content-Length')
|
||||
);
|
||||
$this->drain($stream, $sink, $response->getHeaderLine('Content-Length'));
|
||||
}
|
||||
|
||||
$this->invokeStats($options, $request, $startTime, $response, null);
|
||||
@@ -139,41 +145,37 @@ class StreamHandler
|
||||
return new FulfilledPromise($response);
|
||||
}
|
||||
|
||||
private function createSink(StreamInterface $stream, array $options)
|
||||
private function createSink(StreamInterface $stream, array $options): StreamInterface
|
||||
{
|
||||
if (!empty($options['stream'])) {
|
||||
return $stream;
|
||||
}
|
||||
|
||||
$sink = isset($options['sink'])
|
||||
? $options['sink']
|
||||
: fopen('php://temp', 'r+');
|
||||
$sink = $options['sink'] ?? Psr7\Utils::tryFopen('php://temp', 'r+');
|
||||
|
||||
return is_string($sink)
|
||||
? new Psr7\LazyOpenStream($sink, 'w+')
|
||||
: Psr7\stream_for($sink);
|
||||
return \is_string($sink) ? new Psr7\LazyOpenStream($sink, 'w+') : Psr7\Utils::streamFor($sink);
|
||||
}
|
||||
|
||||
private function checkDecode(array $options, array $headers, $stream)
|
||||
/**
|
||||
* @param resource $stream
|
||||
*/
|
||||
private function checkDecode(array $options, array $headers, $stream): array
|
||||
{
|
||||
// Automatically decode responses when instructed.
|
||||
if (!empty($options['decode_content'])) {
|
||||
$normalizedKeys = \GuzzleHttp\normalize_header_keys($headers);
|
||||
$normalizedKeys = Utils::normalizeHeaderKeys($headers);
|
||||
if (isset($normalizedKeys['content-encoding'])) {
|
||||
$encoding = $headers[$normalizedKeys['content-encoding']];
|
||||
if ($encoding[0] === 'gzip' || $encoding[0] === 'deflate') {
|
||||
$stream = new Psr7\InflateStream(
|
||||
Psr7\stream_for($stream)
|
||||
);
|
||||
$headers['x-encoded-content-encoding']
|
||||
= $headers[$normalizedKeys['content-encoding']];
|
||||
$stream = new Psr7\InflateStream(Psr7\Utils::streamFor($stream));
|
||||
$headers['x-encoded-content-encoding'] = $headers[$normalizedKeys['content-encoding']];
|
||||
|
||||
// Remove content-encoding header
|
||||
unset($headers[$normalizedKeys['content-encoding']]);
|
||||
|
||||
// Fix content-length header
|
||||
if (isset($normalizedKeys['content-length'])) {
|
||||
$headers['x-encoded-content-length']
|
||||
= $headers[$normalizedKeys['content-length']];
|
||||
|
||||
$headers['x-encoded-content-length'] = $headers[$normalizedKeys['content-length']];
|
||||
$length = (int) $stream->getSize();
|
||||
if ($length === 0) {
|
||||
unset($headers[$normalizedKeys['content-length']]);
|
||||
@@ -191,27 +193,21 @@ class StreamHandler
|
||||
/**
|
||||
* Drains the source stream into the "sink" client option.
|
||||
*
|
||||
* @param StreamInterface $source
|
||||
* @param StreamInterface $sink
|
||||
* @param string $contentLength Header specifying the amount of
|
||||
* data to read.
|
||||
* @param string $contentLength Header specifying the amount of
|
||||
* data to read.
|
||||
*
|
||||
* @return StreamInterface
|
||||
* @throws \RuntimeException when the sink option is invalid.
|
||||
*/
|
||||
private function drain(
|
||||
StreamInterface $source,
|
||||
StreamInterface $sink,
|
||||
$contentLength
|
||||
) {
|
||||
private function drain(StreamInterface $source, StreamInterface $sink, string $contentLength): StreamInterface
|
||||
{
|
||||
// If a content-length header is provided, then stop reading once
|
||||
// that number of bytes has been read. This can prevent infinitely
|
||||
// reading from a stream when dealing with servers that do not honor
|
||||
// Connection: Close headers.
|
||||
Psr7\copy_to_stream(
|
||||
Psr7\Utils::copyToStream(
|
||||
$source,
|
||||
$sink,
|
||||
(strlen($contentLength) > 0 && (int) $contentLength > 0) ? (int) $contentLength : -1
|
||||
(\strlen($contentLength) > 0 && (int) $contentLength > 0) ? (int) $contentLength : -1
|
||||
);
|
||||
|
||||
$sink->seek(0);
|
||||
@@ -226,12 +222,13 @@ class StreamHandler
|
||||
* @param callable $callback Callable that returns stream resource
|
||||
*
|
||||
* @return resource
|
||||
*
|
||||
* @throws \RuntimeException on error
|
||||
*/
|
||||
private function createResource(callable $callback)
|
||||
{
|
||||
$errors = null;
|
||||
set_error_handler(function ($_, $msg, $file, $line) use (&$errors) {
|
||||
$errors = [];
|
||||
\set_error_handler(static function ($_, $msg, $file, $line) use (&$errors): bool {
|
||||
$errors[] = [
|
||||
'message' => $msg,
|
||||
'file' => $file,
|
||||
@@ -240,27 +237,37 @@ class StreamHandler
|
||||
return true;
|
||||
});
|
||||
|
||||
$resource = $callback();
|
||||
restore_error_handler();
|
||||
try {
|
||||
$resource = $callback();
|
||||
} finally {
|
||||
\restore_error_handler();
|
||||
}
|
||||
|
||||
if (!$resource) {
|
||||
$message = 'Error creating resource: ';
|
||||
foreach ($errors as $err) {
|
||||
foreach ($err as $key => $value) {
|
||||
$message .= "[$key] $value" . PHP_EOL;
|
||||
$message .= "[$key] $value" . \PHP_EOL;
|
||||
}
|
||||
}
|
||||
throw new \RuntimeException(trim($message));
|
||||
throw new \RuntimeException(\trim($message));
|
||||
}
|
||||
|
||||
return $resource;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return resource
|
||||
*/
|
||||
private function createStream(RequestInterface $request, array $options)
|
||||
{
|
||||
static $methods;
|
||||
if (!$methods) {
|
||||
$methods = array_flip(get_class_methods(__CLASS__));
|
||||
$methods = \array_flip(\get_class_methods(__CLASS__));
|
||||
}
|
||||
|
||||
if (!\in_array($request->getUri()->getScheme(), ['http', 'https'])) {
|
||||
throw new RequestException(\sprintf("The scheme '%s' is not supported.", $request->getUri()->getScheme()), $request);
|
||||
}
|
||||
|
||||
// HTTP/1.1 streams using the PHP stream wrapper require a
|
||||
@@ -279,7 +286,7 @@ class StreamHandler
|
||||
$params = [];
|
||||
$context = $this->getDefaultContext($request);
|
||||
|
||||
if (isset($options['on_headers']) && !is_callable($options['on_headers'])) {
|
||||
if (isset($options['on_headers']) && !\is_callable($options['on_headers'])) {
|
||||
throw new \InvalidArgumentException('on_headers must be callable');
|
||||
}
|
||||
|
||||
@@ -293,42 +300,39 @@ class StreamHandler
|
||||
}
|
||||
|
||||
if (isset($options['stream_context'])) {
|
||||
if (!is_array($options['stream_context'])) {
|
||||
if (!\is_array($options['stream_context'])) {
|
||||
throw new \InvalidArgumentException('stream_context must be an array');
|
||||
}
|
||||
$context = array_replace_recursive(
|
||||
$context,
|
||||
$options['stream_context']
|
||||
);
|
||||
$context = \array_replace_recursive($context, $options['stream_context']);
|
||||
}
|
||||
|
||||
// Microsoft NTLM authentication only supported with curl handler
|
||||
if (isset($options['auth'])
|
||||
&& is_array($options['auth'])
|
||||
&& isset($options['auth'][2])
|
||||
&& 'ntlm' == $options['auth'][2]
|
||||
) {
|
||||
if (isset($options['auth'][2]) && 'ntlm' === $options['auth'][2]) {
|
||||
throw new \InvalidArgumentException('Microsoft NTLM authentication only supported with curl handler');
|
||||
}
|
||||
|
||||
$uri = $this->resolveHost($request, $options);
|
||||
|
||||
$context = $this->createResource(
|
||||
function () use ($context, $params) {
|
||||
return stream_context_create($context, $params);
|
||||
$contextResource = $this->createResource(
|
||||
static function () use ($context, $params) {
|
||||
return \stream_context_create($context, $params);
|
||||
}
|
||||
);
|
||||
|
||||
return $this->createResource(
|
||||
function () use ($uri, &$http_response_header, $context, $options) {
|
||||
$resource = fopen((string) $uri, 'r', null, $context);
|
||||
$this->lastHeaders = $http_response_header;
|
||||
function () use ($uri, &$http_response_header, $contextResource, $context, $options, $request) {
|
||||
$resource = @\fopen((string) $uri, 'r', false, $contextResource);
|
||||
$this->lastHeaders = $http_response_header ?? [];
|
||||
|
||||
if (false === $resource) {
|
||||
throw new ConnectException(sprintf('Connection refused for URI %s', $uri), $request, null, $context);
|
||||
}
|
||||
|
||||
if (isset($options['read_timeout'])) {
|
||||
$readTimeout = $options['read_timeout'];
|
||||
$sec = (int) $readTimeout;
|
||||
$usec = ($readTimeout - $sec) * 100000;
|
||||
stream_set_timeout($resource, $sec, $usec);
|
||||
\stream_set_timeout($resource, $sec, $usec);
|
||||
}
|
||||
|
||||
return $resource;
|
||||
@@ -336,42 +340,31 @@ class StreamHandler
|
||||
);
|
||||
}
|
||||
|
||||
private function resolveHost(RequestInterface $request, array $options)
|
||||
private function resolveHost(RequestInterface $request, array $options): UriInterface
|
||||
{
|
||||
$uri = $request->getUri();
|
||||
|
||||
if (isset($options['force_ip_resolve']) && !filter_var($uri->getHost(), FILTER_VALIDATE_IP)) {
|
||||
if (isset($options['force_ip_resolve']) && !\filter_var($uri->getHost(), \FILTER_VALIDATE_IP)) {
|
||||
if ('v4' === $options['force_ip_resolve']) {
|
||||
$records = dns_get_record($uri->getHost(), DNS_A);
|
||||
if (!isset($records[0]['ip'])) {
|
||||
throw new ConnectException(
|
||||
sprintf(
|
||||
"Could not resolve IPv4 address for host '%s'",
|
||||
$uri->getHost()
|
||||
),
|
||||
$request
|
||||
);
|
||||
$records = \dns_get_record($uri->getHost(), \DNS_A);
|
||||
if (false === $records || !isset($records[0]['ip'])) {
|
||||
throw new ConnectException(\sprintf("Could not resolve IPv4 address for host '%s'", $uri->getHost()), $request);
|
||||
}
|
||||
$uri = $uri->withHost($records[0]['ip']);
|
||||
} elseif ('v6' === $options['force_ip_resolve']) {
|
||||
$records = dns_get_record($uri->getHost(), DNS_AAAA);
|
||||
if (!isset($records[0]['ipv6'])) {
|
||||
throw new ConnectException(
|
||||
sprintf(
|
||||
"Could not resolve IPv6 address for host '%s'",
|
||||
$uri->getHost()
|
||||
),
|
||||
$request
|
||||
);
|
||||
return $uri->withHost($records[0]['ip']);
|
||||
}
|
||||
if ('v6' === $options['force_ip_resolve']) {
|
||||
$records = \dns_get_record($uri->getHost(), \DNS_AAAA);
|
||||
if (false === $records || !isset($records[0]['ipv6'])) {
|
||||
throw new ConnectException(\sprintf("Could not resolve IPv6 address for host '%s'", $uri->getHost()), $request);
|
||||
}
|
||||
$uri = $uri->withHost('[' . $records[0]['ipv6'] . ']');
|
||||
return $uri->withHost('[' . $records[0]['ipv6'] . ']');
|
||||
}
|
||||
}
|
||||
|
||||
return $uri;
|
||||
}
|
||||
|
||||
private function getDefaultContext(RequestInterface $request)
|
||||
private function getDefaultContext(RequestInterface $request): array
|
||||
{
|
||||
$headers = '';
|
||||
foreach ($request->getHeaders() as $name => $value) {
|
||||
@@ -388,6 +381,9 @@ class StreamHandler
|
||||
'ignore_errors' => true,
|
||||
'follow_location' => 0,
|
||||
],
|
||||
'ssl' => [
|
||||
'peer_name' => $request->getUri()->getHost(),
|
||||
],
|
||||
];
|
||||
|
||||
$body = (string) $request->getBody();
|
||||
@@ -400,55 +396,100 @@ class StreamHandler
|
||||
}
|
||||
}
|
||||
|
||||
$context['http']['header'] = rtrim($context['http']['header']);
|
||||
$context['http']['header'] = \rtrim($context['http']['header']);
|
||||
|
||||
return $context;
|
||||
}
|
||||
|
||||
private function add_proxy(RequestInterface $request, &$options, $value, &$params)
|
||||
/**
|
||||
* @param mixed $value as passed via Request transfer options.
|
||||
*/
|
||||
private function add_proxy(RequestInterface $request, array &$options, $value, array &$params): void
|
||||
{
|
||||
if (!is_array($value)) {
|
||||
$options['http']['proxy'] = $value;
|
||||
$uri = null;
|
||||
|
||||
if (!\is_array($value)) {
|
||||
$uri = $value;
|
||||
} else {
|
||||
$scheme = $request->getUri()->getScheme();
|
||||
if (isset($value[$scheme])) {
|
||||
if (!isset($value['no'])
|
||||
|| !\GuzzleHttp\is_host_in_noproxy(
|
||||
$request->getUri()->getHost(),
|
||||
$value['no']
|
||||
)
|
||||
) {
|
||||
$options['http']['proxy'] = $value[$scheme];
|
||||
if (!isset($value['no']) || !Utils::isHostInNoProxy($request->getUri()->getHost(), $value['no'])) {
|
||||
$uri = $value[$scheme];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!$uri) {
|
||||
return;
|
||||
}
|
||||
|
||||
$parsed = $this->parse_proxy($uri);
|
||||
$options['http']['proxy'] = $parsed['proxy'];
|
||||
|
||||
if ($parsed['auth']) {
|
||||
if (!isset($options['http']['header'])) {
|
||||
$options['http']['header'] = [];
|
||||
}
|
||||
$options['http']['header'] .= "\r\nProxy-Authorization: {$parsed['auth']}";
|
||||
}
|
||||
}
|
||||
|
||||
private function add_timeout(RequestInterface $request, &$options, $value, &$params)
|
||||
/**
|
||||
* Parses the given proxy URL to make it compatible with the format PHP's stream context expects.
|
||||
*/
|
||||
private function parse_proxy(string $url): array
|
||||
{
|
||||
$parsed = \parse_url($url);
|
||||
|
||||
if ($parsed !== false && isset($parsed['scheme']) && $parsed['scheme'] === 'http') {
|
||||
if (isset($parsed['host']) && isset($parsed['port'])) {
|
||||
$auth = null;
|
||||
if (isset($parsed['user']) && isset($parsed['pass'])) {
|
||||
$auth = \base64_encode("{$parsed['user']}:{$parsed['pass']}");
|
||||
}
|
||||
|
||||
return [
|
||||
'proxy' => "tcp://{$parsed['host']}:{$parsed['port']}",
|
||||
'auth' => $auth ? "Basic {$auth}" : null,
|
||||
];
|
||||
}
|
||||
}
|
||||
|
||||
// Return proxy as-is.
|
||||
return [
|
||||
'proxy' => $url,
|
||||
'auth' => null,
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param mixed $value as passed via Request transfer options.
|
||||
*/
|
||||
private function add_timeout(RequestInterface $request, array &$options, $value, array &$params): void
|
||||
{
|
||||
if ($value > 0) {
|
||||
$options['http']['timeout'] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
private function add_verify(RequestInterface $request, &$options, $value, &$params)
|
||||
/**
|
||||
* @param mixed $value as passed via Request transfer options.
|
||||
*/
|
||||
private function add_verify(RequestInterface $request, array &$options, $value, array &$params): void
|
||||
{
|
||||
if ($value === true) {
|
||||
// PHP 5.6 or greater will find the system cert by default. When
|
||||
// < 5.6, use the Guzzle bundled cacert.
|
||||
if (PHP_VERSION_ID < 50600) {
|
||||
$options['ssl']['cafile'] = \GuzzleHttp\default_ca_bundle();
|
||||
}
|
||||
} elseif (is_string($value)) {
|
||||
$options['ssl']['cafile'] = $value;
|
||||
if (!file_exists($value)) {
|
||||
throw new \RuntimeException("SSL CA bundle not found: $value");
|
||||
}
|
||||
} elseif ($value === false) {
|
||||
if ($value === false) {
|
||||
$options['ssl']['verify_peer'] = false;
|
||||
$options['ssl']['verify_peer_name'] = false;
|
||||
|
||||
return;
|
||||
} else {
|
||||
}
|
||||
|
||||
if (\is_string($value)) {
|
||||
$options['ssl']['cafile'] = $value;
|
||||
if (!\file_exists($value)) {
|
||||
throw new \RuntimeException("SSL CA bundle not found: $value");
|
||||
}
|
||||
} elseif ($value !== true) {
|
||||
throw new \InvalidArgumentException('Invalid verify request option');
|
||||
}
|
||||
|
||||
@@ -457,88 +498,95 @@ class StreamHandler
|
||||
$options['ssl']['allow_self_signed'] = false;
|
||||
}
|
||||
|
||||
private function add_cert(RequestInterface $request, &$options, $value, &$params)
|
||||
/**
|
||||
* @param mixed $value as passed via Request transfer options.
|
||||
*/
|
||||
private function add_cert(RequestInterface $request, array &$options, $value, array &$params): void
|
||||
{
|
||||
if (is_array($value)) {
|
||||
if (\is_array($value)) {
|
||||
$options['ssl']['passphrase'] = $value[1];
|
||||
$value = $value[0];
|
||||
}
|
||||
|
||||
if (!file_exists($value)) {
|
||||
if (!\file_exists($value)) {
|
||||
throw new \RuntimeException("SSL certificate not found: {$value}");
|
||||
}
|
||||
|
||||
$options['ssl']['local_cert'] = $value;
|
||||
}
|
||||
|
||||
private function add_progress(RequestInterface $request, &$options, $value, &$params)
|
||||
/**
|
||||
* @param mixed $value as passed via Request transfer options.
|
||||
*/
|
||||
private function add_progress(RequestInterface $request, array &$options, $value, array &$params): void
|
||||
{
|
||||
$this->addNotification(
|
||||
self::addNotification(
|
||||
$params,
|
||||
function ($code, $a, $b, $c, $transferred, $total) use ($value) {
|
||||
if ($code == STREAM_NOTIFY_PROGRESS) {
|
||||
$value($total, $transferred, null, null);
|
||||
static function ($code, $a, $b, $c, $transferred, $total) use ($value) {
|
||||
if ($code == \STREAM_NOTIFY_PROGRESS) {
|
||||
// The upload progress cannot be determined. Use 0 for cURL compatibility:
|
||||
// https://curl.se/libcurl/c/CURLOPT_PROGRESSFUNCTION.html
|
||||
$value($total, $transferred, 0, 0);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private function add_debug(RequestInterface $request, &$options, $value, &$params)
|
||||
/**
|
||||
* @param mixed $value as passed via Request transfer options.
|
||||
*/
|
||||
private function add_debug(RequestInterface $request, array &$options, $value, array &$params): void
|
||||
{
|
||||
if ($value === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
static $map = [
|
||||
STREAM_NOTIFY_CONNECT => 'CONNECT',
|
||||
STREAM_NOTIFY_AUTH_REQUIRED => 'AUTH_REQUIRED',
|
||||
STREAM_NOTIFY_AUTH_RESULT => 'AUTH_RESULT',
|
||||
STREAM_NOTIFY_MIME_TYPE_IS => 'MIME_TYPE_IS',
|
||||
STREAM_NOTIFY_FILE_SIZE_IS => 'FILE_SIZE_IS',
|
||||
STREAM_NOTIFY_REDIRECTED => 'REDIRECTED',
|
||||
STREAM_NOTIFY_PROGRESS => 'PROGRESS',
|
||||
STREAM_NOTIFY_FAILURE => 'FAILURE',
|
||||
STREAM_NOTIFY_COMPLETED => 'COMPLETED',
|
||||
STREAM_NOTIFY_RESOLVE => 'RESOLVE',
|
||||
\STREAM_NOTIFY_CONNECT => 'CONNECT',
|
||||
\STREAM_NOTIFY_AUTH_REQUIRED => 'AUTH_REQUIRED',
|
||||
\STREAM_NOTIFY_AUTH_RESULT => 'AUTH_RESULT',
|
||||
\STREAM_NOTIFY_MIME_TYPE_IS => 'MIME_TYPE_IS',
|
||||
\STREAM_NOTIFY_FILE_SIZE_IS => 'FILE_SIZE_IS',
|
||||
\STREAM_NOTIFY_REDIRECTED => 'REDIRECTED',
|
||||
\STREAM_NOTIFY_PROGRESS => 'PROGRESS',
|
||||
\STREAM_NOTIFY_FAILURE => 'FAILURE',
|
||||
\STREAM_NOTIFY_COMPLETED => 'COMPLETED',
|
||||
\STREAM_NOTIFY_RESOLVE => 'RESOLVE',
|
||||
];
|
||||
static $args = ['severity', 'message', 'message_code',
|
||||
'bytes_transferred', 'bytes_max'];
|
||||
static $args = ['severity', 'message', 'message_code', 'bytes_transferred', 'bytes_max'];
|
||||
|
||||
$value = \GuzzleHttp\debug_resource($value);
|
||||
$value = Utils::debugResource($value);
|
||||
$ident = $request->getMethod() . ' ' . $request->getUri()->withFragment('');
|
||||
$this->addNotification(
|
||||
self::addNotification(
|
||||
$params,
|
||||
function () use ($ident, $value, $map, $args) {
|
||||
$passed = func_get_args();
|
||||
$code = array_shift($passed);
|
||||
fprintf($value, '<%s> [%s] ', $ident, $map[$code]);
|
||||
foreach (array_filter($passed) as $i => $v) {
|
||||
fwrite($value, $args[$i] . ': "' . $v . '" ');
|
||||
static function (int $code, ...$passed) use ($ident, $value, $map, $args): void {
|
||||
\fprintf($value, '<%s> [%s] ', $ident, $map[$code]);
|
||||
foreach (\array_filter($passed) as $i => $v) {
|
||||
\fwrite($value, $args[$i] . ': "' . $v . '" ');
|
||||
}
|
||||
fwrite($value, "\n");
|
||||
\fwrite($value, "\n");
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private function addNotification(array &$params, callable $notify)
|
||||
private static function addNotification(array &$params, callable $notify): void
|
||||
{
|
||||
// Wrap the existing function if needed.
|
||||
if (!isset($params['notification'])) {
|
||||
$params['notification'] = $notify;
|
||||
} else {
|
||||
$params['notification'] = $this->callArray([
|
||||
$params['notification'] = self::callArray([
|
||||
$params['notification'],
|
||||
$notify
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
private function callArray(array $functions)
|
||||
private static function callArray(array $functions): callable
|
||||
{
|
||||
return function () use ($functions) {
|
||||
$args = func_get_args();
|
||||
return static function (...$args) use ($functions) {
|
||||
foreach ($functions as $fn) {
|
||||
call_user_func_array($fn, $args);
|
||||
$fn(...$args);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
142
vendor/guzzlehttp/guzzle/src/HandlerStack.php
vendored
142
vendor/guzzlehttp/guzzle/src/HandlerStack.php
vendored
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
namespace GuzzleHttp;
|
||||
|
||||
use GuzzleHttp\Promise\PromiseInterface;
|
||||
@@ -8,16 +9,24 @@ use Psr\Http\Message\ResponseInterface;
|
||||
/**
|
||||
* Creates a composed Guzzle handler function by stacking middlewares on top of
|
||||
* an HTTP handler function.
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class HandlerStack
|
||||
{
|
||||
/** @var callable|null */
|
||||
/**
|
||||
* @var (callable(RequestInterface, array): PromiseInterface)|null
|
||||
*/
|
||||
private $handler;
|
||||
|
||||
/** @var array */
|
||||
/**
|
||||
* @var array{(callable(callable(RequestInterface, array): PromiseInterface): callable), (string|null)}[]
|
||||
*/
|
||||
private $stack = [];
|
||||
|
||||
/** @var callable|null */
|
||||
/**
|
||||
* @var (callable(RequestInterface, array): PromiseInterface)|null
|
||||
*/
|
||||
private $cached;
|
||||
|
||||
/**
|
||||
@@ -31,15 +40,13 @@ class HandlerStack
|
||||
* The returned handler stack can be passed to a client in the "handler"
|
||||
* option.
|
||||
*
|
||||
* @param callable $handler HTTP handler function to use with the stack. If no
|
||||
* handler is provided, the best handler for your
|
||||
* system will be utilized.
|
||||
*
|
||||
* @return HandlerStack
|
||||
* @param (callable(RequestInterface, array): PromiseInterface)|null $handler HTTP handler function to use with the stack. If no
|
||||
* handler is provided, the best handler for your
|
||||
* system will be utilized.
|
||||
*/
|
||||
public static function create(callable $handler = null)
|
||||
public static function create(?callable $handler = null): self
|
||||
{
|
||||
$stack = new self($handler ?: choose_handler());
|
||||
$stack = new self($handler ?: Utils::chooseHandler());
|
||||
$stack->push(Middleware::httpErrors(), 'http_errors');
|
||||
$stack->push(Middleware::redirect(), 'allow_redirects');
|
||||
$stack->push(Middleware::cookies(), 'cookies');
|
||||
@@ -49,7 +56,7 @@ class HandlerStack
|
||||
}
|
||||
|
||||
/**
|
||||
* @param callable $handler Underlying HTTP handler.
|
||||
* @param (callable(RequestInterface, array): PromiseInterface)|null $handler Underlying HTTP handler.
|
||||
*/
|
||||
public function __construct(callable $handler = null)
|
||||
{
|
||||
@@ -59,9 +66,6 @@ class HandlerStack
|
||||
/**
|
||||
* Invokes the handler stack as a composed handler
|
||||
*
|
||||
* @param RequestInterface $request
|
||||
* @param array $options
|
||||
*
|
||||
* @return ResponseInterface|PromiseInterface
|
||||
*/
|
||||
public function __invoke(RequestInterface $request, array $options)
|
||||
@@ -80,12 +84,13 @@ class HandlerStack
|
||||
{
|
||||
$depth = 0;
|
||||
$stack = [];
|
||||
if ($this->handler) {
|
||||
|
||||
if ($this->handler !== null) {
|
||||
$stack[] = "0) Handler: " . $this->debugCallable($this->handler);
|
||||
}
|
||||
|
||||
$result = '';
|
||||
foreach (array_reverse($this->stack) as $tuple) {
|
||||
foreach (\array_reverse($this->stack) as $tuple) {
|
||||
$depth++;
|
||||
$str = "{$depth}) Name: '{$tuple[1]}', ";
|
||||
$str .= "Function: " . $this->debugCallable($tuple[0]);
|
||||
@@ -93,7 +98,7 @@ class HandlerStack
|
||||
$stack[] = $str;
|
||||
}
|
||||
|
||||
foreach (array_keys($stack) as $k) {
|
||||
foreach (\array_keys($stack) as $k) {
|
||||
$result .= "< {$stack[$k]}\n";
|
||||
}
|
||||
|
||||
@@ -103,10 +108,10 @@ class HandlerStack
|
||||
/**
|
||||
* Set the HTTP handler that actually returns a promise.
|
||||
*
|
||||
* @param callable $handler Accepts a request and array of options and
|
||||
* returns a Promise.
|
||||
* @param callable(RequestInterface, array): PromiseInterface $handler Accepts a request and array of options and
|
||||
* returns a Promise.
|
||||
*/
|
||||
public function setHandler(callable $handler)
|
||||
public function setHandler(callable $handler): void
|
||||
{
|
||||
$this->handler = $handler;
|
||||
$this->cached = null;
|
||||
@@ -114,33 +119,31 @@ class HandlerStack
|
||||
|
||||
/**
|
||||
* Returns true if the builder has a handler.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasHandler()
|
||||
public function hasHandler(): bool
|
||||
{
|
||||
return (bool) $this->handler;
|
||||
return $this->handler !== null ;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unshift a middleware to the bottom of the stack.
|
||||
*
|
||||
* @param callable $middleware Middleware function
|
||||
* @param string $name Name to register for this middleware.
|
||||
* @param callable(callable): callable $middleware Middleware function
|
||||
* @param string $name Name to register for this middleware.
|
||||
*/
|
||||
public function unshift(callable $middleware, $name = null)
|
||||
public function unshift(callable $middleware, ?string $name = null): void
|
||||
{
|
||||
array_unshift($this->stack, [$middleware, $name]);
|
||||
\array_unshift($this->stack, [$middleware, $name]);
|
||||
$this->cached = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Push a middleware to the top of the stack.
|
||||
*
|
||||
* @param callable $middleware Middleware function
|
||||
* @param string $name Name to register for this middleware.
|
||||
* @param callable(callable): callable $middleware Middleware function
|
||||
* @param string $name Name to register for this middleware.
|
||||
*/
|
||||
public function push(callable $middleware, $name = '')
|
||||
public function push(callable $middleware, string $name = ''): void
|
||||
{
|
||||
$this->stack[] = [$middleware, $name];
|
||||
$this->cached = null;
|
||||
@@ -149,11 +152,11 @@ class HandlerStack
|
||||
/**
|
||||
* Add a middleware before another middleware by name.
|
||||
*
|
||||
* @param string $findName Middleware to find
|
||||
* @param callable $middleware Middleware function
|
||||
* @param string $withName Name to register for this middleware.
|
||||
* @param string $findName Middleware to find
|
||||
* @param callable(callable): callable $middleware Middleware function
|
||||
* @param string $withName Name to register for this middleware.
|
||||
*/
|
||||
public function before($findName, callable $middleware, $withName = '')
|
||||
public function before(string $findName, callable $middleware, string $withName = ''): void
|
||||
{
|
||||
$this->splice($findName, $withName, $middleware, true);
|
||||
}
|
||||
@@ -161,11 +164,11 @@ class HandlerStack
|
||||
/**
|
||||
* Add a middleware after another middleware by name.
|
||||
*
|
||||
* @param string $findName Middleware to find
|
||||
* @param callable $middleware Middleware function
|
||||
* @param string $withName Name to register for this middleware.
|
||||
* @param string $findName Middleware to find
|
||||
* @param callable(callable): callable $middleware Middleware function
|
||||
* @param string $withName Name to register for this middleware.
|
||||
*/
|
||||
public function after($findName, callable $middleware, $withName = '')
|
||||
public function after(string $findName, callable $middleware, string $withName = ''): void
|
||||
{
|
||||
$this->splice($findName, $withName, $middleware, false);
|
||||
}
|
||||
@@ -175,13 +178,17 @@ class HandlerStack
|
||||
*
|
||||
* @param callable|string $remove Middleware to remove by instance or name.
|
||||
*/
|
||||
public function remove($remove)
|
||||
public function remove($remove): void
|
||||
{
|
||||
if (!is_string($remove) && !is_callable($remove)) {
|
||||
trigger_deprecation('guzzlehttp/guzzle', '7.4', 'Not passing a callable or string to %s::%s() is deprecated and will cause an error in 8.0.', __CLASS__, __FUNCTION__);
|
||||
}
|
||||
|
||||
$this->cached = null;
|
||||
$idx = is_callable($remove) ? 0 : 1;
|
||||
$this->stack = array_values(array_filter(
|
||||
$idx = \is_callable($remove) ? 0 : 1;
|
||||
$this->stack = \array_values(\array_filter(
|
||||
$this->stack,
|
||||
function ($tuple) use ($idx, $remove) {
|
||||
static function ($tuple) use ($idx, $remove) {
|
||||
return $tuple[$idx] !== $remove;
|
||||
}
|
||||
));
|
||||
@@ -190,16 +197,17 @@ class HandlerStack
|
||||
/**
|
||||
* Compose the middleware and handler into a single callable function.
|
||||
*
|
||||
* @return callable
|
||||
* @return callable(RequestInterface, array): PromiseInterface
|
||||
*/
|
||||
public function resolve()
|
||||
public function resolve(): callable
|
||||
{
|
||||
if (!$this->cached) {
|
||||
if (!($prev = $this->handler)) {
|
||||
if ($this->cached === null) {
|
||||
if (($prev = $this->handler) === null) {
|
||||
throw new \LogicException('No handler has been specified');
|
||||
}
|
||||
|
||||
foreach (array_reverse($this->stack) as $fn) {
|
||||
foreach (\array_reverse($this->stack) as $fn) {
|
||||
/** @var callable(RequestInterface, array): PromiseInterface $prev */
|
||||
$prev = $fn[0]($prev);
|
||||
}
|
||||
|
||||
@@ -209,11 +217,7 @@ class HandlerStack
|
||||
return $this->cached;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $name
|
||||
* @return int
|
||||
*/
|
||||
private function findByName($name)
|
||||
private function findByName(string $name): int
|
||||
{
|
||||
foreach ($this->stack as $k => $v) {
|
||||
if ($v[1] === $name) {
|
||||
@@ -226,13 +230,8 @@ class HandlerStack
|
||||
|
||||
/**
|
||||
* Splices a function into the middleware list at a specific position.
|
||||
*
|
||||
* @param string $findName
|
||||
* @param string $withName
|
||||
* @param callable $middleware
|
||||
* @param bool $before
|
||||
*/
|
||||
private function splice($findName, $withName, callable $middleware, $before)
|
||||
private function splice(string $findName, string $withName, callable $middleware, bool $before): void
|
||||
{
|
||||
$this->cached = null;
|
||||
$idx = $this->findByName($findName);
|
||||
@@ -240,38 +239,37 @@ class HandlerStack
|
||||
|
||||
if ($before) {
|
||||
if ($idx === 0) {
|
||||
array_unshift($this->stack, $tuple);
|
||||
\array_unshift($this->stack, $tuple);
|
||||
} else {
|
||||
$replacement = [$tuple, $this->stack[$idx]];
|
||||
array_splice($this->stack, $idx, 1, $replacement);
|
||||
\array_splice($this->stack, $idx, 1, $replacement);
|
||||
}
|
||||
} elseif ($idx === count($this->stack) - 1) {
|
||||
} elseif ($idx === \count($this->stack) - 1) {
|
||||
$this->stack[] = $tuple;
|
||||
} else {
|
||||
$replacement = [$this->stack[$idx], $tuple];
|
||||
array_splice($this->stack, $idx, 1, $replacement);
|
||||
\array_splice($this->stack, $idx, 1, $replacement);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a debug string for a given callable.
|
||||
*
|
||||
* @param array|callable $fn Function to write as a string.
|
||||
*
|
||||
* @return string
|
||||
* @param callable|string $fn Function to write as a string.
|
||||
*/
|
||||
private function debugCallable($fn)
|
||||
private function debugCallable($fn): string
|
||||
{
|
||||
if (is_string($fn)) {
|
||||
if (\is_string($fn)) {
|
||||
return "callable({$fn})";
|
||||
}
|
||||
|
||||
if (is_array($fn)) {
|
||||
return is_string($fn[0])
|
||||
if (\is_array($fn)) {
|
||||
return \is_string($fn[0])
|
||||
? "callable({$fn[0]}::{$fn[1]})"
|
||||
: "callable(['" . get_class($fn[0]) . "', '{$fn[1]}'])";
|
||||
: "callable(['" . \get_class($fn[0]) . "', '{$fn[1]}'])";
|
||||
}
|
||||
|
||||
return 'callable(' . spl_object_hash($fn) . ')';
|
||||
/** @var object $fn */
|
||||
return 'callable(' . \spl_object_hash($fn) . ')';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
namespace GuzzleHttp;
|
||||
|
||||
use Psr\Http\Message\MessageInterface;
|
||||
@@ -31,25 +32,31 @@ use Psr\Http\Message\ResponseInterface;
|
||||
* - {res_headers}: Response headers
|
||||
* - {req_body}: Request body
|
||||
* - {res_body}: Response body
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class MessageFormatter
|
||||
class MessageFormatter implements MessageFormatterInterface
|
||||
{
|
||||
/**
|
||||
* Apache Common Log Format.
|
||||
* @link http://httpd.apache.org/docs/2.4/logs.html#common
|
||||
*
|
||||
* @link https://httpd.apache.org/docs/2.4/logs.html#common
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
const CLF = "{hostname} {req_header_User-Agent} - [{date_common_log}] \"{method} {target} HTTP/{version}\" {code} {res_header_Content-Length}";
|
||||
const DEBUG = ">>>>>>>>\n{request}\n<<<<<<<<\n{response}\n--------\n{error}";
|
||||
const SHORT = '[{ts}] "{method} {target} HTTP/{version}" {code}';
|
||||
public const CLF = "{hostname} {req_header_User-Agent} - [{date_common_log}] \"{method} {target} HTTP/{version}\" {code} {res_header_Content-Length}";
|
||||
public const DEBUG = ">>>>>>>>\n{request}\n<<<<<<<<\n{response}\n--------\n{error}";
|
||||
public const SHORT = '[{ts}] "{method} {target} HTTP/{version}" {code}';
|
||||
|
||||
/** @var string Template used to format log messages */
|
||||
/**
|
||||
* @var string Template used to format log messages
|
||||
*/
|
||||
private $template;
|
||||
|
||||
/**
|
||||
* @param string $template Log message template
|
||||
*/
|
||||
public function __construct($template = self::CLF)
|
||||
public function __construct(?string $template = self::CLF)
|
||||
{
|
||||
$this->template = $template ?: self::CLF;
|
||||
}
|
||||
@@ -57,20 +64,16 @@ class MessageFormatter
|
||||
/**
|
||||
* Returns a formatted message string.
|
||||
*
|
||||
* @param RequestInterface $request Request that was sent
|
||||
* @param ResponseInterface $response Response that was received
|
||||
* @param \Exception $error Exception that was received
|
||||
*
|
||||
* @return string
|
||||
* @param RequestInterface $request Request that was sent
|
||||
* @param ResponseInterface|null $response Response that was received
|
||||
* @param \Throwable|null $error Exception that was received
|
||||
*/
|
||||
public function format(
|
||||
RequestInterface $request,
|
||||
ResponseInterface $response = null,
|
||||
\Exception $error = null
|
||||
) {
|
||||
public function format(RequestInterface $request, ?ResponseInterface $response = null, ?\Throwable $error = null): string
|
||||
{
|
||||
$cache = [];
|
||||
|
||||
return preg_replace_callback(
|
||||
/** @var string */
|
||||
return \preg_replace_callback(
|
||||
'/{\s*([A-Za-z_\-\.0-9]+)\s*}/',
|
||||
function (array $matches) use ($request, $response, $error, &$cache) {
|
||||
if (isset($cache[$matches[1]])) {
|
||||
@@ -80,20 +83,20 @@ class MessageFormatter
|
||||
$result = '';
|
||||
switch ($matches[1]) {
|
||||
case 'request':
|
||||
$result = Psr7\str($request);
|
||||
$result = Psr7\Message::toString($request);
|
||||
break;
|
||||
case 'response':
|
||||
$result = $response ? Psr7\str($response) : '';
|
||||
$result = $response ? Psr7\Message::toString($response) : '';
|
||||
break;
|
||||
case 'req_headers':
|
||||
$result = trim($request->getMethod()
|
||||
$result = \trim($request->getMethod()
|
||||
. ' ' . $request->getRequestTarget())
|
||||
. ' HTTP/' . $request->getProtocolVersion() . "\r\n"
|
||||
. $this->headers($request);
|
||||
break;
|
||||
case 'res_headers':
|
||||
$result = $response ?
|
||||
sprintf(
|
||||
\sprintf(
|
||||
'HTTP/%s %d %s',
|
||||
$response->getProtocolVersion(),
|
||||
$response->getStatusCode(),
|
||||
@@ -102,17 +105,29 @@ class MessageFormatter
|
||||
: 'NULL';
|
||||
break;
|
||||
case 'req_body':
|
||||
$result = $request->getBody();
|
||||
$result = $request->getBody()->__toString();
|
||||
break;
|
||||
case 'res_body':
|
||||
$result = $response ? $response->getBody() : 'NULL';
|
||||
if (!$response instanceof ResponseInterface) {
|
||||
$result = 'NULL';
|
||||
break;
|
||||
}
|
||||
|
||||
$body = $response->getBody();
|
||||
|
||||
if (!$body->isSeekable()) {
|
||||
$result = 'RESPONSE_NOT_LOGGEABLE';
|
||||
break;
|
||||
}
|
||||
|
||||
$result = $response->getBody()->__toString();
|
||||
break;
|
||||
case 'ts':
|
||||
case 'date_iso_8601':
|
||||
$result = gmdate('c');
|
||||
$result = \gmdate('c');
|
||||
break;
|
||||
case 'date_common_log':
|
||||
$result = date('d/M/Y:H:i:s O');
|
||||
$result = \date('d/M/Y:H:i:s O');
|
||||
break;
|
||||
case 'method':
|
||||
$result = $request->getMethod();
|
||||
@@ -122,7 +137,7 @@ class MessageFormatter
|
||||
break;
|
||||
case 'uri':
|
||||
case 'url':
|
||||
$result = $request->getUri();
|
||||
$result = $request->getUri()->__toString();
|
||||
break;
|
||||
case 'target':
|
||||
$result = $request->getRequestTarget();
|
||||
@@ -139,7 +154,7 @@ class MessageFormatter
|
||||
$result = $request->getHeaderLine('Host');
|
||||
break;
|
||||
case 'hostname':
|
||||
$result = gethostname();
|
||||
$result = \gethostname();
|
||||
break;
|
||||
case 'code':
|
||||
$result = $response ? $response->getStatusCode() : 'NULL';
|
||||
@@ -152,11 +167,11 @@ class MessageFormatter
|
||||
break;
|
||||
default:
|
||||
// handle prefixed dynamic headers
|
||||
if (strpos($matches[1], 'req_header_') === 0) {
|
||||
$result = $request->getHeaderLine(substr($matches[1], 11));
|
||||
} elseif (strpos($matches[1], 'res_header_') === 0) {
|
||||
if (\strpos($matches[1], 'req_header_') === 0) {
|
||||
$result = $request->getHeaderLine(\substr($matches[1], 11));
|
||||
} elseif (\strpos($matches[1], 'res_header_') === 0) {
|
||||
$result = $response
|
||||
? $response->getHeaderLine(substr($matches[1], 11))
|
||||
? $response->getHeaderLine(\substr($matches[1], 11))
|
||||
: 'NULL';
|
||||
}
|
||||
}
|
||||
@@ -170,16 +185,14 @@ class MessageFormatter
|
||||
|
||||
/**
|
||||
* Get headers from message as string
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function headers(MessageInterface $message)
|
||||
private function headers(MessageInterface $message): string
|
||||
{
|
||||
$result = '';
|
||||
foreach ($message->getHeaders() as $name => $values) {
|
||||
$result .= $name . ': ' . implode(', ', $values) . "\r\n";
|
||||
$result .= $name . ': ' . \implode(', ', $values) . "\r\n";
|
||||
}
|
||||
|
||||
return trim($result);
|
||||
return \trim($result);
|
||||
}
|
||||
}
|
||||
|
||||
18
vendor/guzzlehttp/guzzle/src/MessageFormatterInterface.php
vendored
Normal file
18
vendor/guzzlehttp/guzzle/src/MessageFormatterInterface.php
vendored
Normal file
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace GuzzleHttp;
|
||||
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
interface MessageFormatterInterface
|
||||
{
|
||||
/**
|
||||
* Returns a formatted message string.
|
||||
*
|
||||
* @param RequestInterface $request Request that was sent
|
||||
* @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;
|
||||
}
|
||||
116
vendor/guzzlehttp/guzzle/src/Middleware.php
vendored
116
vendor/guzzlehttp/guzzle/src/Middleware.php
vendored
@@ -1,10 +1,12 @@
|
||||
<?php
|
||||
|
||||
namespace GuzzleHttp;
|
||||
|
||||
use GuzzleHttp\Cookie\CookieJarInterface;
|
||||
use GuzzleHttp\Exception\RequestException;
|
||||
use GuzzleHttp\Promise\RejectedPromise;
|
||||
use GuzzleHttp\Psr7;
|
||||
use GuzzleHttp\Promise as P;
|
||||
use GuzzleHttp\Promise\PromiseInterface;
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
|
||||
@@ -21,10 +23,10 @@ final class Middleware
|
||||
*
|
||||
* @return callable Returns a function that accepts the next handler.
|
||||
*/
|
||||
public static function cookies()
|
||||
public static function cookies(): callable
|
||||
{
|
||||
return function (callable $handler) {
|
||||
return function ($request, array $options) use ($handler) {
|
||||
return static function (callable $handler): callable {
|
||||
return static function ($request, array $options) use ($handler) {
|
||||
if (empty($options['cookies'])) {
|
||||
return $handler($request, $options);
|
||||
} elseif (!($options['cookies'] instanceof CookieJarInterface)) {
|
||||
@@ -34,7 +36,7 @@ final class Middleware
|
||||
$request = $cookieJar->withCookieHeader($request);
|
||||
return $handler($request, $options)
|
||||
->then(
|
||||
function ($response) use ($cookieJar, $request) {
|
||||
static function (ResponseInterface $response) use ($cookieJar, $request): ResponseInterface {
|
||||
$cookieJar->extractCookies($request, $response);
|
||||
return $response;
|
||||
}
|
||||
@@ -45,24 +47,26 @@ final class Middleware
|
||||
|
||||
/**
|
||||
* Middleware that throws exceptions for 4xx or 5xx responses when the
|
||||
* "http_error" request option is set to true.
|
||||
* "http_errors" request option is set to true.
|
||||
*
|
||||
* @return callable Returns a function that accepts the next handler.
|
||||
* @param BodySummarizerInterface|null $bodySummarizer The body summarizer to use in exception messages.
|
||||
*
|
||||
* @return callable(callable): callable Returns a function that accepts the next handler.
|
||||
*/
|
||||
public static function httpErrors()
|
||||
public static function httpErrors(BodySummarizerInterface $bodySummarizer = null): callable
|
||||
{
|
||||
return function (callable $handler) {
|
||||
return function ($request, array $options) use ($handler) {
|
||||
return static function (callable $handler) use ($bodySummarizer): callable {
|
||||
return static function ($request, array $options) use ($handler, $bodySummarizer) {
|
||||
if (empty($options['http_errors'])) {
|
||||
return $handler($request, $options);
|
||||
}
|
||||
return $handler($request, $options)->then(
|
||||
function (ResponseInterface $response) use ($request) {
|
||||
static function (ResponseInterface $response) use ($request, $bodySummarizer) {
|
||||
$code = $response->getStatusCode();
|
||||
if ($code < 400) {
|
||||
return $response;
|
||||
}
|
||||
throw RequestException::create($request, $response);
|
||||
throw RequestException::create($request, $response, null, [], $bodySummarizer);
|
||||
}
|
||||
);
|
||||
};
|
||||
@@ -72,21 +76,22 @@ final class Middleware
|
||||
/**
|
||||
* Middleware that pushes history data to an ArrayAccess container.
|
||||
*
|
||||
* @param array|\ArrayAccess $container Container to hold the history (by reference).
|
||||
* @param array|\ArrayAccess<int, array> $container Container to hold the history (by reference).
|
||||
*
|
||||
* @return callable(callable): callable Returns a function that accepts the next handler.
|
||||
*
|
||||
* @return callable Returns a function that accepts the next handler.
|
||||
* @throws \InvalidArgumentException if container is not an array or ArrayAccess.
|
||||
*/
|
||||
public static function history(&$container)
|
||||
public static function history(&$container): callable
|
||||
{
|
||||
if (!is_array($container) && !$container instanceof \ArrayAccess) {
|
||||
if (!\is_array($container) && !$container instanceof \ArrayAccess) {
|
||||
throw new \InvalidArgumentException('history container must be an array or object implementing ArrayAccess');
|
||||
}
|
||||
|
||||
return function (callable $handler) use (&$container) {
|
||||
return function ($request, array $options) use ($handler, &$container) {
|
||||
return static function (callable $handler) use (&$container): callable {
|
||||
return static function (RequestInterface $request, array $options) use ($handler, &$container) {
|
||||
return $handler($request, $options)->then(
|
||||
function ($value) use ($request, &$container, $options) {
|
||||
static function ($value) use ($request, &$container, $options) {
|
||||
$container[] = [
|
||||
'request' => $request,
|
||||
'response' => $value,
|
||||
@@ -95,14 +100,14 @@ final class Middleware
|
||||
];
|
||||
return $value;
|
||||
},
|
||||
function ($reason) use ($request, &$container, $options) {
|
||||
static function ($reason) use ($request, &$container, $options) {
|
||||
$container[] = [
|
||||
'request' => $request,
|
||||
'response' => null,
|
||||
'error' => $reason,
|
||||
'options' => $options
|
||||
];
|
||||
return \GuzzleHttp\Promise\rejection_for($reason);
|
||||
return P\Create::rejectionFor($reason);
|
||||
}
|
||||
);
|
||||
};
|
||||
@@ -122,10 +127,10 @@ final class Middleware
|
||||
*
|
||||
* @return callable Returns a function that accepts the next handler.
|
||||
*/
|
||||
public static function tap(callable $before = null, callable $after = null)
|
||||
public static function tap(callable $before = null, callable $after = null): callable
|
||||
{
|
||||
return function (callable $handler) use ($before, $after) {
|
||||
return function ($request, array $options) use ($handler, $before, $after) {
|
||||
return static function (callable $handler) use ($before, $after): callable {
|
||||
return static function (RequestInterface $request, array $options) use ($handler, $before, $after) {
|
||||
if ($before) {
|
||||
$before($request, $options);
|
||||
}
|
||||
@@ -143,9 +148,9 @@ final class Middleware
|
||||
*
|
||||
* @return callable Returns a function that accepts the next handler.
|
||||
*/
|
||||
public static function redirect()
|
||||
public static function redirect(): callable
|
||||
{
|
||||
return function (callable $handler) {
|
||||
return static function (callable $handler): RedirectMiddleware {
|
||||
return new RedirectMiddleware($handler);
|
||||
};
|
||||
}
|
||||
@@ -165,9 +170,9 @@ final class Middleware
|
||||
*
|
||||
* @return callable Returns a function that accepts the next handler.
|
||||
*/
|
||||
public static function retry(callable $decider, callable $delay = null)
|
||||
public static function retry(callable $decider, callable $delay = null): callable
|
||||
{
|
||||
return function (callable $handler) use ($decider, $delay) {
|
||||
return static function (callable $handler) use ($decider, $delay): RetryMiddleware {
|
||||
return new RetryMiddleware($decider, $handler, $delay);
|
||||
};
|
||||
}
|
||||
@@ -176,29 +181,34 @@ final class Middleware
|
||||
* Middleware that logs requests, responses, and errors using a message
|
||||
* formatter.
|
||||
*
|
||||
* @param LoggerInterface $logger Logs messages.
|
||||
* @param MessageFormatter $formatter Formatter used to create message strings.
|
||||
* @param string $logLevel Level at which to log requests.
|
||||
* @phpstan-param \Psr\Log\LogLevel::* $logLevel Level at which to log requests.
|
||||
*
|
||||
* @param LoggerInterface $logger Logs messages.
|
||||
* @param MessageFormatterInterface|MessageFormatter $formatter Formatter used to create message strings.
|
||||
* @param string $logLevel Level at which to log requests.
|
||||
*
|
||||
* @return callable Returns a function that accepts the next handler.
|
||||
*/
|
||||
public static function log(LoggerInterface $logger, MessageFormatter $formatter, $logLevel = 'info' /* \Psr\Log\LogLevel::INFO */)
|
||||
public static function log(LoggerInterface $logger, $formatter, string $logLevel = 'info'): callable
|
||||
{
|
||||
return function (callable $handler) use ($logger, $formatter, $logLevel) {
|
||||
return function ($request, array $options) use ($handler, $logger, $formatter, $logLevel) {
|
||||
// To be compatible with Guzzle 7.1.x we need to allow users to pass a MessageFormatter
|
||||
if (!$formatter instanceof MessageFormatter && !$formatter instanceof MessageFormatterInterface) {
|
||||
throw new \LogicException(sprintf('Argument 2 to %s::log() must be of type %s', self::class, MessageFormatterInterface::class));
|
||||
}
|
||||
|
||||
return static function (callable $handler) use ($logger, $formatter, $logLevel): callable {
|
||||
return static function (RequestInterface $request, array $options = []) use ($handler, $logger, $formatter, $logLevel) {
|
||||
return $handler($request, $options)->then(
|
||||
function ($response) use ($logger, $request, $formatter, $logLevel) {
|
||||
static function ($response) use ($logger, $request, $formatter, $logLevel): ResponseInterface {
|
||||
$message = $formatter->format($request, $response);
|
||||
$logger->log($logLevel, $message);
|
||||
return $response;
|
||||
},
|
||||
function ($reason) use ($logger, $request, $formatter) {
|
||||
$response = $reason instanceof RequestException
|
||||
? $reason->getResponse()
|
||||
: null;
|
||||
$message = $formatter->format($request, $response, $reason);
|
||||
$logger->notice($message);
|
||||
return \GuzzleHttp\Promise\rejection_for($reason);
|
||||
static function ($reason) use ($logger, $request, $formatter): PromiseInterface {
|
||||
$response = $reason instanceof RequestException ? $reason->getResponse() : null;
|
||||
$message = $formatter->format($request, $response, P\Create::exceptionFor($reason));
|
||||
$logger->error($message);
|
||||
return P\Create::rejectionFor($reason);
|
||||
}
|
||||
);
|
||||
};
|
||||
@@ -208,12 +218,10 @@ final class Middleware
|
||||
/**
|
||||
* This middleware adds a default content-type if possible, a default
|
||||
* content-length or transfer-encoding header, and the expect header.
|
||||
*
|
||||
* @return callable
|
||||
*/
|
||||
public static function prepareBody()
|
||||
public static function prepareBody(): callable
|
||||
{
|
||||
return function (callable $handler) {
|
||||
return static function (callable $handler): PrepareBodyMiddleware {
|
||||
return new PrepareBodyMiddleware($handler);
|
||||
};
|
||||
}
|
||||
@@ -224,12 +232,11 @@ final class Middleware
|
||||
*
|
||||
* @param callable $fn Function that accepts a RequestInterface and returns
|
||||
* a RequestInterface.
|
||||
* @return callable
|
||||
*/
|
||||
public static function mapRequest(callable $fn)
|
||||
public static function mapRequest(callable $fn): callable
|
||||
{
|
||||
return function (callable $handler) use ($fn) {
|
||||
return function ($request, array $options) use ($handler, $fn) {
|
||||
return static function (callable $handler) use ($fn): callable {
|
||||
return static function (RequestInterface $request, array $options) use ($handler, $fn) {
|
||||
return $handler($fn($request), $options);
|
||||
};
|
||||
};
|
||||
@@ -241,12 +248,11 @@ final class Middleware
|
||||
*
|
||||
* @param callable $fn Function that accepts a ResponseInterface and
|
||||
* returns a ResponseInterface.
|
||||
* @return callable
|
||||
*/
|
||||
public static function mapResponse(callable $fn)
|
||||
public static function mapResponse(callable $fn): callable
|
||||
{
|
||||
return function (callable $handler) use ($fn) {
|
||||
return function ($request, array $options) use ($handler, $fn) {
|
||||
return static function (callable $handler) use ($fn): callable {
|
||||
return static function (RequestInterface $request, array $options) use ($handler, $fn) {
|
||||
return $handler($request, $options)->then($fn);
|
||||
};
|
||||
};
|
||||
|
||||
63
vendor/guzzlehttp/guzzle/src/Pool.php
vendored
63
vendor/guzzlehttp/guzzle/src/Pool.php
vendored
@@ -1,6 +1,8 @@
|
||||
<?php
|
||||
|
||||
namespace GuzzleHttp;
|
||||
|
||||
use GuzzleHttp\Promise as P;
|
||||
use GuzzleHttp\Promise\EachPromise;
|
||||
use GuzzleHttp\Promise\PromiseInterface;
|
||||
use GuzzleHttp\Promise\PromisorInterface;
|
||||
@@ -16,10 +18,14 @@ use Psr\Http\Message\RequestInterface;
|
||||
* When a function is yielded by the iterator, the function is provided the
|
||||
* "request_options" array that should be merged on top of any existing
|
||||
* options, and the function MUST then return a wait-able promise.
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class Pool implements PromisorInterface
|
||||
{
|
||||
/** @var EachPromise */
|
||||
/**
|
||||
* @var EachPromise
|
||||
*/
|
||||
private $each;
|
||||
|
||||
/**
|
||||
@@ -27,20 +33,14 @@ class Pool implements PromisorInterface
|
||||
* @param array|\Iterator $requests Requests or functions that return
|
||||
* requests to send concurrently.
|
||||
* @param array $config Associative array of options
|
||||
* - concurrency: (int) Maximum number of requests to send concurrently
|
||||
* - options: Array of request options to apply to each request.
|
||||
* - fulfilled: (callable) Function to invoke when a request completes.
|
||||
* - rejected: (callable) Function to invoke when a request is rejected.
|
||||
* - concurrency: (int) Maximum number of requests to send concurrently
|
||||
* - options: Array of request options to apply to each request.
|
||||
* - fulfilled: (callable) Function to invoke when a request completes.
|
||||
* - rejected: (callable) Function to invoke when a request is rejected.
|
||||
*/
|
||||
public function __construct(
|
||||
ClientInterface $client,
|
||||
$requests,
|
||||
array $config = []
|
||||
) {
|
||||
// Backwards compatibility.
|
||||
if (isset($config['pool_size'])) {
|
||||
$config['concurrency'] = $config['pool_size'];
|
||||
} elseif (!isset($config['concurrency'])) {
|
||||
public function __construct(ClientInterface $client, $requests, array $config = [])
|
||||
{
|
||||
if (!isset($config['concurrency'])) {
|
||||
$config['concurrency'] = 25;
|
||||
}
|
||||
|
||||
@@ -51,18 +51,15 @@ class Pool implements PromisorInterface
|
||||
$opts = [];
|
||||
}
|
||||
|
||||
$iterable = \GuzzleHttp\Promise\iter_for($requests);
|
||||
$requests = function () use ($iterable, $client, $opts) {
|
||||
$iterable = P\Create::iterFor($requests);
|
||||
$requests = static function () use ($iterable, $client, $opts) {
|
||||
foreach ($iterable as $key => $rfn) {
|
||||
if ($rfn instanceof RequestInterface) {
|
||||
yield $key => $client->sendAsync($rfn, $opts);
|
||||
} elseif (is_callable($rfn)) {
|
||||
} elseif (\is_callable($rfn)) {
|
||||
yield $key => $rfn($opts);
|
||||
} else {
|
||||
throw new \InvalidArgumentException('Each value yielded by '
|
||||
. 'the iterator must be a Psr7\Http\Message\RequestInterface '
|
||||
. 'or a callable that returns a promise that fulfills '
|
||||
. 'with a Psr7\Message\Http\ResponseInterface object.');
|
||||
throw new \InvalidArgumentException('Each value yielded by the iterator must be a Psr7\Http\Message\RequestInterface or a callable that returns a promise that fulfills with a Psr7\Message\Http\ResponseInterface object.');
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -72,10 +69,8 @@ class Pool implements PromisorInterface
|
||||
|
||||
/**
|
||||
* Get promise
|
||||
*
|
||||
* @return PromiseInterface
|
||||
*/
|
||||
public function promise()
|
||||
public function promise(): PromiseInterface
|
||||
{
|
||||
return $this->each->promise();
|
||||
}
|
||||
@@ -91,41 +86,37 @@ class Pool implements PromisorInterface
|
||||
* @param ClientInterface $client Client used to send the requests
|
||||
* @param array|\Iterator $requests Requests to send concurrently.
|
||||
* @param array $options Passes through the options available in
|
||||
* {@see GuzzleHttp\Pool::__construct}
|
||||
* {@see \GuzzleHttp\Pool::__construct}
|
||||
*
|
||||
* @return array Returns an array containing the response or an exception
|
||||
* in the same order that the requests were sent.
|
||||
*
|
||||
* @throws \InvalidArgumentException if the event format is incorrect.
|
||||
*/
|
||||
public static function batch(
|
||||
ClientInterface $client,
|
||||
$requests,
|
||||
array $options = []
|
||||
) {
|
||||
public static function batch(ClientInterface $client, $requests, array $options = []): array
|
||||
{
|
||||
$res = [];
|
||||
self::cmpCallback($options, 'fulfilled', $res);
|
||||
self::cmpCallback($options, 'rejected', $res);
|
||||
$pool = new static($client, $requests, $options);
|
||||
$pool->promise()->wait();
|
||||
ksort($res);
|
||||
\ksort($res);
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute callback(s)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private static function cmpCallback(array &$options, $name, array &$results)
|
||||
private static function cmpCallback(array &$options, string $name, array &$results): void
|
||||
{
|
||||
if (!isset($options[$name])) {
|
||||
$options[$name] = function ($v, $k) use (&$results) {
|
||||
$options[$name] = static function ($v, $k) use (&$results) {
|
||||
$results[$k] = $v;
|
||||
};
|
||||
} else {
|
||||
$currentFn = $options[$name];
|
||||
$options[$name] = function ($v, $k) use (&$results, $currentFn) {
|
||||
$options[$name] = static function ($v, $k) use (&$results, $currentFn) {
|
||||
$currentFn($v, $k);
|
||||
$results[$k] = $v;
|
||||
};
|
||||
|
||||
@@ -1,34 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace GuzzleHttp;
|
||||
|
||||
use GuzzleHttp\Promise\PromiseInterface;
|
||||
use GuzzleHttp\Psr7;
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
|
||||
/**
|
||||
* Prepares requests that contain a body, adding the Content-Length,
|
||||
* Content-Type, and Expect headers.
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class PrepareBodyMiddleware
|
||||
{
|
||||
/** @var callable */
|
||||
/**
|
||||
* @var callable(RequestInterface, array): PromiseInterface
|
||||
*/
|
||||
private $nextHandler;
|
||||
|
||||
/**
|
||||
* @param callable $nextHandler Next handler to invoke.
|
||||
* @param callable(RequestInterface, array): PromiseInterface $nextHandler Next handler to invoke.
|
||||
*/
|
||||
public function __construct(callable $nextHandler)
|
||||
{
|
||||
$this->nextHandler = $nextHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param RequestInterface $request
|
||||
* @param array $options
|
||||
*
|
||||
* @return PromiseInterface
|
||||
*/
|
||||
public function __invoke(RequestInterface $request, array $options)
|
||||
public function __invoke(RequestInterface $request, array $options): PromiseInterface
|
||||
{
|
||||
$fn = $this->nextHandler;
|
||||
|
||||
@@ -42,7 +40,7 @@ class PrepareBodyMiddleware
|
||||
// Add a default content-type if possible.
|
||||
if (!$request->hasHeader('Content-Type')) {
|
||||
if ($uri = $request->getBody()->getMetadata('uri')) {
|
||||
if ($type = Psr7\mimetype_from_filename($uri)) {
|
||||
if (is_string($uri) && $type = Psr7\MimeType::fromFilename($uri)) {
|
||||
$modify['set_headers']['Content-Type'] = $type;
|
||||
}
|
||||
}
|
||||
@@ -63,25 +61,20 @@ class PrepareBodyMiddleware
|
||||
// Add the expect header if needed.
|
||||
$this->addExpectHeader($request, $options, $modify);
|
||||
|
||||
return $fn(Psr7\modify_request($request, $modify), $options);
|
||||
return $fn(Psr7\Utils::modifyRequest($request, $modify), $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add expect header
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function addExpectHeader(
|
||||
RequestInterface $request,
|
||||
array $options,
|
||||
array &$modify
|
||||
) {
|
||||
private function addExpectHeader(RequestInterface $request, array $options, array &$modify): void
|
||||
{
|
||||
// Determine if the Expect header should be used
|
||||
if ($request->hasHeader('Expect')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$expect = isset($options['expect']) ? $options['expect'] : null;
|
||||
$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) {
|
||||
|
||||
116
vendor/guzzlehttp/guzzle/src/RedirectMiddleware.php
vendored
116
vendor/guzzlehttp/guzzle/src/RedirectMiddleware.php
vendored
@@ -1,10 +1,10 @@
|
||||
<?php
|
||||
|
||||
namespace GuzzleHttp;
|
||||
|
||||
use GuzzleHttp\Exception\BadResponseException;
|
||||
use GuzzleHttp\Exception\TooManyRedirectsException;
|
||||
use GuzzleHttp\Promise\PromiseInterface;
|
||||
use GuzzleHttp\Psr7;
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\UriInterface;
|
||||
@@ -14,13 +14,18 @@ use Psr\Http\Message\UriInterface;
|
||||
*
|
||||
* Apply this middleware like other middleware using
|
||||
* {@see \GuzzleHttp\Middleware::redirect()}.
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class RedirectMiddleware
|
||||
{
|
||||
const HISTORY_HEADER = 'X-Guzzle-Redirect-History';
|
||||
public const HISTORY_HEADER = 'X-Guzzle-Redirect-History';
|
||||
|
||||
const STATUS_HISTORY_HEADER = 'X-Guzzle-Redirect-Status-History';
|
||||
public const STATUS_HISTORY_HEADER = 'X-Guzzle-Redirect-Status-History';
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
public static $defaultSettings = [
|
||||
'max' => 5,
|
||||
'protocols' => ['http', 'https'],
|
||||
@@ -29,24 +34,20 @@ class RedirectMiddleware
|
||||
'track_redirects' => false,
|
||||
];
|
||||
|
||||
/** @var callable */
|
||||
/**
|
||||
* @var callable(RequestInterface, array): PromiseInterface
|
||||
*/
|
||||
private $nextHandler;
|
||||
|
||||
/**
|
||||
* @param callable $nextHandler Next handler to invoke.
|
||||
* @param callable(RequestInterface, array): PromiseInterface $nextHandler Next handler to invoke.
|
||||
*/
|
||||
public function __construct(callable $nextHandler)
|
||||
{
|
||||
$this->nextHandler = $nextHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param RequestInterface $request
|
||||
* @param array $options
|
||||
*
|
||||
* @return PromiseInterface
|
||||
*/
|
||||
public function __invoke(RequestInterface $request, array $options)
|
||||
public function __invoke(RequestInterface $request, array $options): PromiseInterface
|
||||
{
|
||||
$fn = $this->nextHandler;
|
||||
|
||||
@@ -56,7 +57,7 @@ class RedirectMiddleware
|
||||
|
||||
if ($options['allow_redirects'] === true) {
|
||||
$options['allow_redirects'] = self::$defaultSettings;
|
||||
} elseif (!is_array($options['allow_redirects'])) {
|
||||
} elseif (!\is_array($options['allow_redirects'])) {
|
||||
throw new \InvalidArgumentException('allow_redirects must be true, false, or array');
|
||||
} else {
|
||||
// Merge the default settings with the provided settings
|
||||
@@ -74,24 +75,17 @@ class RedirectMiddleware
|
||||
}
|
||||
|
||||
/**
|
||||
* @param RequestInterface $request
|
||||
* @param array $options
|
||||
* @param ResponseInterface $response
|
||||
*
|
||||
* @return ResponseInterface|PromiseInterface
|
||||
*/
|
||||
public function checkRedirect(
|
||||
RequestInterface $request,
|
||||
array $options,
|
||||
ResponseInterface $response
|
||||
) {
|
||||
if (substr($response->getStatusCode(), 0, 1) != '3'
|
||||
public function checkRedirect(RequestInterface $request, array $options, ResponseInterface $response)
|
||||
{
|
||||
if (\strpos((string) $response->getStatusCode(), '3') !== 0
|
||||
|| !$response->hasHeader('Location')
|
||||
) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$this->guardMax($request, $options);
|
||||
$this->guardMax($request, $response, $options);
|
||||
$nextRequest = $this->modifyRequest($request, $options, $response);
|
||||
|
||||
// If authorization is handled by curl, unset it if URI is cross-origin.
|
||||
@@ -103,15 +97,13 @@ class RedirectMiddleware
|
||||
}
|
||||
|
||||
if (isset($options['allow_redirects']['on_redirect'])) {
|
||||
call_user_func(
|
||||
$options['allow_redirects']['on_redirect'],
|
||||
($options['allow_redirects']['on_redirect'])(
|
||||
$request,
|
||||
$response,
|
||||
$nextRequest->getUri()
|
||||
);
|
||||
}
|
||||
|
||||
/** @var PromiseInterface|ResponseInterface $promise */
|
||||
$promise = $this($nextRequest, $options);
|
||||
|
||||
// Add headers to be able to track history of redirects.
|
||||
@@ -128,20 +120,19 @@ class RedirectMiddleware
|
||||
|
||||
/**
|
||||
* Enable tracking on promise.
|
||||
*
|
||||
* @return PromiseInterface
|
||||
*/
|
||||
private function withTracking(PromiseInterface $promise, $uri, $statusCode)
|
||||
private function withTracking(PromiseInterface $promise, string $uri, int $statusCode): PromiseInterface
|
||||
{
|
||||
return $promise->then(
|
||||
function (ResponseInterface $response) use ($uri, $statusCode) {
|
||||
static function (ResponseInterface $response) use ($uri, $statusCode) {
|
||||
// Note that we are pushing to the front of the list as this
|
||||
// would be an earlier response than what is currently present
|
||||
// in the history header.
|
||||
$historyHeader = $response->getHeader(self::HISTORY_HEADER);
|
||||
$statusHeader = $response->getHeader(self::STATUS_HISTORY_HEADER);
|
||||
array_unshift($historyHeader, $uri);
|
||||
array_unshift($statusHeader, $statusCode);
|
||||
\array_unshift($historyHeader, $uri);
|
||||
\array_unshift($statusHeader, (string) $statusCode);
|
||||
|
||||
return $response->withHeader(self::HISTORY_HEADER, $historyHeader)
|
||||
->withHeader(self::STATUS_HISTORY_HEADER, $statusHeader);
|
||||
}
|
||||
@@ -151,38 +142,22 @@ class RedirectMiddleware
|
||||
/**
|
||||
* Check for too many redirects.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @throws TooManyRedirectsException Too many redirects.
|
||||
*/
|
||||
private function guardMax(RequestInterface $request, array &$options)
|
||||
private function guardMax(RequestInterface $request, ResponseInterface $response, array &$options): void
|
||||
{
|
||||
$current = isset($options['__redirect_count'])
|
||||
? $options['__redirect_count']
|
||||
: 0;
|
||||
$current = $options['__redirect_count']
|
||||
?? 0;
|
||||
$options['__redirect_count'] = $current + 1;
|
||||
$max = $options['allow_redirects']['max'];
|
||||
|
||||
if ($options['__redirect_count'] > $max) {
|
||||
throw new TooManyRedirectsException(
|
||||
"Will not follow more than {$max} redirects",
|
||||
$request
|
||||
);
|
||||
throw new TooManyRedirectsException("Will not follow more than {$max} redirects", $request, $response);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param RequestInterface $request
|
||||
* @param array $options
|
||||
* @param ResponseInterface $response
|
||||
*
|
||||
* @return RequestInterface
|
||||
*/
|
||||
public function modifyRequest(
|
||||
RequestInterface $request,
|
||||
array $options,
|
||||
ResponseInterface $response
|
||||
) {
|
||||
public function modifyRequest(RequestInterface $request, array $options, ResponseInterface $response): RequestInterface
|
||||
{
|
||||
// Request modifications to apply.
|
||||
$modify = [];
|
||||
$protocols = $options['allow_redirects']['protocols'];
|
||||
@@ -194,18 +169,21 @@ class RedirectMiddleware
|
||||
if ($statusCode == 303 ||
|
||||
($statusCode <= 302 && !$options['allow_redirects']['strict'])
|
||||
) {
|
||||
$modify['method'] = 'GET';
|
||||
$safeMethods = ['GET', 'HEAD', 'OPTIONS'];
|
||||
$requestMethod = $request->getMethod();
|
||||
|
||||
$modify['method'] = in_array($requestMethod, $safeMethods) ? $requestMethod : 'GET';
|
||||
$modify['body'] = '';
|
||||
}
|
||||
|
||||
$uri = self::redirectUri($request, $response, $protocols);
|
||||
if (isset($options['idn_conversion']) && ($options['idn_conversion'] !== false)) {
|
||||
$idnOptions = ($options['idn_conversion'] === true) ? IDNA_DEFAULT : $options['idn_conversion'];
|
||||
$idnOptions = ($options['idn_conversion'] === true) ? \IDNA_DEFAULT : $options['idn_conversion'];
|
||||
$uri = Utils::idnUriConvert($uri, $idnOptions);
|
||||
}
|
||||
|
||||
$modify['uri'] = $uri;
|
||||
Psr7\rewind_body($request);
|
||||
Psr7\Message::rewindBody($request);
|
||||
|
||||
// Add the Referer header if it is told to do so and only
|
||||
// add the header if we are not redirecting from https to http.
|
||||
@@ -224,39 +202,25 @@ class RedirectMiddleware
|
||||
$modify['remove_headers'][] = 'Cookie';
|
||||
}
|
||||
|
||||
return Psr7\modify_request($request, $modify);
|
||||
return Psr7\Utils::modifyRequest($request, $modify);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the appropriate URL on the request based on the location header.
|
||||
*
|
||||
* @param RequestInterface $request
|
||||
* @param ResponseInterface $response
|
||||
* @param array $protocols
|
||||
*
|
||||
* @return UriInterface
|
||||
*/
|
||||
private static function redirectUri(
|
||||
RequestInterface $request,
|
||||
ResponseInterface $response,
|
||||
array $protocols
|
||||
) {
|
||||
): UriInterface {
|
||||
$location = Psr7\UriResolver::resolve(
|
||||
$request->getUri(),
|
||||
new Psr7\Uri($response->getHeaderLine('Location'))
|
||||
);
|
||||
|
||||
// Ensure that the redirect URI is allowed based on the protocols.
|
||||
if (!in_array($location->getScheme(), $protocols)) {
|
||||
throw new BadResponseException(
|
||||
sprintf(
|
||||
'Redirect URI, %s, does not use one of the allowed redirect protocols: %s',
|
||||
$location,
|
||||
implode(', ', $protocols)
|
||||
),
|
||||
$request,
|
||||
$response
|
||||
);
|
||||
if (!\in_array($location->getScheme(), $protocols)) {
|
||||
throw new BadResponseException(\sprintf('Redirect URI, %s, does not use one of the allowed redirect protocols: %s', $location, \implode(', ', $protocols)), $request, $response);
|
||||
}
|
||||
|
||||
return $location;
|
||||
|
||||
63
vendor/guzzlehttp/guzzle/src/RequestOptions.php
vendored
63
vendor/guzzlehttp/guzzle/src/RequestOptions.php
vendored
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
namespace GuzzleHttp;
|
||||
|
||||
/**
|
||||
@@ -31,7 +32,7 @@ final class RequestOptions
|
||||
* response that was received, and the effective URI. Any return value
|
||||
* from the on_redirect function is ignored.
|
||||
*/
|
||||
const ALLOW_REDIRECTS = 'allow_redirects';
|
||||
public const ALLOW_REDIRECTS = 'allow_redirects';
|
||||
|
||||
/**
|
||||
* auth: (array) Pass an array of HTTP authentication parameters to use
|
||||
@@ -40,13 +41,13 @@ final class RequestOptions
|
||||
* authentication type in index [2]. Pass null to disable authentication
|
||||
* for a request.
|
||||
*/
|
||||
const AUTH = 'auth';
|
||||
public const AUTH = 'auth';
|
||||
|
||||
/**
|
||||
* body: (resource|string|null|int|float|StreamInterface|callable|\Iterator)
|
||||
* Body to send in the request.
|
||||
*/
|
||||
const BODY = 'body';
|
||||
public const BODY = 'body';
|
||||
|
||||
/**
|
||||
* cert: (string|array) Set to a string to specify the path to a file
|
||||
@@ -55,42 +56,42 @@ final class RequestOptions
|
||||
* file in the first array element followed by the certificate password
|
||||
* in the second array element.
|
||||
*/
|
||||
const CERT = 'cert';
|
||||
public const CERT = 'cert';
|
||||
|
||||
/**
|
||||
* cookies: (bool|GuzzleHttp\Cookie\CookieJarInterface, default=false)
|
||||
* 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 \GuzzleHttp\Cookie\CookieJarInterface}.
|
||||
*/
|
||||
const COOKIES = 'cookies';
|
||||
public const COOKIES = 'cookies';
|
||||
|
||||
/**
|
||||
* connect_timeout: (float, default=0) Float describing the number of
|
||||
* seconds to wait while trying to connect to a server. Use 0 to wait
|
||||
* indefinitely (the default behavior).
|
||||
*/
|
||||
const CONNECT_TIMEOUT = 'connect_timeout';
|
||||
public const CONNECT_TIMEOUT = 'connect_timeout';
|
||||
|
||||
/**
|
||||
* debug: (bool|resource) Set to true or set to a PHP stream returned by
|
||||
* fopen() enable debug output with the HTTP handler used to send a
|
||||
* request.
|
||||
*/
|
||||
const DEBUG = 'debug';
|
||||
public const DEBUG = 'debug';
|
||||
|
||||
/**
|
||||
* decode_content: (bool, default=true) Specify whether or not
|
||||
* Content-Encoding responses (gzip, deflate, etc.) are automatically
|
||||
* decoded.
|
||||
*/
|
||||
const DECODE_CONTENT = 'decode_content';
|
||||
public const DECODE_CONTENT = 'decode_content';
|
||||
|
||||
/**
|
||||
* delay: (int) The amount of time to delay before sending in milliseconds.
|
||||
*/
|
||||
const DELAY = 'delay';
|
||||
public const DELAY = 'delay';
|
||||
|
||||
/**
|
||||
* expect: (bool|integer) Controls the behavior of the
|
||||
@@ -108,7 +109,7 @@ final class RequestOptions
|
||||
* size of the body of a request is greater than 1 MB and a request is
|
||||
* using HTTP/1.1.
|
||||
*/
|
||||
const EXPECT = 'expect';
|
||||
public const EXPECT = 'expect';
|
||||
|
||||
/**
|
||||
* form_params: (array) Associative array of form field names to values
|
||||
@@ -116,13 +117,13 @@ final class RequestOptions
|
||||
* header to application/x-www-form-urlencoded when no Content-Type header
|
||||
* is already present.
|
||||
*/
|
||||
const FORM_PARAMS = 'form_params';
|
||||
public const FORM_PARAMS = 'form_params';
|
||||
|
||||
/**
|
||||
* headers: (array) Associative array of HTTP headers. Each value MUST be
|
||||
* a string or array of strings.
|
||||
*/
|
||||
const HEADERS = 'headers';
|
||||
public const HEADERS = 'headers';
|
||||
|
||||
/**
|
||||
* http_errors: (bool, default=true) Set to false to disable exceptions
|
||||
@@ -130,7 +131,7 @@ final class RequestOptions
|
||||
* exceptions will be thrown for 4xx and 5xx responses. This option only
|
||||
* works if your handler has the `httpErrors` middleware.
|
||||
*/
|
||||
const HTTP_ERRORS = 'http_errors';
|
||||
public const HTTP_ERRORS = 'http_errors';
|
||||
|
||||
/**
|
||||
* idn: (bool|int, default=true) A combination of IDNA_* constants for
|
||||
@@ -138,14 +139,14 @@ final class RequestOptions
|
||||
* disable IDN support completely, or to true to use the default
|
||||
* configuration (IDNA_DEFAULT constant).
|
||||
*/
|
||||
const IDN_CONVERSION = 'idn_conversion';
|
||||
public const IDN_CONVERSION = 'idn_conversion';
|
||||
|
||||
/**
|
||||
* json: (mixed) Adds JSON data to a request. The provided value is JSON
|
||||
* encoded and a Content-Type header of application/json will be added to
|
||||
* the request if no Content-Type header is already present.
|
||||
*/
|
||||
const JSON = 'json';
|
||||
public const JSON = 'json';
|
||||
|
||||
/**
|
||||
* multipart: (array) Array of associative arrays, each containing a
|
||||
@@ -156,14 +157,14 @@ final class RequestOptions
|
||||
* the part. If no "filename" key is present, then no "filename" attribute
|
||||
* will be added to the part.
|
||||
*/
|
||||
const MULTIPART = 'multipart';
|
||||
public const MULTIPART = 'multipart';
|
||||
|
||||
/**
|
||||
* on_headers: (callable) A callable that is invoked when the HTTP headers
|
||||
* of the response have been received but the body has not yet begun to
|
||||
* download.
|
||||
*/
|
||||
const ON_HEADERS = 'on_headers';
|
||||
public const ON_HEADERS = 'on_headers';
|
||||
|
||||
/**
|
||||
* on_stats: (callable) allows you to get access to transfer statistics of
|
||||
@@ -174,7 +175,7 @@ final class RequestOptions
|
||||
* the error encountered. Included in the data is the total amount of time
|
||||
* taken to send the request.
|
||||
*/
|
||||
const ON_STATS = 'on_stats';
|
||||
public const ON_STATS = 'on_stats';
|
||||
|
||||
/**
|
||||
* progress: (callable) Defines a function to invoke when transfer
|
||||
@@ -183,14 +184,14 @@ final class RequestOptions
|
||||
* number of bytes downloaded so far, the number of bytes expected to be
|
||||
* uploaded, the number of bytes uploaded so far.
|
||||
*/
|
||||
const PROGRESS = 'progress';
|
||||
public const PROGRESS = 'progress';
|
||||
|
||||
/**
|
||||
* proxy: (string|array) Pass a string to specify an HTTP proxy, or an
|
||||
* array to specify different proxies for different protocols (where the
|
||||
* key is the protocol and the value is a proxy string).
|
||||
*/
|
||||
const PROXY = 'proxy';
|
||||
public const PROXY = 'proxy';
|
||||
|
||||
/**
|
||||
* query: (array|string) Associative array of query string values to add
|
||||
@@ -198,14 +199,14 @@ final class RequestOptions
|
||||
* the string representation. Pass a string value if you need more
|
||||
* control than what this method provides
|
||||
*/
|
||||
const QUERY = 'query';
|
||||
public const QUERY = 'query';
|
||||
|
||||
/**
|
||||
* sink: (resource|string|StreamInterface) Where the data of the
|
||||
* response is written to. Defaults to a PHP temp stream. Providing a
|
||||
* string will write data to a file by the given name.
|
||||
*/
|
||||
const SINK = 'sink';
|
||||
public const SINK = 'sink';
|
||||
|
||||
/**
|
||||
* synchronous: (bool) Set to true to inform HTTP handlers that you intend
|
||||
@@ -213,7 +214,7 @@ final class RequestOptions
|
||||
* that a promise is still returned if you are using one of the async
|
||||
* client methods.
|
||||
*/
|
||||
const SYNCHRONOUS = 'synchronous';
|
||||
public const SYNCHRONOUS = 'synchronous';
|
||||
|
||||
/**
|
||||
* ssl_key: (array|string) Specify the path to a file containing a private
|
||||
@@ -221,13 +222,13 @@ final class RequestOptions
|
||||
* containing the path to the SSL key in the first array element followed
|
||||
* by the password required for the certificate in the second element.
|
||||
*/
|
||||
const SSL_KEY = 'ssl_key';
|
||||
public const SSL_KEY = 'ssl_key';
|
||||
|
||||
/**
|
||||
* stream: Set to true to attempt to stream a response rather than
|
||||
* download it all up-front.
|
||||
*/
|
||||
const STREAM = 'stream';
|
||||
public const STREAM = 'stream';
|
||||
|
||||
/**
|
||||
* verify: (bool|string, default=true) Describes the SSL certificate
|
||||
@@ -237,27 +238,27 @@ final class RequestOptions
|
||||
* is insecure!). Set to a string to provide the path to a CA bundle on
|
||||
* disk to enable verification using a custom certificate.
|
||||
*/
|
||||
const VERIFY = 'verify';
|
||||
public const VERIFY = 'verify';
|
||||
|
||||
/**
|
||||
* timeout: (float, default=0) Float describing the timeout of the
|
||||
* request in seconds. Use 0 to wait indefinitely (the default behavior).
|
||||
*/
|
||||
const TIMEOUT = 'timeout';
|
||||
public const TIMEOUT = 'timeout';
|
||||
|
||||
/**
|
||||
* read_timeout: (float, default=default_socket_timeout ini setting) Float describing
|
||||
* the body read timeout, for stream requests.
|
||||
*/
|
||||
const READ_TIMEOUT = 'read_timeout';
|
||||
public const READ_TIMEOUT = 'read_timeout';
|
||||
|
||||
/**
|
||||
* version: (float) Specifies the HTTP protocol version to attempt to use.
|
||||
*/
|
||||
const VERSION = 'version';
|
||||
public const VERSION = 'version';
|
||||
|
||||
/**
|
||||
* force_ip_resolve: (bool) Force client to use only ipv4 or ipv6 protocol
|
||||
*/
|
||||
const FORCE_IP_RESOLVE = 'force_ip_resolve';
|
||||
public const FORCE_IP_RESOLVE = 'force_ip_resolve';
|
||||
}
|
||||
|
||||
84
vendor/guzzlehttp/guzzle/src/RetryMiddleware.php
vendored
84
vendor/guzzlehttp/guzzle/src/RetryMiddleware.php
vendored
@@ -1,42 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace GuzzleHttp;
|
||||
|
||||
use GuzzleHttp\Promise as P;
|
||||
use GuzzleHttp\Promise\PromiseInterface;
|
||||
use GuzzleHttp\Promise\RejectedPromise;
|
||||
use GuzzleHttp\Psr7;
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
/**
|
||||
* Middleware that retries requests based on the boolean result of
|
||||
* invoking the provided "decider" function.
|
||||
*
|
||||
* @final
|
||||
*/
|
||||
class RetryMiddleware
|
||||
{
|
||||
/** @var callable */
|
||||
/**
|
||||
* @var callable(RequestInterface, array): PromiseInterface
|
||||
*/
|
||||
private $nextHandler;
|
||||
|
||||
/** @var callable */
|
||||
/**
|
||||
* @var callable
|
||||
*/
|
||||
private $decider;
|
||||
|
||||
/** @var callable */
|
||||
/**
|
||||
* @var callable(int)
|
||||
*/
|
||||
private $delay;
|
||||
|
||||
/**
|
||||
* @param callable $decider Function that accepts the number of retries,
|
||||
* a request, [response], and [exception] and
|
||||
* returns true if the request is to be
|
||||
* retried.
|
||||
* @param callable $nextHandler Next handler to invoke.
|
||||
* @param callable $delay Function that accepts the number of retries
|
||||
* and [response] and returns the number of
|
||||
* milliseconds to delay.
|
||||
* @param callable $decider Function that accepts the number of retries,
|
||||
* a request, [response], and [exception] and
|
||||
* returns true if the request is to be
|
||||
* retried.
|
||||
* @param callable(RequestInterface, array): PromiseInterface $nextHandler Next handler to invoke.
|
||||
* @param (callable(int): int)|null $delay Function that accepts the number of retries
|
||||
* 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;
|
||||
$this->delay = $delay ?: __CLASS__ . '::exponentialDelay';
|
||||
@@ -45,22 +50,14 @@ class RetryMiddleware
|
||||
/**
|
||||
* Default exponential backoff delay function.
|
||||
*
|
||||
* @param int $retries
|
||||
*
|
||||
* @return int milliseconds.
|
||||
*/
|
||||
public static function exponentialDelay($retries)
|
||||
public static function exponentialDelay(int $retries): int
|
||||
{
|
||||
return (int) pow(2, $retries - 1) * 1000;
|
||||
return (int) \pow(2, $retries - 1) * 1000;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param RequestInterface $request
|
||||
* @param array $options
|
||||
*
|
||||
* @return PromiseInterface
|
||||
*/
|
||||
public function __invoke(RequestInterface $request, array $options)
|
||||
public function __invoke(RequestInterface $request, array $options): PromiseInterface
|
||||
{
|
||||
if (!isset($options['retries'])) {
|
||||
$options['retries'] = 0;
|
||||
@@ -76,52 +73,43 @@ class RetryMiddleware
|
||||
|
||||
/**
|
||||
* Execute fulfilled closure
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
private function onFulfilled(RequestInterface $req, array $options)
|
||||
private function onFulfilled(RequestInterface $request, array $options): callable
|
||||
{
|
||||
return function ($value) use ($req, $options) {
|
||||
if (!call_user_func(
|
||||
$this->decider,
|
||||
return function ($value) use ($request, $options) {
|
||||
if (!($this->decider)(
|
||||
$options['retries'],
|
||||
$req,
|
||||
$request,
|
||||
$value,
|
||||
null
|
||||
)) {
|
||||
return $value;
|
||||
}
|
||||
return $this->doRetry($req, $options, $value);
|
||||
return $this->doRetry($request, $options, $value);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute rejected closure
|
||||
*
|
||||
* @return callable
|
||||
*/
|
||||
private function onRejected(RequestInterface $req, array $options)
|
||||
private function onRejected(RequestInterface $req, array $options): callable
|
||||
{
|
||||
return function ($reason) use ($req, $options) {
|
||||
if (!call_user_func(
|
||||
$this->decider,
|
||||
if (!($this->decider)(
|
||||
$options['retries'],
|
||||
$req,
|
||||
null,
|
||||
$reason
|
||||
)) {
|
||||
return \GuzzleHttp\Promise\rejection_for($reason);
|
||||
return P\Create::rejectionFor($reason);
|
||||
}
|
||||
return $this->doRetry($req, $options);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @return self
|
||||
*/
|
||||
private function doRetry(RequestInterface $request, array $options, ResponseInterface $response = null)
|
||||
private function doRetry(RequestInterface $request, array $options, ResponseInterface $response = null): PromiseInterface
|
||||
{
|
||||
$options['delay'] = call_user_func($this->delay, ++$options['retries'], $response);
|
||||
$options['delay'] = ($this->delay)(++$options['retries'], $response, $request);
|
||||
|
||||
return $this($request, $options);
|
||||
}
|
||||
|
||||
55
vendor/guzzlehttp/guzzle/src/TransferStats.php
vendored
55
vendor/guzzlehttp/guzzle/src/TransferStats.php
vendored
@@ -1,4 +1,5 @@
|
||||
<?php
|
||||
|
||||
namespace GuzzleHttp;
|
||||
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
@@ -11,10 +12,29 @@ use Psr\Http\Message\UriInterface;
|
||||
*/
|
||||
final class TransferStats
|
||||
{
|
||||
/**
|
||||
* @var RequestInterface
|
||||
*/
|
||||
private $request;
|
||||
|
||||
/**
|
||||
* @var ResponseInterface|null
|
||||
*/
|
||||
private $response;
|
||||
|
||||
/**
|
||||
* @var float|null
|
||||
*/
|
||||
private $transferTime;
|
||||
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
private $handlerStats;
|
||||
|
||||
/**
|
||||
* @var mixed|null
|
||||
*/
|
||||
private $handlerErrorData;
|
||||
|
||||
/**
|
||||
@@ -26,10 +46,10 @@ final class TransferStats
|
||||
*/
|
||||
public function __construct(
|
||||
RequestInterface $request,
|
||||
ResponseInterface $response = null,
|
||||
$transferTime = null,
|
||||
?ResponseInterface $response = null,
|
||||
?float $transferTime = null,
|
||||
$handlerErrorData = null,
|
||||
$handlerStats = []
|
||||
array $handlerStats = []
|
||||
) {
|
||||
$this->request = $request;
|
||||
$this->response = $response;
|
||||
@@ -38,30 +58,23 @@ final class TransferStats
|
||||
$this->handlerStats = $handlerStats;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return RequestInterface
|
||||
*/
|
||||
public function getRequest()
|
||||
public function getRequest(): RequestInterface
|
||||
{
|
||||
return $this->request;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the response that was received (if any).
|
||||
*
|
||||
* @return ResponseInterface|null
|
||||
*/
|
||||
public function getResponse()
|
||||
public function getResponse(): ?ResponseInterface
|
||||
{
|
||||
return $this->response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if a response was received.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasResponse()
|
||||
public function hasResponse(): bool
|
||||
{
|
||||
return $this->response !== null;
|
||||
}
|
||||
@@ -82,10 +95,8 @@ final class TransferStats
|
||||
|
||||
/**
|
||||
* Get the effective URI the request was sent to.
|
||||
*
|
||||
* @return UriInterface
|
||||
*/
|
||||
public function getEffectiveUri()
|
||||
public function getEffectiveUri(): UriInterface
|
||||
{
|
||||
return $this->request->getUri();
|
||||
}
|
||||
@@ -95,17 +106,15 @@ final class TransferStats
|
||||
*
|
||||
* @return float|null Time in seconds.
|
||||
*/
|
||||
public function getTransferTime()
|
||||
public function getTransferTime(): ?float
|
||||
{
|
||||
return $this->transferTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an array of all of the handler specific transfer data.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getHandlerStats()
|
||||
public function getHandlerStats(): array
|
||||
{
|
||||
return $this->handlerStats;
|
||||
}
|
||||
@@ -117,10 +126,8 @@ final class TransferStats
|
||||
*
|
||||
* @return mixed|null
|
||||
*/
|
||||
public function getHandlerStat($stat)
|
||||
public function getHandlerStat(string $stat)
|
||||
{
|
||||
return isset($this->handlerStats[$stat])
|
||||
? $this->handlerStats[$stat]
|
||||
: null;
|
||||
return $this->handlerStats[$stat] ?? null;
|
||||
}
|
||||
}
|
||||
|
||||
237
vendor/guzzlehttp/guzzle/src/UriTemplate.php
vendored
237
vendor/guzzlehttp/guzzle/src/UriTemplate.php
vendored
@@ -1,237 +0,0 @@
|
||||
<?php
|
||||
namespace GuzzleHttp;
|
||||
|
||||
/**
|
||||
* Expands URI templates. Userland implementation of PECL uri_template.
|
||||
*
|
||||
* @link http://tools.ietf.org/html/rfc6570
|
||||
*/
|
||||
class UriTemplate
|
||||
{
|
||||
/** @var string URI template */
|
||||
private $template;
|
||||
|
||||
/** @var array Variables to use in the template expansion */
|
||||
private $variables;
|
||||
|
||||
/** @var array Hash for quick operator lookups */
|
||||
private static $operatorHash = [
|
||||
'' => ['prefix' => '', 'joiner' => ',', 'query' => false],
|
||||
'+' => ['prefix' => '', 'joiner' => ',', 'query' => false],
|
||||
'#' => ['prefix' => '#', 'joiner' => ',', 'query' => false],
|
||||
'.' => ['prefix' => '.', 'joiner' => '.', 'query' => false],
|
||||
'/' => ['prefix' => '/', 'joiner' => '/', 'query' => false],
|
||||
';' => ['prefix' => ';', 'joiner' => ';', 'query' => true],
|
||||
'?' => ['prefix' => '?', 'joiner' => '&', 'query' => true],
|
||||
'&' => ['prefix' => '&', 'joiner' => '&', 'query' => true]
|
||||
];
|
||||
|
||||
/** @var array Delimiters */
|
||||
private static $delims = [':', '/', '?', '#', '[', ']', '@', '!', '$',
|
||||
'&', '\'', '(', ')', '*', '+', ',', ';', '='];
|
||||
|
||||
/** @var array Percent encoded delimiters */
|
||||
private static $delimsPct = ['%3A', '%2F', '%3F', '%23', '%5B', '%5D',
|
||||
'%40', '%21', '%24', '%26', '%27', '%28', '%29', '%2A', '%2B', '%2C',
|
||||
'%3B', '%3D'];
|
||||
|
||||
public function expand($template, array $variables)
|
||||
{
|
||||
if (false === strpos($template, '{')) {
|
||||
return $template;
|
||||
}
|
||||
|
||||
$this->template = $template;
|
||||
$this->variables = $variables;
|
||||
|
||||
return preg_replace_callback(
|
||||
'/\{([^\}]+)\}/',
|
||||
[$this, 'expandMatch'],
|
||||
$this->template
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse an expression into parts
|
||||
*
|
||||
* @param string $expression Expression to parse
|
||||
*
|
||||
* @return array Returns an associative array of parts
|
||||
*/
|
||||
private function parseExpression($expression)
|
||||
{
|
||||
$result = [];
|
||||
|
||||
if (isset(self::$operatorHash[$expression[0]])) {
|
||||
$result['operator'] = $expression[0];
|
||||
$expression = substr($expression, 1);
|
||||
} else {
|
||||
$result['operator'] = '';
|
||||
}
|
||||
|
||||
foreach (explode(',', $expression) as $value) {
|
||||
$value = trim($value);
|
||||
$varspec = [];
|
||||
if ($colonPos = strpos($value, ':')) {
|
||||
$varspec['value'] = substr($value, 0, $colonPos);
|
||||
$varspec['modifier'] = ':';
|
||||
$varspec['position'] = (int) substr($value, $colonPos + 1);
|
||||
} elseif (substr($value, -1) === '*') {
|
||||
$varspec['modifier'] = '*';
|
||||
$varspec['value'] = substr($value, 0, -1);
|
||||
} else {
|
||||
$varspec['value'] = (string) $value;
|
||||
$varspec['modifier'] = '';
|
||||
}
|
||||
$result['values'][] = $varspec;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process an expansion
|
||||
*
|
||||
* @param array $matches Matches met in the preg_replace_callback
|
||||
*
|
||||
* @return string Returns the replacement string
|
||||
*/
|
||||
private function expandMatch(array $matches)
|
||||
{
|
||||
static $rfc1738to3986 = ['+' => '%20', '%7e' => '~'];
|
||||
|
||||
$replacements = [];
|
||||
$parsed = self::parseExpression($matches[1]);
|
||||
$prefix = self::$operatorHash[$parsed['operator']]['prefix'];
|
||||
$joiner = self::$operatorHash[$parsed['operator']]['joiner'];
|
||||
$useQuery = self::$operatorHash[$parsed['operator']]['query'];
|
||||
|
||||
foreach ($parsed['values'] as $value) {
|
||||
if (!isset($this->variables[$value['value']])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$variable = $this->variables[$value['value']];
|
||||
$actuallyUseQuery = $useQuery;
|
||||
$expanded = '';
|
||||
|
||||
if (is_array($variable)) {
|
||||
$isAssoc = $this->isAssoc($variable);
|
||||
$kvp = [];
|
||||
foreach ($variable as $key => $var) {
|
||||
if ($isAssoc) {
|
||||
$key = rawurlencode($key);
|
||||
$isNestedArray = is_array($var);
|
||||
} else {
|
||||
$isNestedArray = false;
|
||||
}
|
||||
|
||||
if (!$isNestedArray) {
|
||||
$var = rawurlencode($var);
|
||||
if ($parsed['operator'] === '+' ||
|
||||
$parsed['operator'] === '#'
|
||||
) {
|
||||
$var = $this->decodeReserved($var);
|
||||
}
|
||||
}
|
||||
|
||||
if ($value['modifier'] === '*') {
|
||||
if ($isAssoc) {
|
||||
if ($isNestedArray) {
|
||||
// Nested arrays must allow for deeply nested
|
||||
// structures.
|
||||
$var = strtr(
|
||||
http_build_query([$key => $var]),
|
||||
$rfc1738to3986
|
||||
);
|
||||
} else {
|
||||
$var = $key . '=' . $var;
|
||||
}
|
||||
} elseif ($key > 0 && $actuallyUseQuery) {
|
||||
$var = $value['value'] . '=' . $var;
|
||||
}
|
||||
}
|
||||
|
||||
$kvp[$key] = $var;
|
||||
}
|
||||
|
||||
if (empty($variable)) {
|
||||
$actuallyUseQuery = false;
|
||||
} elseif ($value['modifier'] === '*') {
|
||||
$expanded = implode($joiner, $kvp);
|
||||
if ($isAssoc) {
|
||||
// Don't prepend the value name when using the explode
|
||||
// modifier with an associative array.
|
||||
$actuallyUseQuery = false;
|
||||
}
|
||||
} else {
|
||||
if ($isAssoc) {
|
||||
// When an associative array is encountered and the
|
||||
// explode modifier is not set, then the result must be
|
||||
// a comma separated list of keys followed by their
|
||||
// respective values.
|
||||
foreach ($kvp as $k => &$v) {
|
||||
$v = $k . ',' . $v;
|
||||
}
|
||||
}
|
||||
$expanded = implode(',', $kvp);
|
||||
}
|
||||
} else {
|
||||
if ($value['modifier'] === ':') {
|
||||
$variable = substr($variable, 0, $value['position']);
|
||||
}
|
||||
$expanded = rawurlencode($variable);
|
||||
if ($parsed['operator'] === '+' || $parsed['operator'] === '#') {
|
||||
$expanded = $this->decodeReserved($expanded);
|
||||
}
|
||||
}
|
||||
|
||||
if ($actuallyUseQuery) {
|
||||
if (!$expanded && $joiner !== '&') {
|
||||
$expanded = $value['value'];
|
||||
} else {
|
||||
$expanded = $value['value'] . '=' . $expanded;
|
||||
}
|
||||
}
|
||||
|
||||
$replacements[] = $expanded;
|
||||
}
|
||||
|
||||
$ret = implode($joiner, $replacements);
|
||||
if ($ret && $prefix) {
|
||||
return $prefix . $ret;
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if an array is associative.
|
||||
*
|
||||
* This makes the assumption that input arrays are sequences or hashes.
|
||||
* This assumption is a tradeoff for accuracy in favor of speed, but it
|
||||
* should work in almost every case where input is supplied for a URI
|
||||
* template.
|
||||
*
|
||||
* @param array $array Array to check
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function isAssoc(array $array)
|
||||
{
|
||||
return $array && array_keys($array)[0] !== 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes percent encoding on reserved characters (used with + and #
|
||||
* modifiers).
|
||||
*
|
||||
* @param string $string String to fix
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function decodeReserved($string)
|
||||
{
|
||||
return str_replace(self::$delimsPct, self::$delims, $string);
|
||||
}
|
||||
}
|
||||
365
vendor/guzzlehttp/guzzle/src/Utils.php
vendored
365
vendor/guzzlehttp/guzzle/src/Utils.php
vendored
@@ -1,41 +1,334 @@
|
||||
<?php
|
||||
|
||||
namespace GuzzleHttp;
|
||||
|
||||
use GuzzleHttp\Exception\InvalidArgumentException;
|
||||
use GuzzleHttp\Handler\CurlHandler;
|
||||
use GuzzleHttp\Handler\CurlMultiHandler;
|
||||
use GuzzleHttp\Handler\Proxy;
|
||||
use GuzzleHttp\Handler\StreamHandler;
|
||||
use Psr\Http\Message\UriInterface;
|
||||
use Symfony\Polyfill\Intl\Idn\Idn;
|
||||
|
||||
final class Utils
|
||||
{
|
||||
/**
|
||||
* Wrapper for the hrtime() or microtime() functions
|
||||
* (depending on the PHP version, one of the two is used)
|
||||
* Debug function used to describe the provided value type and class.
|
||||
*
|
||||
* @return float|mixed UNIX timestamp
|
||||
* @param mixed $input
|
||||
*
|
||||
* @internal
|
||||
* @return string Returns a string containing the type of the variable and
|
||||
* if a class is provided, the class name.
|
||||
*/
|
||||
public static function currentTime()
|
||||
public static function describeType($input): string
|
||||
{
|
||||
return function_exists('hrtime') ? hrtime(true) / 1e9 : microtime(true);
|
||||
switch (\gettype($input)) {
|
||||
case 'object':
|
||||
return 'object(' . \get_class($input) . ')';
|
||||
case 'array':
|
||||
return 'array(' . \count($input) . ')';
|
||||
default:
|
||||
\ob_start();
|
||||
\var_dump($input);
|
||||
// normalize float vs double
|
||||
/** @var string $varDumpContent */
|
||||
$varDumpContent = \ob_get_clean();
|
||||
|
||||
return \str_replace('double(', 'float(', \rtrim($varDumpContent));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $options
|
||||
* Parses an array of header lines into an associative array of headers.
|
||||
*
|
||||
* @return UriInterface
|
||||
* @param iterable $lines Header lines array of strings in the following
|
||||
* format: "Name: Value"
|
||||
*/
|
||||
public static function headersFromLines(iterable $lines): array
|
||||
{
|
||||
$headers = [];
|
||||
|
||||
foreach ($lines as $line) {
|
||||
$parts = \explode(':', $line, 2);
|
||||
$headers[\trim($parts[0])][] = isset($parts[1]) ? \trim($parts[1]) : null;
|
||||
}
|
||||
|
||||
return $headers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a debug stream based on the provided variable.
|
||||
*
|
||||
* @param mixed $value Optional value
|
||||
*
|
||||
* @return resource
|
||||
*/
|
||||
public static function debugResource($value = null)
|
||||
{
|
||||
if (\is_resource($value)) {
|
||||
return $value;
|
||||
}
|
||||
if (\defined('STDOUT')) {
|
||||
return \STDOUT;
|
||||
}
|
||||
|
||||
return \GuzzleHttp\Psr7\Utils::tryFopen('php://output', 'w');
|
||||
}
|
||||
|
||||
/**
|
||||
* Chooses and creates a default handler to use based on the environment.
|
||||
*
|
||||
* The returned handler is not wrapped by any default middlewares.
|
||||
*
|
||||
* @throws \RuntimeException if no viable Handler is available.
|
||||
*
|
||||
* @return callable(\Psr\Http\Message\RequestInterface, array): \GuzzleHttp\Promise\PromiseInterface Returns the best handler for the given system.
|
||||
*/
|
||||
public static function chooseHandler(): callable
|
||||
{
|
||||
$handler = null;
|
||||
|
||||
if (\defined('CURLOPT_CUSTOMREQUEST')) {
|
||||
if (\function_exists('curl_multi_exec') && \function_exists('curl_exec')) {
|
||||
$handler = Proxy::wrapSync(new CurlMultiHandler(), new CurlHandler());
|
||||
} elseif (\function_exists('curl_exec')) {
|
||||
$handler = new CurlHandler();
|
||||
} elseif (\function_exists('curl_multi_exec')) {
|
||||
$handler = new CurlMultiHandler();
|
||||
}
|
||||
}
|
||||
|
||||
if (\ini_get('allow_url_fopen')) {
|
||||
$handler = $handler
|
||||
? Proxy::wrapStreaming($handler, new StreamHandler())
|
||||
: new StreamHandler();
|
||||
} elseif (!$handler) {
|
||||
throw new \RuntimeException('GuzzleHttp requires cURL, the allow_url_fopen ini setting, or a custom HTTP handler.');
|
||||
}
|
||||
|
||||
return $handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default User-Agent string to use with Guzzle.
|
||||
*/
|
||||
public static function defaultUserAgent(): string
|
||||
{
|
||||
return sprintf('GuzzleHttp/%d', ClientInterface::MAJOR_VERSION);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default cacert bundle for the current system.
|
||||
*
|
||||
* First, the openssl.cafile and curl.cainfo php.ini settings are checked.
|
||||
* If those settings are not configured, then the common locations for
|
||||
* bundles found on Red Hat, CentOS, Fedora, Ubuntu, Debian, FreeBSD, OS X
|
||||
* and Windows are checked. If any of these file locations are found on
|
||||
* disk, they will be utilized.
|
||||
*
|
||||
* Note: the result of this function is cached for subsequent calls.
|
||||
*
|
||||
* @throws \RuntimeException if no bundle can be found.
|
||||
*
|
||||
* @deprecated Utils::defaultCaBundle will be removed in guzzlehttp/guzzle:8.0. This method is not needed in PHP 5.6+.
|
||||
*/
|
||||
public static function defaultCaBundle(): string
|
||||
{
|
||||
static $cached = null;
|
||||
static $cafiles = [
|
||||
// Red Hat, CentOS, Fedora (provided by the ca-certificates package)
|
||||
'/etc/pki/tls/certs/ca-bundle.crt',
|
||||
// Ubuntu, Debian (provided by the ca-certificates package)
|
||||
'/etc/ssl/certs/ca-certificates.crt',
|
||||
// FreeBSD (provided by the ca_root_nss package)
|
||||
'/usr/local/share/certs/ca-root-nss.crt',
|
||||
// SLES 12 (provided by the ca-certificates package)
|
||||
'/var/lib/ca-certificates/ca-bundle.pem',
|
||||
// OS X provided by homebrew (using the default path)
|
||||
'/usr/local/etc/openssl/cert.pem',
|
||||
// Google app engine
|
||||
'/etc/ca-certificates.crt',
|
||||
// Windows?
|
||||
'C:\\windows\\system32\\curl-ca-bundle.crt',
|
||||
'C:\\windows\\curl-ca-bundle.crt',
|
||||
];
|
||||
|
||||
if ($cached) {
|
||||
return $cached;
|
||||
}
|
||||
|
||||
if ($ca = \ini_get('openssl.cafile')) {
|
||||
return $cached = $ca;
|
||||
}
|
||||
|
||||
if ($ca = \ini_get('curl.cainfo')) {
|
||||
return $cached = $ca;
|
||||
}
|
||||
|
||||
foreach ($cafiles as $filename) {
|
||||
if (\file_exists($filename)) {
|
||||
return $cached = $filename;
|
||||
}
|
||||
}
|
||||
|
||||
throw new \RuntimeException(
|
||||
<<< EOT
|
||||
No system CA bundle could be found in any of the the common system locations.
|
||||
PHP versions earlier than 5.6 are not properly configured to use the system's
|
||||
CA bundle by default. In order to verify peer certificates, you will need to
|
||||
supply the path on disk to a certificate bundle to the 'verify' request
|
||||
option: http://docs.guzzlephp.org/en/latest/clients.html#verify. If you do not
|
||||
need a specific certificate bundle, then Mozilla provides a commonly used CA
|
||||
bundle which can be downloaded here (provided by the maintainer of cURL):
|
||||
https://curl.haxx.se/ca/cacert.pem. Once
|
||||
you have a CA bundle available on disk, you can set the 'openssl.cafile' PHP
|
||||
ini setting to point to the path to the file, allowing you to omit the 'verify'
|
||||
request option. See https://curl.haxx.se/docs/sslcerts.html for more
|
||||
information.
|
||||
EOT
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an associative array of lowercase header names to the actual
|
||||
* header casing.
|
||||
*/
|
||||
public static function normalizeHeaderKeys(array $headers): array
|
||||
{
|
||||
$result = [];
|
||||
foreach (\array_keys($headers) as $key) {
|
||||
$result[\strtolower($key)] = $key;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the provided host matches any of the no proxy areas.
|
||||
*
|
||||
* This method will strip a port from the host if it is present. Each pattern
|
||||
* can be matched with an exact match (e.g., "foo.com" == "foo.com") or a
|
||||
* partial match: (e.g., "foo.com" == "baz.foo.com" and ".foo.com" ==
|
||||
* "baz.foo.com", but ".foo.com" != "foo.com").
|
||||
*
|
||||
* Areas are matched in the following cases:
|
||||
* 1. "*" (without quotes) always matches any hosts.
|
||||
* 2. An exact match.
|
||||
* 3. The area starts with "." and the area is the last part of the host. e.g.
|
||||
* '.mit.edu' will match any host that ends with '.mit.edu'.
|
||||
*
|
||||
* @param string $host Host to check against the patterns.
|
||||
* @param string[] $noProxyArray An array of host patterns.
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public static function isHostInNoProxy(string $host, array $noProxyArray): bool
|
||||
{
|
||||
if (\strlen($host) === 0) {
|
||||
throw new InvalidArgumentException('Empty host provided');
|
||||
}
|
||||
|
||||
// Strip port if present.
|
||||
[$host] = \explode(':', $host, 2);
|
||||
|
||||
foreach ($noProxyArray as $area) {
|
||||
// Always match on wildcards.
|
||||
if ($area === '*') {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (empty($area)) {
|
||||
// Don't match on empty values.
|
||||
continue;
|
||||
}
|
||||
|
||||
if ($area === $host) {
|
||||
// Exact matches.
|
||||
return true;
|
||||
}
|
||||
// Special match if the area when prefixed with ".". Remove any
|
||||
// existing leading "." and add a new leading ".".
|
||||
$area = '.' . \ltrim($area, '.');
|
||||
if (\substr($host, -(\strlen($area))) === $area) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for json_decode that throws when an error occurs.
|
||||
*
|
||||
* @param string $json JSON data to parse
|
||||
* @param bool $assoc When true, returned objects will be converted
|
||||
* into associative arrays.
|
||||
* @param int $depth User specified recursion depth.
|
||||
* @param int $options Bitmask of JSON decode options.
|
||||
*
|
||||
* @return object|array|string|int|float|bool|null
|
||||
*
|
||||
* @throws InvalidArgumentException if the JSON cannot be decoded.
|
||||
*
|
||||
* @link https://www.php.net/manual/en/function.json-decode.php
|
||||
*/
|
||||
public static function jsonDecode(string $json, bool $assoc = false, int $depth = 512, int $options = 0)
|
||||
{
|
||||
$data = \json_decode($json, $assoc, $depth, $options);
|
||||
if (\JSON_ERROR_NONE !== \json_last_error()) {
|
||||
throw new InvalidArgumentException('json_decode error: ' . \json_last_error_msg());
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for JSON encoding that throws when an error occurs.
|
||||
*
|
||||
* @param mixed $value The value being encoded
|
||||
* @param int $options JSON encode option bitmask
|
||||
* @param int $depth Set the maximum depth. Must be greater than zero.
|
||||
*
|
||||
* @throws InvalidArgumentException if the JSON cannot be encoded.
|
||||
*
|
||||
* @link https://www.php.net/manual/en/function.json-encode.php
|
||||
*/
|
||||
public static function jsonEncode($value, int $options = 0, int $depth = 512): string
|
||||
{
|
||||
$json = \json_encode($value, $options, $depth);
|
||||
if (\JSON_ERROR_NONE !== \json_last_error()) {
|
||||
throw new InvalidArgumentException('json_encode error: ' . \json_last_error_msg());
|
||||
}
|
||||
|
||||
/** @var string */
|
||||
return $json;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for the hrtime() or microtime() functions
|
||||
* (depending on the PHP version, one of the two is used)
|
||||
*
|
||||
* @return float UNIX timestamp
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public static function currentTime(): float
|
||||
{
|
||||
return (float) \function_exists('hrtime') ? \hrtime(true) / 1e9 : \microtime(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws InvalidArgumentException
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public static function idnUriConvert(UriInterface $uri, $options = 0)
|
||||
public static function idnUriConvert(UriInterface $uri, int $options = 0): UriInterface
|
||||
{
|
||||
if ($uri->getHost()) {
|
||||
$asciiHost = self::idnToAsci($uri->getHost(), $options, $info);
|
||||
if ($asciiHost === false) {
|
||||
$errorBitSet = isset($info['errors']) ? $info['errors'] : 0;
|
||||
$errorBitSet = $info['errors'] ?? 0;
|
||||
|
||||
$errorConstants = array_filter(array_keys(get_defined_constants()), function ($name) {
|
||||
$errorConstants = array_filter(array_keys(get_defined_constants()), static function (string $name): bool {
|
||||
return substr($name, 0, 11) === 'IDNA_ERROR_';
|
||||
});
|
||||
|
||||
@@ -52,11 +345,10 @@ final class Utils
|
||||
}
|
||||
|
||||
throw new InvalidArgumentException($errorMessage);
|
||||
} else {
|
||||
if ($uri->getHost() !== $asciiHost) {
|
||||
// Replace URI only if the ASCII version is different
|
||||
$uri = $uri->withHost($asciiHost);
|
||||
}
|
||||
}
|
||||
if ($uri->getHost() !== $asciiHost) {
|
||||
// Replace URI only if the ASCII version is different
|
||||
$uri = $uri->withHost($asciiHost);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -64,29 +356,30 @@ final class Utils
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $domain
|
||||
* @param int $options
|
||||
* @param array $info
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public static function getenv(string $name): ?string
|
||||
{
|
||||
if (isset($_SERVER[$name])) {
|
||||
return (string) $_SERVER[$name];
|
||||
}
|
||||
|
||||
if (\PHP_SAPI === 'cli' && ($value = \getenv($name)) !== false && $value !== null) {
|
||||
return (string) $value;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string|false
|
||||
*/
|
||||
private static function idnToAsci($domain, $options, &$info = [])
|
||||
private static function idnToAsci(string $domain, int $options, ?array &$info = [])
|
||||
{
|
||||
if (\preg_match('%^[ -~]+$%', $domain) === 1) {
|
||||
return $domain;
|
||||
if (\function_exists('idn_to_ascii') && \defined('INTL_IDNA_VARIANT_UTS46')) {
|
||||
return \idn_to_ascii($domain, $options, \INTL_IDNA_VARIANT_UTS46, $info);
|
||||
}
|
||||
|
||||
if (\extension_loaded('intl') && defined('INTL_IDNA_VARIANT_UTS46')) {
|
||||
return \idn_to_ascii($domain, $options, INTL_IDNA_VARIANT_UTS46, $info);
|
||||
}
|
||||
|
||||
/*
|
||||
* The Idn class is marked as @internal. Verify that class and method exists.
|
||||
*/
|
||||
if (method_exists(Idn::class, 'idn_to_ascii')) {
|
||||
return Idn::idn_to_ascii($domain, $options, Idn::INTL_IDNA_VARIANT_UTS46, $info);
|
||||
}
|
||||
|
||||
throw new \RuntimeException('ext-intl or symfony/polyfill-intl-idn not loaded or too old');
|
||||
throw new \Error('ext-idn or symfony/polyfill-intl-idn not loaded or too old');
|
||||
}
|
||||
}
|
||||
|
||||
275
vendor/guzzlehttp/guzzle/src/functions.php
vendored
275
vendor/guzzlehttp/guzzle/src/functions.php
vendored
@@ -1,77 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace GuzzleHttp;
|
||||
|
||||
use GuzzleHttp\Handler\CurlHandler;
|
||||
use GuzzleHttp\Handler\CurlMultiHandler;
|
||||
use GuzzleHttp\Handler\Proxy;
|
||||
use GuzzleHttp\Handler\StreamHandler;
|
||||
|
||||
/**
|
||||
* Expands a URI template
|
||||
*
|
||||
* @param string $template URI template
|
||||
* @param array $variables Template variables
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function uri_template($template, array $variables)
|
||||
{
|
||||
if (extension_loaded('uri_template')) {
|
||||
// @codeCoverageIgnoreStart
|
||||
return \uri_template($template, $variables);
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
static $uriTemplate;
|
||||
if (!$uriTemplate) {
|
||||
$uriTemplate = new UriTemplate();
|
||||
}
|
||||
|
||||
return $uriTemplate->expand($template, $variables);
|
||||
}
|
||||
|
||||
/**
|
||||
* Debug function used to describe the provided value type and class.
|
||||
*
|
||||
* @param mixed $input
|
||||
* @param mixed $input Any type of variable to describe the type of. This
|
||||
* parameter misses a typehint because of that.
|
||||
*
|
||||
* @return string Returns a string containing the type of the variable and
|
||||
* if a class is provided, the class name.
|
||||
*
|
||||
* @deprecated describe_type will be removed in guzzlehttp/guzzle:8.0. Use Utils::describeType instead.
|
||||
*/
|
||||
function describe_type($input)
|
||||
function describe_type($input): string
|
||||
{
|
||||
switch (gettype($input)) {
|
||||
case 'object':
|
||||
return 'object(' . get_class($input) . ')';
|
||||
case 'array':
|
||||
return 'array(' . count($input) . ')';
|
||||
default:
|
||||
ob_start();
|
||||
var_dump($input);
|
||||
// normalize float vs double
|
||||
return str_replace('double(', 'float(', rtrim(ob_get_clean()));
|
||||
}
|
||||
return Utils::describeType($input);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an array of header lines into an associative array of headers.
|
||||
*
|
||||
* @param iterable $lines Header lines array of strings in the following
|
||||
* format: "Name: Value"
|
||||
* @return array
|
||||
* format: "Name: Value"
|
||||
*
|
||||
* @deprecated headers_from_lines will be removed in guzzlehttp/guzzle:8.0. Use Utils::headersFromLines instead.
|
||||
*/
|
||||
function headers_from_lines($lines)
|
||||
function headers_from_lines(iterable $lines): array
|
||||
{
|
||||
$headers = [];
|
||||
|
||||
foreach ($lines as $line) {
|
||||
$parts = explode(':', $line, 2);
|
||||
$headers[trim($parts[0])][] = isset($parts[1])
|
||||
? trim($parts[1])
|
||||
: null;
|
||||
}
|
||||
|
||||
return $headers;
|
||||
return Utils::headersFromLines($lines);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -80,16 +37,12 @@ function headers_from_lines($lines)
|
||||
* @param mixed $value Optional value
|
||||
*
|
||||
* @return resource
|
||||
*
|
||||
* @deprecated debug_resource will be removed in guzzlehttp/guzzle:8.0. Use Utils::debugResource instead.
|
||||
*/
|
||||
function debug_resource($value = null)
|
||||
{
|
||||
if (is_resource($value)) {
|
||||
return $value;
|
||||
} elseif (defined('STDOUT')) {
|
||||
return STDOUT;
|
||||
}
|
||||
|
||||
return fopen('php://output', 'w');
|
||||
return Utils::debugResource($value);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -97,50 +50,25 @@ function debug_resource($value = null)
|
||||
*
|
||||
* The returned handler is not wrapped by any default middlewares.
|
||||
*
|
||||
* @return callable Returns the best handler for the given system.
|
||||
* @throws \RuntimeException if no viable Handler is available.
|
||||
*
|
||||
* @return callable(\Psr\Http\Message\RequestInterface, array): \GuzzleHttp\Promise\PromiseInterface Returns the best handler for the given system.
|
||||
*
|
||||
* @deprecated choose_handler will be removed in guzzlehttp/guzzle:8.0. Use Utils::chooseHandler instead.
|
||||
*/
|
||||
function choose_handler()
|
||||
function choose_handler(): callable
|
||||
{
|
||||
$handler = null;
|
||||
if (function_exists('curl_multi_exec') && function_exists('curl_exec')) {
|
||||
$handler = Proxy::wrapSync(new CurlMultiHandler(), new CurlHandler());
|
||||
} elseif (function_exists('curl_exec')) {
|
||||
$handler = new CurlHandler();
|
||||
} elseif (function_exists('curl_multi_exec')) {
|
||||
$handler = new CurlMultiHandler();
|
||||
}
|
||||
|
||||
if (ini_get('allow_url_fopen')) {
|
||||
$handler = $handler
|
||||
? Proxy::wrapStreaming($handler, new StreamHandler())
|
||||
: new StreamHandler();
|
||||
} elseif (!$handler) {
|
||||
throw new \RuntimeException('GuzzleHttp requires cURL, the '
|
||||
. 'allow_url_fopen ini setting, or a custom HTTP handler.');
|
||||
}
|
||||
|
||||
return $handler;
|
||||
return Utils::chooseHandler();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default User-Agent string to use with Guzzle
|
||||
* Get the default User-Agent string to use with Guzzle.
|
||||
*
|
||||
* @return string
|
||||
* @deprecated default_user_agent will be removed in guzzlehttp/guzzle:8.0. Use Utils::defaultUserAgent instead.
|
||||
*/
|
||||
function default_user_agent()
|
||||
function default_user_agent(): string
|
||||
{
|
||||
static $defaultAgent = '';
|
||||
|
||||
if (!$defaultAgent) {
|
||||
$defaultAgent = 'GuzzleHttp/' . Client::VERSION;
|
||||
if (extension_loaded('curl') && function_exists('curl_version')) {
|
||||
$defaultAgent .= ' curl/' . \curl_version()['version'];
|
||||
}
|
||||
$defaultAgent .= ' PHP/' . PHP_VERSION;
|
||||
}
|
||||
|
||||
return $defaultAgent;
|
||||
return Utils::defaultUserAgent();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -154,82 +82,24 @@ function default_user_agent()
|
||||
*
|
||||
* Note: the result of this function is cached for subsequent calls.
|
||||
*
|
||||
* @return string
|
||||
* @throws \RuntimeException if no bundle can be found.
|
||||
*
|
||||
* @deprecated default_ca_bundle will be removed in guzzlehttp/guzzle:8.0. This function is not needed in PHP 5.6+.
|
||||
*/
|
||||
function default_ca_bundle()
|
||||
function default_ca_bundle(): string
|
||||
{
|
||||
static $cached = null;
|
||||
static $cafiles = [
|
||||
// Red Hat, CentOS, Fedora (provided by the ca-certificates package)
|
||||
'/etc/pki/tls/certs/ca-bundle.crt',
|
||||
// Ubuntu, Debian (provided by the ca-certificates package)
|
||||
'/etc/ssl/certs/ca-certificates.crt',
|
||||
// FreeBSD (provided by the ca_root_nss package)
|
||||
'/usr/local/share/certs/ca-root-nss.crt',
|
||||
// SLES 12 (provided by the ca-certificates package)
|
||||
'/var/lib/ca-certificates/ca-bundle.pem',
|
||||
// OS X provided by homebrew (using the default path)
|
||||
'/usr/local/etc/openssl/cert.pem',
|
||||
// Google app engine
|
||||
'/etc/ca-certificates.crt',
|
||||
// Windows?
|
||||
'C:\\windows\\system32\\curl-ca-bundle.crt',
|
||||
'C:\\windows\\curl-ca-bundle.crt',
|
||||
];
|
||||
|
||||
if ($cached) {
|
||||
return $cached;
|
||||
}
|
||||
|
||||
if ($ca = ini_get('openssl.cafile')) {
|
||||
return $cached = $ca;
|
||||
}
|
||||
|
||||
if ($ca = ini_get('curl.cainfo')) {
|
||||
return $cached = $ca;
|
||||
}
|
||||
|
||||
foreach ($cafiles as $filename) {
|
||||
if (file_exists($filename)) {
|
||||
return $cached = $filename;
|
||||
}
|
||||
}
|
||||
|
||||
throw new \RuntimeException(
|
||||
<<< EOT
|
||||
No system CA bundle could be found in any of the the common system locations.
|
||||
PHP versions earlier than 5.6 are not properly configured to use the system's
|
||||
CA bundle by default. In order to verify peer certificates, you will need to
|
||||
supply the path on disk to a certificate bundle to the 'verify' request
|
||||
option: http://docs.guzzlephp.org/en/latest/clients.html#verify. If you do not
|
||||
need a specific certificate bundle, then Mozilla provides a commonly used CA
|
||||
bundle which can be downloaded here (provided by the maintainer of cURL):
|
||||
https://raw.githubusercontent.com/bagder/ca-bundle/master/ca-bundle.crt. Once
|
||||
you have a CA bundle available on disk, you can set the 'openssl.cafile' PHP
|
||||
ini setting to point to the path to the file, allowing you to omit the 'verify'
|
||||
request option. See http://curl.haxx.se/docs/sslcerts.html for more
|
||||
information.
|
||||
EOT
|
||||
);
|
||||
return Utils::defaultCaBundle();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an associative array of lowercase header names to the actual
|
||||
* header casing.
|
||||
*
|
||||
* @param array $headers
|
||||
*
|
||||
* @return array
|
||||
* @deprecated normalize_header_keys will be removed in guzzlehttp/guzzle:8.0. Use Utils::normalizeHeaderKeys instead.
|
||||
*/
|
||||
function normalize_header_keys(array $headers)
|
||||
function normalize_header_keys(array $headers): array
|
||||
{
|
||||
$result = [];
|
||||
foreach (array_keys($headers) as $key) {
|
||||
$result[strtolower($key)] = $key;
|
||||
}
|
||||
|
||||
return $result;
|
||||
return Utils::normalizeHeaderKeys($headers);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -246,89 +116,52 @@ function normalize_header_keys(array $headers)
|
||||
* 3. The area starts with "." and the area is the last part of the host. e.g.
|
||||
* '.mit.edu' will match any host that ends with '.mit.edu'.
|
||||
*
|
||||
* @param string $host Host to check against the patterns.
|
||||
* @param array $noProxyArray An array of host patterns.
|
||||
* @param string $host Host to check against the patterns.
|
||||
* @param string[] $noProxyArray An array of host patterns.
|
||||
*
|
||||
* @return bool
|
||||
* @throws Exception\InvalidArgumentException
|
||||
*
|
||||
* @deprecated is_host_in_noproxy will be removed in guzzlehttp/guzzle:8.0. Use Utils::isHostInNoProxy instead.
|
||||
*/
|
||||
function is_host_in_noproxy($host, array $noProxyArray)
|
||||
function is_host_in_noproxy(string $host, array $noProxyArray): bool
|
||||
{
|
||||
if (strlen($host) === 0) {
|
||||
throw new \InvalidArgumentException('Empty host provided');
|
||||
}
|
||||
|
||||
// Strip port if present.
|
||||
if (strpos($host, ':')) {
|
||||
$host = explode($host, ':', 2)[0];
|
||||
}
|
||||
|
||||
foreach ($noProxyArray as $area) {
|
||||
// Always match on wildcards.
|
||||
if ($area === '*') {
|
||||
return true;
|
||||
} elseif (empty($area)) {
|
||||
// Don't match on empty values.
|
||||
continue;
|
||||
} elseif ($area === $host) {
|
||||
// Exact matches.
|
||||
return true;
|
||||
} else {
|
||||
// Special match if the area when prefixed with ".". Remove any
|
||||
// existing leading "." and add a new leading ".".
|
||||
$area = '.' . ltrim($area, '.');
|
||||
if (substr($host, -(strlen($area))) === $area) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
return Utils::isHostInNoProxy($host, $noProxyArray);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for json_decode that throws when an error occurs.
|
||||
*
|
||||
* @param string $json JSON data to parse
|
||||
* @param bool $assoc When true, returned objects will be converted
|
||||
* @param bool $assoc When true, returned objects will be converted
|
||||
* into associative arrays.
|
||||
* @param int $depth User specified recursion depth.
|
||||
* @param int $options Bitmask of JSON decode options.
|
||||
*
|
||||
* @return mixed
|
||||
* @return object|array|string|int|float|bool|null
|
||||
*
|
||||
* @throws Exception\InvalidArgumentException if the JSON cannot be decoded.
|
||||
* @link http://www.php.net/manual/en/function.json-decode.php
|
||||
*
|
||||
* @link https://www.php.net/manual/en/function.json-decode.php
|
||||
* @deprecated json_decode will be removed in guzzlehttp/guzzle:8.0. Use Utils::jsonDecode instead.
|
||||
*/
|
||||
function json_decode($json, $assoc = false, $depth = 512, $options = 0)
|
||||
function json_decode(string $json, bool $assoc = false, int $depth = 512, int $options = 0)
|
||||
{
|
||||
$data = \json_decode($json, $assoc, $depth, $options);
|
||||
if (JSON_ERROR_NONE !== json_last_error()) {
|
||||
throw new Exception\InvalidArgumentException(
|
||||
'json_decode error: ' . json_last_error_msg()
|
||||
);
|
||||
}
|
||||
|
||||
return $data;
|
||||
return Utils::jsonDecode($json, $assoc, $depth, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for JSON encoding that throws when an error occurs.
|
||||
*
|
||||
* @param mixed $value The value being encoded
|
||||
* @param int $options JSON encode option bitmask
|
||||
* @param int $depth Set the maximum depth. Must be greater than zero.
|
||||
* @param int $options JSON encode option bitmask
|
||||
* @param int $depth Set the maximum depth. Must be greater than zero.
|
||||
*
|
||||
* @return string
|
||||
* @throws Exception\InvalidArgumentException if the JSON cannot be encoded.
|
||||
* @link http://www.php.net/manual/en/function.json-encode.php
|
||||
*
|
||||
* @link https://www.php.net/manual/en/function.json-encode.php
|
||||
* @deprecated json_encode will be removed in guzzlehttp/guzzle:8.0. Use Utils::jsonEncode instead.
|
||||
*/
|
||||
function json_encode($value, $options = 0, $depth = 512)
|
||||
function json_encode($value, int $options = 0, int $depth = 512): string
|
||||
{
|
||||
$json = \json_encode($value, $options, $depth);
|
||||
if (JSON_ERROR_NONE !== json_last_error()) {
|
||||
throw new Exception\InvalidArgumentException(
|
||||
'json_encode error: ' . json_last_error_msg()
|
||||
);
|
||||
}
|
||||
|
||||
return $json;
|
||||
return Utils::jsonEncode($value, $options, $depth);
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
<?php
|
||||
|
||||
// Don't redefine the functions if included multiple times.
|
||||
if (!function_exists('GuzzleHttp\uri_template')) {
|
||||
if (!\function_exists('GuzzleHttp\describe_type')) {
|
||||
require __DIR__ . '/functions.php';
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user