Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nextcloud/3rdparty.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristoph Wurst <christoph@winzerhof-wurst.at>2020-02-06 20:49:21 +0300
committerChristoph Wurst <christoph@winzerhof-wurst.at>2020-02-06 20:49:21 +0300
commitd583bf2a4b2db903846bfbf1600f69f3b4b60702 (patch)
treeebb17468edebe72b58a4b123cee7dc4ef3cc9372 /guzzlehttp
parent052a1b2481dbf65b6ede66f1d35b0da54f92b3c6 (diff)
Vendor #364 and #396 files
Signed-off-by: Christoph Wurst <christoph@winzerhof-wurst.at>
Diffstat (limited to 'guzzlehttp')
-rw-r--r--guzzlehttp/guzzle/src/Client.php101
-rw-r--r--guzzlehttp/guzzle/src/ClientInterface.php7
-rw-r--r--guzzlehttp/guzzle/src/Cookie/CookieJar.php8
-rw-r--r--guzzlehttp/guzzle/src/Cookie/CookieJarInterface.php6
-rw-r--r--guzzlehttp/guzzle/src/Cookie/FileCookieJar.php3
-rw-r--r--guzzlehttp/guzzle/src/Cookie/SessionCookieJar.php1
-rw-r--r--guzzlehttp/guzzle/src/Cookie/SetCookie.php4
-rw-r--r--guzzlehttp/guzzle/src/Exception/ClientException.php4
-rw-r--r--guzzlehttp/guzzle/src/Exception/GuzzleException.php30
-rw-r--r--guzzlehttp/guzzle/src/Exception/RequestException.php35
-rw-r--r--guzzlehttp/guzzle/src/Exception/ServerException.php4
-rw-r--r--guzzlehttp/guzzle/src/Exception/TooManyRedirectsException.php4
-rw-r--r--guzzlehttp/guzzle/src/Exception/TransferException.php4
-rw-r--r--guzzlehttp/guzzle/src/Handler/CurlFactory.php44
-rw-r--r--guzzlehttp/guzzle/src/Handler/CurlMultiHandler.php34
-rw-r--r--guzzlehttp/guzzle/src/Handler/MockHandler.php10
-rw-r--r--guzzlehttp/guzzle/src/Handler/StreamHandler.php24
-rw-r--r--guzzlehttp/guzzle/src/HandlerStack.php14
-rw-r--r--guzzlehttp/guzzle/src/MessageFormatter.php5
-rw-r--r--guzzlehttp/guzzle/src/Middleware.php7
-rw-r--r--guzzlehttp/guzzle/src/Pool.php15
-rw-r--r--guzzlehttp/guzzle/src/PrepareBodyMiddleware.php5
-rw-r--r--guzzlehttp/guzzle/src/RedirectMiddleware.php28
-rw-r--r--guzzlehttp/guzzle/src/RequestOptions.php10
-rw-r--r--guzzlehttp/guzzle/src/RetryMiddleware.php22
-rw-r--r--guzzlehttp/guzzle/src/TransferStats.php12
-rw-r--r--guzzlehttp/guzzle/src/functions.php73
-rw-r--r--guzzlehttp/psr7/CHANGELOG.md23
-rw-r--r--guzzlehttp/psr7/composer.json10
-rw-r--r--guzzlehttp/psr7/src/LimitStream.php2
-rw-r--r--guzzlehttp/psr7/src/MessageTrait.php60
-rw-r--r--guzzlehttp/psr7/src/Request.php9
-rw-r--r--guzzlehttp/psr7/src/Response.php28
-rw-r--r--guzzlehttp/psr7/src/ServerRequest.php2
-rw-r--r--guzzlehttp/psr7/src/Stream.php33
-rw-r--r--guzzlehttp/psr7/src/Uri.php36
-rw-r--r--guzzlehttp/psr7/src/functions.php1
37 files changed, 547 insertions, 171 deletions
diff --git a/guzzlehttp/guzzle/src/Client.php b/guzzlehttp/guzzle/src/Client.php
index 80417918..f2bf2044 100644
--- a/guzzlehttp/guzzle/src/Client.php
+++ b/guzzlehttp/guzzle/src/Client.php
@@ -2,11 +2,12 @@
namespace GuzzleHttp;
use GuzzleHttp\Cookie\CookieJar;
+use GuzzleHttp\Exception\InvalidArgumentException;
use GuzzleHttp\Promise;
use GuzzleHttp\Psr7;
-use Psr\Http\Message\UriInterface;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
+use Psr\Http\Message\UriInterface;
/**
* @method ResponseInterface get(string|UriInterface $uri, array $options = [])
@@ -75,6 +76,12 @@ class Client implements ClientInterface
$this->configureDefaults($config);
}
+ /**
+ * @param string $method
+ * @param array $args
+ *
+ * @return Promise\PromiseInterface
+ */
public function __call($method, $args)
{
if (count($args) < 1) {
@@ -89,6 +96,14 @@ class Client implements ClientInterface
: $this->request($method, $uri, $opts);
}
+ /**
+ * Asynchronously send an HTTP request.
+ *
+ * @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 = [])
{
// Merge the base URI into the request URI if needed.
@@ -100,12 +115,35 @@ class Client implements ClientInterface
);
}
+ /**
+ * Send an HTTP request.
+ *
+ * @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 = [])
{
$options[RequestOptions::SYNCHRONOUS] = true;
return $this->sendAsync($request, $options)->wait();
}
+ /**
+ * 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. See \GuzzleHttp\RequestOptions.
+ *
+ * @return Promise\PromiseInterface
+ */
public function requestAsync($method, $uri = '', array $options = [])
{
$options = $this->prepareDefaults($options);
@@ -125,12 +163,37 @@ class Client implements ClientInterface
return $this->transfer($request, $options);
}
+ /**
+ * 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. See \GuzzleHttp\RequestOptions.
+ *
+ * @return ResponseInterface
+ * @throws GuzzleException
+ */
public function request($method, $uri = '', array $options = [])
{
$options[RequestOptions::SYNCHRONOUS] = true;
return $this->requestAsync($method, $uri, $options)->wait();
}
+ /**
+ * Get a client configuration option.
+ *
+ * These options include default request options of the client, a "handler"
+ * (if utilized by the concrete client), and a "base_uri" if utilized by
+ * the concrete client.
+ *
+ * @param string|null $option The config option to retrieve.
+ *
+ * @return mixed
+ */
public function getConfig($option = null)
{
return $option === null
@@ -138,6 +201,11 @@ class Client implements ClientInterface
: (isset($this->config[$option]) ? $this->config[$option] : null);
}
+ /**
+ * @param string|null $uri
+ *
+ * @return UriInterface
+ */
private function buildUri($uri, array $config)
{
// for BC we accept null which would otherwise fail in uri_for
@@ -147,6 +215,11 @@ class Client implements ClientInterface
$uri = Psr7\UriResolver::resolve(Psr7\uri_for($config['base_uri']), $uri);
}
+ if (isset($config['idn_conversion']) && ($config['idn_conversion'] !== false)) {
+ $idnOptions = ($config['idn_conversion'] === true) ? IDNA_DEFAULT : $config['idn_conversion'];
+ $uri = _idn_uri_convert($uri, $idnOptions);
+ }
+
return $uri->getScheme() === '' && $uri->getHost() !== '' ? $uri->withScheme('http') : $uri;
}
@@ -154,6 +227,7 @@ class Client implements ClientInterface
* Configures the default options for a client.
*
* @param array $config
+ * @return void
*/
private function configureDefaults(array $config)
{
@@ -165,12 +239,22 @@ class Client implements ClientInterface
'cookies' => false
];
+ // idn_to_ascii() is a part of ext-intl and might be not available
+ $defaults['idn_conversion'] = function_exists('idn_to_ascii')
+ // Old ICU versions don't have this constant, so we are basically stuck (see https://github.com/guzzle/guzzle/pull/2424
+ // and https://github.com/guzzle/guzzle/issues/2448 for details)
+ && (
+ defined('INTL_IDNA_VARIANT_UTS46')
+ ||
+ PHP_VERSION_ID < 70200
+ );
+
// Use the standard Linux HTTP_PROXY and HTTPS_PROXY if set.
// 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')) {
+ if (php_sapi_name() === 'cli' && getenv('HTTP_PROXY')) {
$defaults['proxy']['http'] = getenv('HTTP_PROXY');
}
@@ -210,7 +294,7 @@ class Client implements ClientInterface
*
* @return array
*/
- private function prepareDefaults($options)
+ private function prepareDefaults(array $options)
{
$defaults = $this->config;
@@ -225,7 +309,7 @@ class Client implements ClientInterface
if (array_key_exists('headers', $options)) {
// Allows default headers to be unset.
if ($options['headers'] === null) {
- $defaults['_conditional'] = null;
+ $defaults['_conditional'] = [];
unset($options['headers']);
} elseif (!is_array($options['headers'])) {
throw new \InvalidArgumentException('headers must be an array');
@@ -251,8 +335,7 @@ class Client implements ClientInterface
* The URI of the request is not modified and the request options are used
* as-is without merging in default options.
*
- * @param RequestInterface $request
- * @param array $options
+ * @param array $options See \GuzzleHttp\RequestOptions.
*
* @return Promise\PromiseInterface
*/
@@ -271,6 +354,7 @@ class Client implements ClientInterface
}
$request = $this->applyOptions($request, $options);
+ /** @var HandlerStack $handler */
$handler = $options['handler'];
try {
@@ -411,6 +495,11 @@ class Client implements ClientInterface
return $request;
}
+ /**
+ * Throw Exception with pre-set message.
+ * @return void
+ * @throws InvalidArgumentException Invalid body.
+ */
private function invalidBody()
{
throw new \InvalidArgumentException('Passing in the "body" request '
diff --git a/guzzlehttp/guzzle/src/ClientInterface.php b/guzzlehttp/guzzle/src/ClientInterface.php
index 2dbcffa4..0c8d42a1 100644
--- a/guzzlehttp/guzzle/src/ClientInterface.php
+++ b/guzzlehttp/guzzle/src/ClientInterface.php
@@ -1,8 +1,8 @@
<?php
namespace GuzzleHttp;
-use GuzzleHttp\Promise\PromiseInterface;
use GuzzleHttp\Exception\GuzzleException;
+use GuzzleHttp\Promise\PromiseInterface;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\UriInterface;
@@ -12,7 +12,10 @@ use Psr\Http\Message\UriInterface;
*/
interface ClientInterface
{
- const VERSION = '6.3.3';
+ /**
+ * @deprecated Will be removed in Guzzle 7.0.0
+ */
+ const VERSION = '6.5.1';
/**
* Send an HTTP request.
diff --git a/guzzlehttp/guzzle/src/Cookie/CookieJar.php b/guzzlehttp/guzzle/src/Cookie/CookieJar.php
index 78f2b79f..38f98ad7 100644
--- a/guzzlehttp/guzzle/src/Cookie/CookieJar.php
+++ b/guzzlehttp/guzzle/src/Cookie/CookieJar.php
@@ -94,8 +94,8 @@ class CookieJar implements CookieJarInterface
*/
public function getCookieByName($name)
{
- // don't allow a null name
- if ($name === null) {
+ // don't allow a non string name
+ if ($name === null || !is_scalar($name)) {
return null;
}
foreach ($this->cookies as $cookie) {
@@ -103,6 +103,8 @@ class CookieJar implements CookieJarInterface
return $cookie;
}
}
+
+ return null;
}
public function toArray()
@@ -120,7 +122,7 @@ class CookieJar implements CookieJarInterface
} elseif (!$path) {
$this->cookies = array_filter(
$this->cookies,
- function (SetCookie $cookie) use ($path, $domain) {
+ function (SetCookie $cookie) use ($domain) {
return !$cookie->matchesDomain($domain);
}
);
diff --git a/guzzlehttp/guzzle/src/Cookie/CookieJarInterface.php b/guzzlehttp/guzzle/src/Cookie/CookieJarInterface.php
index 2cf298a8..6ee11885 100644
--- a/guzzlehttp/guzzle/src/Cookie/CookieJarInterface.php
+++ b/guzzlehttp/guzzle/src/Cookie/CookieJarInterface.php
@@ -58,9 +58,9 @@ interface CookieJarInterface extends \Countable, \IteratorAggregate
* arguments, then the cookie with the specified name, path and domain is
* removed.
*
- * @param string $domain Clears cookies matching a domain
- * @param string $path Clears cookies matching a domain and path
- * @param string $name Clears cookies matching a domain, path, and name
+ * @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
*/
diff --git a/guzzlehttp/guzzle/src/Cookie/FileCookieJar.php b/guzzlehttp/guzzle/src/Cookie/FileCookieJar.php
index 9887c1d5..3fb8600e 100644
--- a/guzzlehttp/guzzle/src/Cookie/FileCookieJar.php
+++ b/guzzlehttp/guzzle/src/Cookie/FileCookieJar.php
@@ -23,6 +23,7 @@ class FileCookieJar extends CookieJar
*/
public function __construct($cookieFile, $storeSessionCookies = false)
{
+ parent::__construct();
$this->filename = $cookieFile;
$this->storeSessionCookies = $storeSessionCookies;
@@ -56,7 +57,7 @@ class FileCookieJar extends CookieJar
}
$jsonStr = \GuzzleHttp\json_encode($json);
- if (false === file_put_contents($filename, $jsonStr)) {
+ if (false === file_put_contents($filename, $jsonStr, LOCK_EX)) {
throw new \RuntimeException("Unable to save file {$filename}");
}
}
diff --git a/guzzlehttp/guzzle/src/Cookie/SessionCookieJar.php b/guzzlehttp/guzzle/src/Cookie/SessionCookieJar.php
index 4497bcf0..0224a244 100644
--- a/guzzlehttp/guzzle/src/Cookie/SessionCookieJar.php
+++ b/guzzlehttp/guzzle/src/Cookie/SessionCookieJar.php
@@ -22,6 +22,7 @@ class SessionCookieJar extends CookieJar
*/
public function __construct($sessionKey, $storeSessionCookies = false)
{
+ parent::__construct();
$this->sessionKey = $sessionKey;
$this->storeSessionCookies = $storeSessionCookies;
$this->load();
diff --git a/guzzlehttp/guzzle/src/Cookie/SetCookie.php b/guzzlehttp/guzzle/src/Cookie/SetCookie.php
index f6993943..3d776a70 100644
--- a/guzzlehttp/guzzle/src/Cookie/SetCookie.php
+++ b/guzzlehttp/guzzle/src/Cookie/SetCookie.php
@@ -227,7 +227,7 @@ class SetCookie
/**
* Get whether or not this is a secure cookie
*
- * @return null|bool
+ * @return bool|null
*/
public function getSecure()
{
@@ -247,7 +247,7 @@ class SetCookie
/**
* Get whether or not this is a session cookie
*
- * @return null|bool
+ * @return bool|null
*/
public function getDiscard()
{
diff --git a/guzzlehttp/guzzle/src/Exception/ClientException.php b/guzzlehttp/guzzle/src/Exception/ClientException.php
index f95c09f2..4cfd393c 100644
--- a/guzzlehttp/guzzle/src/Exception/ClientException.php
+++ b/guzzlehttp/guzzle/src/Exception/ClientException.php
@@ -4,4 +4,6 @@ namespace GuzzleHttp\Exception;
/**
* Exception when a client error is encountered (4xx codes)
*/
-class ClientException extends BadResponseException {}
+class ClientException extends BadResponseException
+{
+}
diff --git a/guzzlehttp/guzzle/src/Exception/GuzzleException.php b/guzzlehttp/guzzle/src/Exception/GuzzleException.php
index 510778f6..27b2722b 100644
--- a/guzzlehttp/guzzle/src/Exception/GuzzleException.php
+++ b/guzzlehttp/guzzle/src/Exception/GuzzleException.php
@@ -1,13 +1,23 @@
<?php
namespace GuzzleHttp\Exception;
-/**
- * @method string getMessage()
- * @method \Throwable|null getPrevious()
- * @method mixed getCode()
- * @method string getFile()
- * @method int getLine()
- * @method array getTrace()
- * @method string getTraceAsString()
- */
-interface GuzzleException {}
+use Throwable;
+
+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
+ {
+ }
+}
diff --git a/guzzlehttp/guzzle/src/Exception/RequestException.php b/guzzlehttp/guzzle/src/Exception/RequestException.php
index 39de327e..12dd081e 100644
--- a/guzzlehttp/guzzle/src/Exception/RequestException.php
+++ b/guzzlehttp/guzzle/src/Exception/RequestException.php
@@ -1,9 +1,9 @@
<?php
namespace GuzzleHttp\Exception;
+use GuzzleHttp\Promise\PromiseInterface;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
-use GuzzleHttp\Promise\PromiseInterface;
use Psr\Http\Message\UriInterface;
/**
@@ -14,7 +14,7 @@ class RequestException extends TransferException
/** @var RequestInterface */
private $request;
- /** @var ResponseInterface */
+ /** @var ResponseInterface|null */
private $response;
/** @var array */
@@ -124,42 +124,17 @@ class RequestException extends TransferException
*/
public static function getResponseBodySummary(ResponseInterface $response)
{
- $body = $response->getBody();
-
- if (!$body->isSeekable()) {
- return null;
- }
-
- $size = $body->getSize();
-
- if ($size === 0) {
- return null;
- }
-
- $summary = $body->read(120);
- $body->rewind();
-
- if ($size > 120) {
- $summary .= ' (truncated...)';
- }
-
- // Matches any printable character, including unicode characters:
- // letters, marks, numbers, punctuation, spacing, and separators.
- if (preg_match('/[^\pL\pM\pN\pP\pS\pZ\n\r\t]/', $summary)) {
- return null;
- }
-
- return $summary;
+ return \GuzzleHttp\Psr7\get_message_body_summary($response);
}
/**
- * Obfuscates URI if there is an username and a password present
+ * Obfuscates URI if there is a username and a password present
*
* @param UriInterface $uri
*
* @return UriInterface
*/
- private static function obfuscateUri($uri)
+ private static function obfuscateUri(UriInterface $uri)
{
$userInfo = $uri->getUserInfo();
diff --git a/guzzlehttp/guzzle/src/Exception/ServerException.php b/guzzlehttp/guzzle/src/Exception/ServerException.php
index 7cdd3408..127094c1 100644
--- a/guzzlehttp/guzzle/src/Exception/ServerException.php
+++ b/guzzlehttp/guzzle/src/Exception/ServerException.php
@@ -4,4 +4,6 @@ namespace GuzzleHttp\Exception;
/**
* Exception when a server error is encountered (5xx codes)
*/
-class ServerException extends BadResponseException {}
+class ServerException extends BadResponseException
+{
+}
diff --git a/guzzlehttp/guzzle/src/Exception/TooManyRedirectsException.php b/guzzlehttp/guzzle/src/Exception/TooManyRedirectsException.php
index b60a9678..fff05251 100644
--- a/guzzlehttp/guzzle/src/Exception/TooManyRedirectsException.php
+++ b/guzzlehttp/guzzle/src/Exception/TooManyRedirectsException.php
@@ -1,4 +1,6 @@
<?php
namespace GuzzleHttp\Exception;
-class TooManyRedirectsException extends RequestException {}
+class TooManyRedirectsException extends RequestException
+{
+}
diff --git a/guzzlehttp/guzzle/src/Exception/TransferException.php b/guzzlehttp/guzzle/src/Exception/TransferException.php
index b92071ca..7c11db3a 100644
--- a/guzzlehttp/guzzle/src/Exception/TransferException.php
+++ b/guzzlehttp/guzzle/src/Exception/TransferException.php
@@ -1,4 +1,6 @@
<?php
namespace GuzzleHttp\Exception;
-class TransferException extends \RuntimeException implements GuzzleException {}
+class TransferException extends \RuntimeException implements GuzzleException
+{
+}
diff --git a/guzzlehttp/guzzle/src/Handler/CurlFactory.php b/guzzlehttp/guzzle/src/Handler/CurlFactory.php
index e0923714..4a28a96e 100644
--- a/guzzlehttp/guzzle/src/Handler/CurlFactory.php
+++ b/guzzlehttp/guzzle/src/Handler/CurlFactory.php
@@ -1,8 +1,8 @@
<?php
namespace GuzzleHttp\Handler;
-use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Exception\ConnectException;
+use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Promise\FulfilledPromise;
use GuzzleHttp\Psr7;
use GuzzleHttp\Psr7\LazyOpenStream;
@@ -14,6 +14,9 @@ use Psr\Http\Message\RequestInterface;
*/
class CurlFactory implements CurlFactoryInterface
{
+ const CURL_VERSION_STR = 'curl_version';
+ const LOW_CURL_VERSION_NUMBER = '7.21.2';
+
/** @var array */
private $handles = [];
@@ -117,6 +120,7 @@ class CurlFactory implements CurlFactoryInterface
private static function invokeStats(EasyHandle $easy)
{
$curlStats = curl_getinfo($easy->handle);
+ $curlStats['appconnect_time'] = curl_getinfo($easy->handle, CURLINFO_APPCONNECT_TIME);
$stats = new TransferStats(
$easy->request,
$easy->response,
@@ -136,7 +140,9 @@ class CurlFactory implements CurlFactoryInterface
$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'];
$factory->release($easy);
// Retry when nothing is present or when curl failed to rewind.
@@ -172,13 +178,22 @@ class CurlFactory implements CurlFactoryInterface
)
);
}
-
- $message = sprintf(
- 'cURL error %s: %s (%s)',
- $ctx['errno'],
- $ctx['error'],
- 'see http://curl.haxx.se/libcurl/c/libcurl-errors.html'
- );
+ 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()
+ );
+ }
// Create a connection exception if it was a specific error code.
$error = isset($connectionErrors[$easy->errno])
@@ -439,11 +454,16 @@ class CurlFactory implements CurlFactoryInterface
}
if (isset($options['ssl_key'])) {
- $sslKey = $options['ssl_key'];
- if (is_array($sslKey)) {
- $conf[CURLOPT_SSLKEYPASSWD] = $sslKey[1];
- $sslKey = $sslKey[0];
+ if (is_array($options['ssl_key'])) {
+ if (count($options['ssl_key']) === 2) {
+ list($sslKey, $conf[CURLOPT_SSLKEYPASSWD]) = $options['ssl_key'];
+ } else {
+ list($sslKey) = $options['ssl_key'];
+ }
}
+
+ $sslKey = isset($sslKey) ? $sslKey: $options['ssl_key'];
+
if (!file_exists($sslKey)) {
throw new \InvalidArgumentException(
"SSL private key not found: {$sslKey}"
diff --git a/guzzlehttp/guzzle/src/Handler/CurlMultiHandler.php b/guzzlehttp/guzzle/src/Handler/CurlMultiHandler.php
index 2754d8e4..b73e5c72 100644
--- a/guzzlehttp/guzzle/src/Handler/CurlMultiHandler.php
+++ b/guzzlehttp/guzzle/src/Handler/CurlMultiHandler.php
@@ -1,9 +1,9 @@
<?php
namespace GuzzleHttp\Handler;
+use GuzzleHttp\Exception\InvalidArgumentException;
use GuzzleHttp\Promise as P;
use GuzzleHttp\Promise\Promise;
-use GuzzleHttp\Psr7;
use Psr\Http\Message\RequestInterface;
/**
@@ -23,6 +23,7 @@ class CurlMultiHandler
private $active;
private $handles = [];
private $delays = [];
+ private $options = [];
/**
* This handler accepts the following options:
@@ -30,6 +31,8 @@ class CurlMultiHandler
* - handle_factory: An optional factory used to create curl handles
* - select_timeout: Optional timeout (in seconds) to block before timing
* 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
*/
@@ -37,14 +40,31 @@ class CurlMultiHandler
{
$this->factory = isset($options['handle_factory'])
? $options['handle_factory'] : new CurlFactory(50);
- $this->selectTimeout = isset($options['select_timeout'])
- ? $options['select_timeout'] : 1;
+
+ if (isset($options['select_timeout'])) {
+ $this->selectTimeout = $options['select_timeout'];
+ } elseif ($selectTimeout = getenv('GUZZLE_CURL_SELECT_TIMEOUT')) {
+ $this->selectTimeout = $selectTimeout;
+ } else {
+ $this->selectTimeout = 1;
+ }
+
+ $this->options = isset($options['options']) ? $options['options'] : [];
}
public function __get($name)
{
if ($name === '_mh') {
- return $this->_mh = curl_multi_init();
+ $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;
}
throw new \BadMethodCallException();
@@ -82,7 +102,7 @@ class CurlMultiHandler
{
// Add any delayed handles if needed.
if ($this->delays) {
- $currentTime = microtime(true);
+ $currentTime = \GuzzleHttp\_current_time();
foreach ($this->delays as $id => $delay) {
if ($currentTime >= $delay) {
unset($this->delays[$id]);
@@ -134,7 +154,7 @@ class CurlMultiHandler
if (empty($easy->options['delay'])) {
curl_multi_add_handle($this->_mh, $easy->handle);
} else {
- $this->delays[$id] = microtime(true) + ($easy->options['delay'] / 1000);
+ $this->delays[$id] = \GuzzleHttp\_current_time() + ($easy->options['delay'] / 1000);
}
}
@@ -186,7 +206,7 @@ class CurlMultiHandler
private function timeToNext()
{
- $currentTime = microtime(true);
+ $currentTime = \GuzzleHttp\_current_time();
$nextTime = PHP_INT_MAX;
foreach ($this->delays as $time) {
if ($time < $nextTime) {
diff --git a/guzzlehttp/guzzle/src/Handler/MockHandler.php b/guzzlehttp/guzzle/src/Handler/MockHandler.php
index d892061c..5b312bc0 100644
--- a/guzzlehttp/guzzle/src/Handler/MockHandler.php
+++ b/guzzlehttp/guzzle/src/Handler/MockHandler.php
@@ -66,7 +66,7 @@ class MockHandler implements \Countable
throw new \OutOfBoundsException('Mock queue is empty');
}
- if (isset($options['delay'])) {
+ if (isset($options['delay']) && is_numeric($options['delay'])) {
usleep($options['delay'] * 1000);
}
@@ -175,6 +175,11 @@ class MockHandler implements \Countable
return count($this->queue);
}
+ public function reset()
+ {
+ $this->queue = [];
+ }
+
private function invokeStats(
RequestInterface $request,
array $options,
@@ -182,7 +187,8 @@ class MockHandler implements \Countable
$reason = null
) {
if (isset($options['on_stats'])) {
- $stats = new TransferStats($request, $response, 0, $reason);
+ $transferTime = isset($options['transfer_time']) ? $options['transfer_time'] : 0;
+ $stats = new TransferStats($request, $response, $transferTime, $reason);
call_user_func($options['on_stats'], $stats);
}
}
diff --git a/guzzlehttp/guzzle/src/Handler/StreamHandler.php b/guzzlehttp/guzzle/src/Handler/StreamHandler.php
index b686545e..a8eba378 100644
--- a/guzzlehttp/guzzle/src/Handler/StreamHandler.php
+++ b/guzzlehttp/guzzle/src/Handler/StreamHandler.php
@@ -1,8 +1,8 @@
<?php
namespace GuzzleHttp\Handler;
-use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Exception\ConnectException;
+use GuzzleHttp\Exception\RequestException;
use GuzzleHttp\Promise\FulfilledPromise;
use GuzzleHttp\Promise\PromiseInterface;
use GuzzleHttp\Psr7;
@@ -33,7 +33,7 @@ class StreamHandler
usleep($options['delay'] * 1000);
}
- $startTime = isset($options['on_stats']) ? microtime(true) : null;
+ $startTime = isset($options['on_stats']) ? \GuzzleHttp\_current_time() : null;
try {
// Does not support the expect header.
@@ -42,7 +42,7 @@ class StreamHandler
// Append a content-length header if body size is zero to match
// cURL's behavior.
if (0 === $request->getBody()->getSize()) {
- $request = $request->withHeader('Content-Length', 0);
+ $request = $request->withHeader('Content-Length', '0');
}
return $this->createResponse(
@@ -82,7 +82,7 @@ class StreamHandler
$stats = new TransferStats(
$request,
$response,
- microtime(true) - $startTime,
+ \GuzzleHttp\_current_time() - $startTime,
$error,
[]
);
@@ -343,13 +343,25 @@ class StreamHandler
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);
+ 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);
+ throw new ConnectException(
+ sprintf(
+ "Could not resolve IPv6 address for host '%s'",
+ $uri->getHost()
+ ),
+ $request
+ );
}
$uri = $uri->withHost('[' . $records[0]['ipv6'] . ']');
}
diff --git a/guzzlehttp/guzzle/src/HandlerStack.php b/guzzlehttp/guzzle/src/HandlerStack.php
index 24c46fd9..6a49cc06 100644
--- a/guzzlehttp/guzzle/src/HandlerStack.php
+++ b/guzzlehttp/guzzle/src/HandlerStack.php
@@ -1,7 +1,9 @@
<?php
namespace GuzzleHttp;
+use GuzzleHttp\Promise\PromiseInterface;
use Psr\Http\Message\RequestInterface;
+use Psr\Http\Message\ResponseInterface;
/**
* Creates a composed Guzzle handler function by stacking middlewares on top of
@@ -9,7 +11,7 @@ use Psr\Http\Message\RequestInterface;
*/
class HandlerStack
{
- /** @var callable */
+ /** @var callable|null */
private $handler;
/** @var array */
@@ -59,6 +61,8 @@ class HandlerStack
*
* @param RequestInterface $request
* @param array $options
+ *
+ * @return ResponseInterface|PromiseInterface
*/
public function __invoke(RequestInterface $request, array $options)
{
@@ -206,7 +210,7 @@ class HandlerStack
}
/**
- * @param $name
+ * @param string $name
* @return int
*/
private function findByName($name)
@@ -223,10 +227,10 @@ class HandlerStack
/**
* Splices a function into the middleware list at a specific position.
*
- * @param $findName
- * @param $withName
+ * @param string $findName
+ * @param string $withName
* @param callable $middleware
- * @param $before
+ * @param bool $before
*/
private function splice($findName, $withName, callable $middleware, $before)
{
diff --git a/guzzlehttp/guzzle/src/MessageFormatter.php b/guzzlehttp/guzzle/src/MessageFormatter.php
index 663ac739..dc36bb52 100644
--- a/guzzlehttp/guzzle/src/MessageFormatter.php
+++ b/guzzlehttp/guzzle/src/MessageFormatter.php
@@ -168,6 +168,11 @@ class MessageFormatter
);
}
+ /**
+ * Get headers from message as string
+ *
+ * @return string
+ */
private function headers(MessageInterface $message)
{
$result = '';
diff --git a/guzzlehttp/guzzle/src/Middleware.php b/guzzlehttp/guzzle/src/Middleware.php
index d4ad75c9..bffc1974 100644
--- a/guzzlehttp/guzzle/src/Middleware.php
+++ b/guzzlehttp/guzzle/src/Middleware.php
@@ -7,7 +7,6 @@ use GuzzleHttp\Promise\RejectedPromise;
use GuzzleHttp\Psr7;
use Psr\Http\Message\ResponseInterface;
use Psr\Log\LoggerInterface;
-use Psr\Log\LogLevel;
/**
* Functions used to create and wrap handlers with handler middleware.
@@ -39,7 +38,7 @@ final class Middleware
$cookieJar->extractCookies($request, $response);
return $response;
}
- );
+ );
};
};
}
@@ -58,7 +57,7 @@ final class Middleware
return $handler($request, $options);
}
return $handler($request, $options)->then(
- function (ResponseInterface $response) use ($request, $handler) {
+ function (ResponseInterface $response) use ($request) {
$code = $response->getStatusCode();
if ($code < 400) {
return $response;
@@ -183,7 +182,7 @@ final class Middleware
*
* @return callable Returns a function that accepts the next handler.
*/
- public static function log(LoggerInterface $logger, MessageFormatter $formatter, $logLevel = LogLevel::INFO)
+ public static function log(LoggerInterface $logger, MessageFormatter $formatter, $logLevel = 'info' /* \Psr\Log\LogLevel::INFO */)
{
return function (callable $handler) use ($logger, $formatter, $logLevel) {
return function ($request, array $options) use ($handler, $logger, $formatter, $logLevel) {
diff --git a/guzzlehttp/guzzle/src/Pool.php b/guzzlehttp/guzzle/src/Pool.php
index 8f1be33c..5838db4f 100644
--- a/guzzlehttp/guzzle/src/Pool.php
+++ b/guzzlehttp/guzzle/src/Pool.php
@@ -1,12 +1,13 @@
<?php
namespace GuzzleHttp;
+use GuzzleHttp\Promise\EachPromise;
+use GuzzleHttp\Promise\PromiseInterface;
use GuzzleHttp\Promise\PromisorInterface;
use Psr\Http\Message\RequestInterface;
-use GuzzleHttp\Promise\EachPromise;
/**
- * Sends and iterator of requests concurrently using a capped pool size.
+ * Sends an iterator of requests concurrently using a capped pool size.
*
* The pool will read from an iterator until it is cancelled or until the
* iterator is consumed. When a request is yielded, the request is sent after
@@ -69,6 +70,11 @@ class Pool implements PromisorInterface
$this->each = new EachPromise($requests(), $config);
}
+ /**
+ * Get promise
+ *
+ * @return PromiseInterface
+ */
public function promise()
{
return $this->each->promise();
@@ -106,6 +112,11 @@ class Pool implements PromisorInterface
return $res;
}
+ /**
+ * Execute callback(s)
+ *
+ * @return void
+ */
private static function cmpCallback(array &$options, $name, array &$results)
{
if (!isset($options[$name])) {
diff --git a/guzzlehttp/guzzle/src/PrepareBodyMiddleware.php b/guzzlehttp/guzzle/src/PrepareBodyMiddleware.php
index 2eb95f9b..568a1e90 100644
--- a/guzzlehttp/guzzle/src/PrepareBodyMiddleware.php
+++ b/guzzlehttp/guzzle/src/PrepareBodyMiddleware.php
@@ -66,6 +66,11 @@ class PrepareBodyMiddleware
return $fn(Psr7\modify_request($request, $modify), $options);
}
+ /**
+ * Add expect header
+ *
+ * @return void
+ */
private function addExpectHeader(
RequestInterface $request,
array $options,
diff --git a/guzzlehttp/guzzle/src/RedirectMiddleware.php b/guzzlehttp/guzzle/src/RedirectMiddleware.php
index 131b7717..2f301261 100644
--- a/guzzlehttp/guzzle/src/RedirectMiddleware.php
+++ b/guzzlehttp/guzzle/src/RedirectMiddleware.php
@@ -13,7 +13,7 @@ use Psr\Http\Message\UriInterface;
* Request redirect middleware.
*
* Apply this middleware like other middleware using
- * {@see GuzzleHttp\Middleware::redirect()}.
+ * {@see \GuzzleHttp\Middleware::redirect()}.
*/
class RedirectMiddleware
{
@@ -76,7 +76,7 @@ class RedirectMiddleware
/**
* @param RequestInterface $request
* @param array $options
- * @param ResponseInterface|PromiseInterface $response
+ * @param ResponseInterface $response
*
* @return ResponseInterface|PromiseInterface
*/
@@ -118,6 +118,11 @@ class RedirectMiddleware
return $promise;
}
+ /**
+ * Enable tracking on promise.
+ *
+ * @return PromiseInterface
+ */
private function withTracking(PromiseInterface $promise, $uri, $statusCode)
{
return $promise->then(
@@ -135,6 +140,13 @@ class RedirectMiddleware
);
}
+ /**
+ * Check for too many redirects
+ *
+ * @return void
+ *
+ * @throws TooManyRedirectsException Too many redirects.
+ */
private function guardMax(RequestInterface $request, array &$options)
{
$current = isset($options['__redirect_count'])
@@ -172,13 +184,19 @@ class RedirectMiddleware
// would do.
$statusCode = $response->getStatusCode();
if ($statusCode == 303 ||
- ($statusCode <= 302 && $request->getBody() && !$options['allow_redirects']['strict'])
+ ($statusCode <= 302 && !$options['allow_redirects']['strict'])
) {
$modify['method'] = 'GET';
$modify['body'] = '';
}
- $modify['uri'] = $this->redirectUri($request, $response, $protocols);
+ $uri = $this->redirectUri($request, $response, $protocols);
+ if (isset($options['idn_conversion']) && ($options['idn_conversion'] !== false)) {
+ $idnOptions = ($options['idn_conversion'] === true) ? IDNA_DEFAULT : $options['idn_conversion'];
+ $uri = _idn_uri_convert($uri, $idnOptions);
+ }
+
+ $modify['uri'] = $uri;
Psr7\rewind_body($request);
// Add the Referer header if it is told to do so and only
@@ -186,7 +204,7 @@ class RedirectMiddleware
if ($options['allow_redirects']['referer']
&& $modify['uri']->getScheme() === $request->getUri()->getScheme()
) {
- $uri = $request->getUri()->withUserInfo('', '');
+ $uri = $request->getUri()->withUserInfo('');
$modify['set_headers']['Referer'] = (string) $uri;
} else {
$modify['remove_headers'][] = 'Referer';
diff --git a/guzzlehttp/guzzle/src/RequestOptions.php b/guzzlehttp/guzzle/src/RequestOptions.php
index c6aacfb1..355f658f 100644
--- a/guzzlehttp/guzzle/src/RequestOptions.php
+++ b/guzzlehttp/guzzle/src/RequestOptions.php
@@ -22,7 +22,7 @@ final class RequestOptions
* - strict: (bool, default=false) Set to true to use strict redirects
* meaning redirect POST requests with POST requests vs. doing what most
* browsers do which is redirect POST requests with GET requests
- * - referer: (bool, default=true) Set to false to disable the Referer
+ * - referer: (bool, default=false) Set to true to enable the Referer
* header.
* - protocols: (array, default=['http', 'https']) Allowed redirect
* protocols.
@@ -133,6 +133,14 @@ final class RequestOptions
const HTTP_ERRORS = 'http_errors';
/**
+ * idn: (bool|int, default=true) A combination of IDNA_* constants for
+ * idn_to_ascii() PHP's function (see "options" parameter). Set to false to
+ * disable IDN support completely, or to true to use the default
+ * configuration (IDNA_DEFAULT constant).
+ */
+ 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.
diff --git a/guzzlehttp/guzzle/src/RetryMiddleware.php b/guzzlehttp/guzzle/src/RetryMiddleware.php
index f27090fd..5acc8c5c 100644
--- a/guzzlehttp/guzzle/src/RetryMiddleware.php
+++ b/guzzlehttp/guzzle/src/RetryMiddleware.php
@@ -19,6 +19,9 @@ class RetryMiddleware
/** @var callable */
private $decider;
+ /** @var callable */
+ private $delay;
+
/**
* @param callable $decider Function that accepts the number of retries,
* a request, [response], and [exception] and
@@ -42,13 +45,13 @@ class RetryMiddleware
/**
* Default exponential backoff delay function.
*
- * @param $retries
+ * @param int $retries
*
- * @return int
+ * @return int milliseconds.
*/
public static function exponentialDelay($retries)
{
- return (int) pow(2, $retries - 1);
+ return (int) pow(2, $retries - 1) * 1000;
}
/**
@@ -71,6 +74,11 @@ class RetryMiddleware
);
}
+ /**
+ * Execute fulfilled closure
+ *
+ * @return mixed
+ */
private function onFulfilled(RequestInterface $req, array $options)
{
return function ($value) use ($req, $options) {
@@ -87,6 +95,11 @@ class RetryMiddleware
};
}
+ /**
+ * Execute rejected closure
+ *
+ * @return callable
+ */
private function onRejected(RequestInterface $req, array $options)
{
return function ($reason) use ($req, $options) {
@@ -103,6 +116,9 @@ class RetryMiddleware
};
}
+ /**
+ * @return self
+ */
private function doRetry(RequestInterface $request, array $options, ResponseInterface $response = null)
{
$options['delay'] = call_user_func($this->delay, ++$options['retries'], $response);
diff --git a/guzzlehttp/guzzle/src/TransferStats.php b/guzzlehttp/guzzle/src/TransferStats.php
index 15f717e1..87fb3c00 100644
--- a/guzzlehttp/guzzle/src/TransferStats.php
+++ b/guzzlehttp/guzzle/src/TransferStats.php
@@ -18,11 +18,11 @@ final class TransferStats
private $handlerErrorData;
/**
- * @param RequestInterface $request Request that was sent.
- * @param ResponseInterface $response Response received (if any)
- * @param null $transferTime Total handler transfer time.
- * @param mixed $handlerErrorData Handler error data.
- * @param array $handlerStats Handler specific stats.
+ * @param RequestInterface $request Request that was sent.
+ * @param ResponseInterface|null $response Response received (if any)
+ * @param float|null $transferTime Total handler transfer time.
+ * @param mixed $handlerErrorData Handler error data.
+ * @param array $handlerStats Handler specific stats.
*/
public function __construct(
RequestInterface $request,
@@ -93,7 +93,7 @@ final class TransferStats
/**
* Get the estimated time the request was being transferred by the handler.
*
- * @return float Time in seconds.
+ * @return float|null Time in seconds.
*/
public function getTransferTime()
{
diff --git a/guzzlehttp/guzzle/src/functions.php b/guzzlehttp/guzzle/src/functions.php
index a3ac450d..5e806f63 100644
--- a/guzzlehttp/guzzle/src/functions.php
+++ b/guzzlehttp/guzzle/src/functions.php
@@ -1,10 +1,12 @@
<?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;
/**
* Expands a URI template
@@ -56,7 +58,7 @@ function describe_type($input)
/**
* Parses an array of header lines into an associative array of headers.
*
- * @param array $lines Header lines array of strings in the following
+ * @param iterable $lines Header lines array of strings in the following
* format: "Name: Value"
* @return array
*/
@@ -196,7 +198,8 @@ function default_ca_bundle()
}
}
- throw new \RuntimeException(<<< EOT
+ 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
@@ -294,14 +297,14 @@ function is_host_in_noproxy($host, array $noProxyArray)
* @param int $options Bitmask of JSON decode options.
*
* @return mixed
- * @throws \InvalidArgumentException if the JSON cannot be decoded.
+ * @throws Exception\InvalidArgumentException if the JSON cannot be decoded.
* @link http://www.php.net/manual/en/function.json-decode.php
*/
function json_decode($json, $assoc = false, $depth = 512, $options = 0)
{
$data = \json_decode($json, $assoc, $depth, $options);
if (JSON_ERROR_NONE !== json_last_error()) {
- throw new \InvalidArgumentException(
+ throw new Exception\InvalidArgumentException(
'json_decode error: ' . json_last_error_msg()
);
}
@@ -317,17 +320,75 @@ function json_decode($json, $assoc = false, $depth = 512, $options = 0)
* @param int $depth Set the maximum depth. Must be greater than zero.
*
* @return string
- * @throws \InvalidArgumentException if the JSON cannot be encoded.
+ * @throws Exception\InvalidArgumentException if the JSON cannot be encoded.
* @link http://www.php.net/manual/en/function.json-encode.php
*/
function json_encode($value, $options = 0, $depth = 512)
{
$json = \json_encode($value, $options, $depth);
if (JSON_ERROR_NONE !== json_last_error()) {
- throw new \InvalidArgumentException(
+ throw new Exception\InvalidArgumentException(
'json_encode error: ' . json_last_error_msg()
);
}
return $json;
}
+
+/**
+ * Wrapper for the hrtime() or microtime() functions
+ * (depending on the PHP version, one of the two is used)
+ *
+ * @return float|mixed UNIX timestamp
+ * @internal
+ */
+function _current_time()
+{
+ return function_exists('hrtime') ? hrtime(true) / 1e9 : microtime(true);
+}
+
+
+/**
+ * @param int $options
+ *
+ * @return UriInterface
+ *
+ * @internal
+ */
+function _idn_uri_convert(UriInterface $uri, $options = 0)
+{
+ if ($uri->getHost()) {
+ $idnaVariant = defined('INTL_IDNA_VARIANT_UTS46') ? INTL_IDNA_VARIANT_UTS46 : 0;
+ $asciiHost = $idnaVariant === 0
+ ? idn_to_ascii($uri->getHost(), $options)
+ : idn_to_ascii($uri->getHost(), $options, $idnaVariant, $info);
+ if ($asciiHost === false) {
+ $errorBitSet = isset($info['errors']) ? $info['errors'] : 0;
+
+ $errorConstants = array_filter(array_keys(get_defined_constants()), function ($name) {
+ return substr($name, 0, 11) === 'IDNA_ERROR_';
+ });
+
+ $errors = [];
+ foreach ($errorConstants as $errorConstant) {
+ if ($errorBitSet & constant($errorConstant)) {
+ $errors[] = $errorConstant;
+ }
+ }
+
+ $errorMessage = 'IDN conversion failed';
+ if ($errors) {
+ $errorMessage .= ' (errors: ' . implode(', ', $errors) . ')';
+ }
+
+ throw new InvalidArgumentException($errorMessage);
+ } else {
+ if ($uri->getHost() !== $asciiHost) {
+ // Replace URI only if the ASCII version is different
+ $uri = $uri->withHost($asciiHost);
+ }
+ }
+ }
+
+ return $uri;
+}
diff --git a/guzzlehttp/psr7/CHANGELOG.md b/guzzlehttp/psr7/CHANGELOG.md
index 27b65f09..8a3743db 100644
--- a/guzzlehttp/psr7/CHANGELOG.md
+++ b/guzzlehttp/psr7/CHANGELOG.md
@@ -10,6 +10,26 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
## [Unreleased]
+## [1.6.0]
+
+### Added
+
+- Allowed version `^3.0` of `ralouphie/getallheaders` dependency (#244)
+- Added MIME type for WEBP image format (#246)
+- Added more validation of values according to PSR-7 and RFC standards, e.g. status code range (#250, #272)
+
+### Changed
+
+- Tests don't pass with HHVM 4.0, so HHVM support got dropped. Other libraries like composer have done the same. (#262)
+- Accept port number 0 to be valid (#270)
+
+### Fixed
+
+- Fixed subsequent reads from `php://input` in ServerRequest (#247)
+- Fixed readable/writable detection for certain stream modes (#248)
+- Fixed encoding of special characters in the `userInfo` component of an URI (#253)
+
+
## [1.5.2] - 2018-12-04
### Fixed
@@ -209,7 +229,8 @@ Currently unsupported:
-[Unreleased]: https://github.com/guzzle/psr7/compare/1.5.2...HEAD
+[Unreleased]: https://github.com/guzzle/psr7/compare/1.6.0...HEAD
+[1.6.0]: https://github.com/guzzle/psr7/compare/1.5.2...1.6.0
[1.5.2]: https://github.com/guzzle/psr7/compare/1.5.1...1.5.2
[1.5.1]: https://github.com/guzzle/psr7/compare/1.5.0...1.5.1
[1.5.0]: https://github.com/guzzle/psr7/compare/1.4.2...1.5.0
diff --git a/guzzlehttp/psr7/composer.json b/guzzlehttp/psr7/composer.json
index 2add153e..168a055b 100644
--- a/guzzlehttp/psr7/composer.json
+++ b/guzzlehttp/psr7/composer.json
@@ -18,14 +18,18 @@
"require": {
"php": ">=5.4.0",
"psr/http-message": "~1.0",
- "ralouphie/getallheaders": "^2.0.5"
+ "ralouphie/getallheaders": "^2.0.5 || ^3.0.0"
},
"require-dev": {
- "phpunit/phpunit": "~4.8.36 || ^5.7.27 || ^6.5.8"
+ "phpunit/phpunit": "~4.8.36 || ^5.7.27 || ^6.5.8",
+ "ext-zlib": "*"
},
"provide": {
"psr/http-message-implementation": "1.0"
},
+ "suggest": {
+ "zendframework/zend-httphandlerrunner": "Emit PSR-7 responses"
+ },
"autoload": {
"psr-4": {
"GuzzleHttp\\Psr7\\": "src/"
@@ -39,7 +43,7 @@
},
"extra": {
"branch-alias": {
- "dev-master": "1.5-dev"
+ "dev-master": "1.6-dev"
}
}
}
diff --git a/guzzlehttp/psr7/src/LimitStream.php b/guzzlehttp/psr7/src/LimitStream.php
index 3c13d4f4..e4f239e3 100644
--- a/guzzlehttp/psr7/src/LimitStream.php
+++ b/guzzlehttp/psr7/src/LimitStream.php
@@ -72,7 +72,7 @@ class LimitStream implements StreamInterface
{
if ($whence !== SEEK_SET || $offset < 0) {
throw new \RuntimeException(sprintf(
- 'Cannot seek to offset % with whence %s',
+ 'Cannot seek to offset %s with whence %s',
$offset,
$whence
));
diff --git a/guzzlehttp/psr7/src/MessageTrait.php b/guzzlehttp/psr7/src/MessageTrait.php
index 1e4da649..a7966d10 100644
--- a/guzzlehttp/psr7/src/MessageTrait.php
+++ b/guzzlehttp/psr7/src/MessageTrait.php
@@ -66,11 +66,8 @@ trait MessageTrait
public function withHeader($header, $value)
{
- if (!is_array($value)) {
- $value = [$value];
- }
-
- $value = $this->trimHeaderValues($value);
+ $this->assertHeader($header);
+ $value = $this->normalizeHeaderValue($value);
$normalized = strtolower($header);
$new = clone $this;
@@ -85,11 +82,8 @@ trait MessageTrait
public function withAddedHeader($header, $value)
{
- if (!is_array($value)) {
- $value = [$value];
- }
-
- $value = $this->trimHeaderValues($value);
+ $this->assertHeader($header);
+ $value = $this->normalizeHeaderValue($value);
$normalized = strtolower($header);
$new = clone $this;
@@ -144,11 +138,13 @@ trait MessageTrait
{
$this->headerNames = $this->headers = [];
foreach ($headers as $header => $value) {
- if (!is_array($value)) {
- $value = [$value];
+ if (is_int($header)) {
+ // Numeric array keys are converted to int by PHP but having a header name '123' is not forbidden by the spec
+ // and also allowed in withHeader(). So we need to cast it to string again for the following assertion to pass.
+ $header = (string) $header;
}
-
- $value = $this->trimHeaderValues($value);
+ $this->assertHeader($header);
+ $value = $this->normalizeHeaderValue($value);
$normalized = strtolower($header);
if (isset($this->headerNames[$normalized])) {
$header = $this->headerNames[$normalized];
@@ -160,6 +156,19 @@ trait MessageTrait
}
}
+ private function normalizeHeaderValue($value)
+ {
+ if (!is_array($value)) {
+ return $this->trimHeaderValues([$value]);
+ }
+
+ if (count($value) === 0) {
+ throw new \InvalidArgumentException('Header value can not be an empty array.');
+ }
+
+ return $this->trimHeaderValues($value);
+ }
+
/**
* Trims whitespace from the header values.
*
@@ -177,7 +186,28 @@ trait MessageTrait
private function trimHeaderValues(array $values)
{
return array_map(function ($value) {
- return trim($value, " \t");
+ if (!is_scalar($value) && null !== $value) {
+ throw new \InvalidArgumentException(sprintf(
+ 'Header value must be scalar or null but %s provided.',
+ is_object($value) ? get_class($value) : gettype($value)
+ ));
+ }
+
+ return trim((string) $value, " \t");
}, $values);
}
+
+ private function assertHeader($header)
+ {
+ if (!is_string($header)) {
+ throw new \InvalidArgumentException(sprintf(
+ 'Header name must be a string but %s provided.',
+ is_object($header) ? get_class($header) : gettype($header)
+ ));
+ }
+
+ if ($header === '') {
+ throw new \InvalidArgumentException('Header name can not be empty.');
+ }
+ }
}
diff --git a/guzzlehttp/psr7/src/Request.php b/guzzlehttp/psr7/src/Request.php
index 00066424..59f337db 100644
--- a/guzzlehttp/psr7/src/Request.php
+++ b/guzzlehttp/psr7/src/Request.php
@@ -36,6 +36,7 @@ class Request implements RequestInterface
$body = null,
$version = '1.1'
) {
+ $this->assertMethod($method);
if (!($uri instanceof UriInterface)) {
$uri = new Uri($uri);
}
@@ -91,6 +92,7 @@ class Request implements RequestInterface
public function withMethod($method)
{
+ $this->assertMethod($method);
$new = clone $this;
$new->method = strtoupper($method);
return $new;
@@ -139,4 +141,11 @@ class Request implements RequestInterface
// See: http://tools.ietf.org/html/rfc7230#section-5.4
$this->headers = [$header => [$host]] + $this->headers;
}
+
+ private function assertMethod($method)
+ {
+ if (!is_string($method) || $method === '') {
+ throw new \InvalidArgumentException('Method must be a non-empty string.');
+ }
+ }
}
diff --git a/guzzlehttp/psr7/src/Response.php b/guzzlehttp/psr7/src/Response.php
index 6e72c06b..e7e04d86 100644
--- a/guzzlehttp/psr7/src/Response.php
+++ b/guzzlehttp/psr7/src/Response.php
@@ -93,11 +93,11 @@ class Response implements ResponseInterface
$version = '1.1',
$reason = null
) {
- if (filter_var($status, FILTER_VALIDATE_INT) === false) {
- throw new \InvalidArgumentException('Status code must be an integer value.');
- }
+ $this->assertStatusCodeIsInteger($status);
+ $status = (int) $status;
+ $this->assertStatusCodeRange($status);
- $this->statusCode = (int) $status;
+ $this->statusCode = $status;
if ($body !== '' && $body !== null) {
$this->stream = stream_for($body);
@@ -125,12 +125,30 @@ class Response implements ResponseInterface
public function withStatus($code, $reasonPhrase = '')
{
+ $this->assertStatusCodeIsInteger($code);
+ $code = (int) $code;
+ $this->assertStatusCodeRange($code);
+
$new = clone $this;
- $new->statusCode = (int) $code;
+ $new->statusCode = $code;
if ($reasonPhrase == '' && isset(self::$phrases[$new->statusCode])) {
$reasonPhrase = self::$phrases[$new->statusCode];
}
$new->reasonPhrase = $reasonPhrase;
return $new;
}
+
+ private function assertStatusCodeIsInteger($statusCode)
+ {
+ if (filter_var($statusCode, FILTER_VALIDATE_INT) === false) {
+ throw new \InvalidArgumentException('Status code must be an integer value.');
+ }
+ }
+
+ private function assertStatusCodeRange($statusCode)
+ {
+ if ($statusCode < 100 || $statusCode >= 600) {
+ throw new \InvalidArgumentException('Status code must be an integer value between 1xx and 5xx.');
+ }
+ }
}
diff --git a/guzzlehttp/psr7/src/ServerRequest.php b/guzzlehttp/psr7/src/ServerRequest.php
index 99f453a5..1a09a6c8 100644
--- a/guzzlehttp/psr7/src/ServerRequest.php
+++ b/guzzlehttp/psr7/src/ServerRequest.php
@@ -168,7 +168,7 @@ class ServerRequest extends Request implements ServerRequestInterface
$method = isset($_SERVER['REQUEST_METHOD']) ? $_SERVER['REQUEST_METHOD'] : 'GET';
$headers = getallheaders();
$uri = self::getUriFromGlobals();
- $body = new LazyOpenStream('php://input', 'r+');
+ $body = new CachingStream(new LazyOpenStream('php://input', 'r+'));
$protocol = isset($_SERVER['SERVER_PROTOCOL']) ? str_replace('HTTP/', '', $_SERVER['SERVER_PROTOCOL']) : '1.1';
$serverRequest = new ServerRequest($method, $uri, $headers, $body, $protocol, $_SERVER);
diff --git a/guzzlehttp/psr7/src/Stream.php b/guzzlehttp/psr7/src/Stream.php
index 111795eb..d9e7409c 100644
--- a/guzzlehttp/psr7/src/Stream.php
+++ b/guzzlehttp/psr7/src/Stream.php
@@ -10,6 +10,17 @@ use Psr\Http\Message\StreamInterface;
*/
class Stream implements StreamInterface
{
+ /**
+ * Resource modes.
+ *
+ * @var string
+ *
+ * @see http://php.net/manual/function.fopen.php
+ * @see http://php.net/manual/en/function.gzopen.php
+ */
+ const READABLE_MODES = '/r|a\+|ab\+|w\+|wb\+|x\+|xb\+|c\+|cb\+/';
+ const WRITABLE_MODES = '/a|w|r\+|rb\+|rw|x|c/';
+
private $stream;
private $size;
private $seekable;
@@ -18,22 +29,6 @@ class Stream implements StreamInterface
private $uri;
private $customMetadata;
- /** @var array Hash of readable and writable stream types */
- private static $readWriteHash = [
- 'read' => [
- 'r' => true, 'w+' => true, 'r+' => true, 'x+' => true, 'c+' => true,
- 'rb' => true, 'w+b' => true, 'r+b' => true, 'x+b' => true,
- 'c+b' => true, 'rt' => true, 'w+t' => true, 'r+t' => true,
- 'x+t' => true, 'c+t' => true, 'a+' => true, 'rb+' => true,
- ],
- 'write' => [
- 'w' => true, 'w+' => true, 'rw' => true, 'r+' => true, 'x+' => true,
- 'c+' => true, 'wb' => true, 'w+b' => true, 'r+b' => true, 'rb+' => true,
- 'x+b' => true, 'c+b' => true, 'w+t' => true, 'r+t' => true,
- 'x+t' => true, 'c+t' => true, 'a' => true, 'a+' => true
- ]
- ];
-
/**
* This constructor accepts an associative array of options.
*
@@ -65,8 +60,8 @@ class Stream implements StreamInterface
$this->stream = $stream;
$meta = stream_get_meta_data($this->stream);
$this->seekable = $meta['seekable'];
- $this->readable = isset(self::$readWriteHash['read'][$meta['mode']]);
- $this->writable = isset(self::$readWriteHash['write'][$meta['mode']]);
+ $this->readable = (bool)preg_match(self::READABLE_MODES, $meta['mode']);
+ $this->writable = (bool)preg_match(self::WRITABLE_MODES, $meta['mode']);
$this->uri = $this->getMetadata('uri');
}
@@ -197,6 +192,8 @@ class Stream implements StreamInterface
public function seek($offset, $whence = SEEK_SET)
{
+ $whence = (int) $whence;
+
if (!isset($this->stream)) {
throw new \RuntimeException('Stream is detached');
}
diff --git a/guzzlehttp/psr7/src/Uri.php b/guzzlehttp/psr7/src/Uri.php
index 36219568..825a25ee 100644
--- a/guzzlehttp/psr7/src/Uri.php
+++ b/guzzlehttp/psr7/src/Uri.php
@@ -437,9 +437,9 @@ class Uri implements UriInterface
public function withUserInfo($user, $password = null)
{
- $info = $user;
- if ($password != '') {
- $info .= ':' . $password;
+ $info = $this->filterUserInfoComponent($user);
+ if ($password !== null) {
+ $info .= ':' . $this->filterUserInfoComponent($password);
}
if ($this->userInfo === $info) {
@@ -537,7 +537,9 @@ class Uri implements UriInterface
$this->scheme = isset($parts['scheme'])
? $this->filterScheme($parts['scheme'])
: '';
- $this->userInfo = isset($parts['user']) ? $parts['user'] : '';
+ $this->userInfo = isset($parts['user'])
+ ? $this->filterUserInfoComponent($parts['user'])
+ : '';
$this->host = isset($parts['host'])
? $this->filterHost($parts['host'])
: '';
@@ -554,7 +556,7 @@ class Uri implements UriInterface
? $this->filterQueryAndFragment($parts['fragment'])
: '';
if (isset($parts['pass'])) {
- $this->userInfo .= ':' . $parts['pass'];
+ $this->userInfo .= ':' . $this->filterUserInfoComponent($parts['pass']);
}
$this->removeDefaultPort();
@@ -577,6 +579,26 @@ class Uri implements UriInterface
}
/**
+ * @param string $component
+ *
+ * @return string
+ *
+ * @throws \InvalidArgumentException If the user info is invalid.
+ */
+ private function filterUserInfoComponent($component)
+ {
+ if (!is_string($component)) {
+ throw new \InvalidArgumentException('User info must be a string');
+ }
+
+ return preg_replace_callback(
+ '/(?:[^%' . self::$charUnreserved . self::$charSubDelims . ']+|%(?![A-Fa-f0-9]{2}))/',
+ [$this, 'rawurlencodeMatchZero'],
+ $component
+ );
+ }
+
+ /**
* @param string $host
*
* @return string
@@ -606,9 +628,9 @@ class Uri implements UriInterface
}
$port = (int) $port;
- if (1 > $port || 0xffff < $port) {
+ if (0 > $port || 0xffff < $port) {
throw new \InvalidArgumentException(
- sprintf('Invalid port: %d. Must be between 1 and 65535', $port)
+ sprintf('Invalid port: %d. Must be between 0 and 65535', $port)
);
}
diff --git a/guzzlehttp/psr7/src/functions.php b/guzzlehttp/psr7/src/functions.php
index 957bfb42..8e6dafe6 100644
--- a/guzzlehttp/psr7/src/functions.php
+++ b/guzzlehttp/psr7/src/functions.php
@@ -724,6 +724,7 @@ function mimetype_from_extension($extension)
'txt' => 'text/plain',
'wav' => 'audio/x-wav',
'webm' => 'video/webm',
+ 'webp' => 'image/webp',
'wma' => 'audio/x-ms-wma',
'wmv' => 'video/x-ms-wmv',
'woff' => 'application/x-font-woff',