Skip to content
Snippets Groups Projects

Compare revisions

Changes are shown as if the source revision was being merged into the target revision. Learn more about comparing revisions.

Source

Select target project
No results found

Target

Select target project
  • dmj/selbstzeugnisse-hab
  • goermar/selbstzeugnisse-hab
2 results
Show changes
Showing
with 320 additions and 111 deletions
# Change Log
## 6.5.5 - 2020-06-16
* Unpin version constraint for `symfony/polyfill-intl-idn` [#2678](https://github.com/guzzle/guzzle/pull/2678)
## 6.5.4 - 2020-05-25
* Fix various intl icu issues [#2626](https://github.com/guzzle/guzzle/pull/2626)
## 6.5.3 - 2020-04-18
* Use Symfony intl-idn polyfill [#2550](https://github.com/guzzle/guzzle/pull/2550)
* Remove use of internal functions [#2548](https://github.com/guzzle/guzzle/pull/2548)
## 6.5.2 - 2019-12-23
* idn_to_ascii() fix for old PHP versions [#2489](https://github.com/guzzle/guzzle/pull/2489)
## 6.5.1 - 2019-12-21
* Better defaults for PHP installations with old ICU lib [#2454](https://github.com/guzzle/guzzle/pull/2454)
* IDN support for redirects [#2424](https://github.com/guzzle/guzzle/pull/2424)
## 6.5.0 - 2019-12-07
* Improvement: Added support for reset internal queue in MockHandler. [#2143](https://github.com/guzzle/guzzle/pull/2143)
* Improvement: Added support to pass arbitrary options to `curl_multi_init`. [#2287](https://github.com/guzzle/guzzle/pull/2287)
* Fix: Gracefully handle passing `null` to the `header` option. [#2132](https://github.com/guzzle/guzzle/pull/2132)
* Fix: `RetryMiddleware` did not do exponential delay between retries due unit mismatch. [#2132](https://github.com/guzzle/guzzle/pull/2132)
Previously, `RetryMiddleware` would sleep for 1 millisecond, then 2 milliseconds, then 4 milliseconds.
**After this change, `RetryMiddleware` will sleep for 1 second, then 2 seconds, then 4 seconds.**
`Middleware::retry()` accepts a second callback parameter to override the default timeouts if needed.
* Fix: Prevent undefined offset when using array for ssl_key options. [#2348](https://github.com/guzzle/guzzle/pull/2348)
* Deprecated `ClientInterface::VERSION`
## 6.4.1 - 2019-10-23
* No `guzzle.phar` was created in 6.4.0 due expired API token. This release will fix that
* Added `parent::__construct()` to `FileCookieJar` and `SessionCookieJar`
## 6.4.0 - 2019-10-23
* Improvement: Improved error messages when using curl < 7.21.2 [#2108](https://github.com/guzzle/guzzle/pull/2108)
* Fix: Test if response is readable before returning a summary in `RequestException::getResponseBodySummary()` [#2081](https://github.com/guzzle/guzzle/pull/2081)
* Fix: Add support for GUZZLE_CURL_SELECT_TIMEOUT environment variable [#2161](https://github.com/guzzle/guzzle/pull/2161)
* Improvement: Added `GuzzleHttp\Exception\InvalidArgumentException` [#2163](https://github.com/guzzle/guzzle/pull/2163)
* Improvement: Added `GuzzleHttp\_current_time()` to use `hrtime()` if that function exists. [#2242](https://github.com/guzzle/guzzle/pull/2242)
* Improvement: Added curl's `appconnect_time` in `TransferStats` [#2284](https://github.com/guzzle/guzzle/pull/2284)
* Improvement: Make GuzzleException extend Throwable wherever it's available [#2273](https://github.com/guzzle/guzzle/pull/2273)
* Fix: Prevent concurrent writes to file when saving `CookieJar` [#2335](https://github.com/guzzle/guzzle/pull/2335)
* Improvement: Update `MockHandler` so we can test transfer time [#2362](https://github.com/guzzle/guzzle/pull/2362)
## 6.3.3 - 2018-04-22
* Fix: Default headers when decode_content is specified
......
FROM composer:latest as setup
RUN mkdir /guzzle
WORKDIR /guzzle
RUN set -xe \
&& composer init --name=guzzlehttp/test --description="Simple project for testing Guzzle scripts" --author="Márk Sági-Kazár <mark.sagikazar@gmail.com>" --no-interaction \
&& composer require guzzlehttp/guzzle
FROM php:7.3
RUN mkdir /guzzle
WORKDIR /guzzle
COPY --from=setup /guzzle /guzzle
......@@ -21,19 +21,18 @@ trivial to integrate with web services.
```php
$client = new \GuzzleHttp\Client();
$res = $client->request('GET', 'https://api.github.com/repos/guzzle/guzzle');
echo $res->getStatusCode();
// 200
echo $res->getHeaderLine('content-type');
// 'application/json; charset=utf8'
echo $res->getBody();
// '{"id": 1420053, "name": "guzzle", ...}'
// Send an asynchronous request.
$response = $client->request('GET', 'https://api.github.com/repos/guzzle/guzzle');
echo $response->getStatusCode(); # 200
echo $response->getHeaderLine('content-type'); # 'application/json; charset=utf8'
echo $response->getBody(); # '{"id": 1420053, "name": "guzzle", ...}'
# Send an asynchronous request.
$request = new \GuzzleHttp\Psr7\Request('GET', 'http://httpbin.org');
$promise = $client->sendAsync($request)->then(function ($response) {
echo 'I completed! ' . $response->getBody();
});
$promise->wait();
```
......@@ -57,7 +56,7 @@ curl -sS https://getcomposer.org/installer | php
Next, run the Composer command to install the latest stable version of Guzzle:
```bash
php composer.phar require guzzlehttp/guzzle
composer require guzzlehttp/guzzle
```
After installing, you need to require Composer's autoloader:
......@@ -69,7 +68,7 @@ require 'vendor/autoload.php';
You can then later update Guzzle using composer:
```bash
composer.phar update
composer update
```
......@@ -79,13 +78,13 @@ composer.phar update
|---------|------------|---------------------|--------------|---------------------|---------------------|-------|-------------|
| 3.x | EOL | `guzzle/guzzle` | `Guzzle` | [v3][guzzle-3-repo] | [v3][guzzle-3-docs] | No | >= 5.3.3 |
| 4.x | EOL | `guzzlehttp/guzzle` | `GuzzleHttp` | [v4][guzzle-4-repo] | N/A | No | >= 5.4 |
| 5.x | Maintained | `guzzlehttp/guzzle` | `GuzzleHttp` | [v5][guzzle-5-repo] | [v5][guzzle-5-docs] | No | >= 5.4 |
| 5.x | EOL | `guzzlehttp/guzzle` | `GuzzleHttp` | [v5][guzzle-5-repo] | [v5][guzzle-5-docs] | No | >= 5.4 |
| 6.x | Latest | `guzzlehttp/guzzle` | `GuzzleHttp` | [v6][guzzle-6-repo] | [v6][guzzle-6-docs] | Yes | >= 5.5 |
[guzzle-3-repo]: https://github.com/guzzle/guzzle3
[guzzle-4-repo]: https://github.com/guzzle/guzzle/tree/4.x
[guzzle-5-repo]: https://github.com/guzzle/guzzle/tree/5.3
[guzzle-6-repo]: https://github.com/guzzle/guzzle
[guzzle-3-docs]: http://guzzle3.readthedocs.org/en/latest/
[guzzle-3-docs]: http://guzzle3.readthedocs.org
[guzzle-5-docs]: http://guzzle.readthedocs.org/en/5.3/
[guzzle-6-docs]: http://guzzle.readthedocs.org/en/latest/
......@@ -2,7 +2,15 @@
"name": "guzzlehttp/guzzle",
"type": "library",
"description": "Guzzle is a PHP HTTP client library",
"keywords": ["framework", "http", "rest", "web service", "curl", "client", "HTTP client"],
"keywords": [
"framework",
"http",
"rest",
"web service",
"curl",
"client",
"HTTP client"
],
"homepage": "http://guzzlephp.org/",
"license": "MIT",
"authors": [
......@@ -14,31 +22,38 @@
],
"require": {
"php": ">=5.5",
"guzzlehttp/psr7": "^1.4",
"guzzlehttp/promises": "^1.0"
"ext-json": "*",
"symfony/polyfill-intl-idn": "^1.17.0",
"guzzlehttp/promises": "^1.0",
"guzzlehttp/psr7": "^1.6.1"
},
"require-dev": {
"ext-curl": "*",
"phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.4 || ^7.0",
"psr/log": "^1.0"
"psr/log": "^1.1"
},
"suggest": {
"psr/log": "Required for using the Log middleware"
},
"config": {
"sort-packages": true
},
"extra": {
"branch-alias": {
"dev-master": "6.5-dev"
}
},
"autoload": {
"files": ["src/functions_include.php"],
"psr-4": {
"GuzzleHttp\\": "src/"
}
},
"files": [
"src/functions_include.php"
]
},
"autoload-dev": {
"psr-4": {
"GuzzleHttp\\Tests\\": "tests/"
}
},
"suggest": {
"psr/log": "Required for using the Log middleware"
},
"extra": {
"branch-alias": {
"dev-master": "6.3-dev"
}
}
}
......@@ -2,11 +2,12 @@
namespace GuzzleHttp;
use GuzzleHttp\Cookie\CookieJar;
use GuzzleHttp\Exception\GuzzleException;
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 = [])
......@@ -46,9 +47,8 @@ class Client implements ClientInterface
* wire. The function is called with a Psr7\Http\Message\RequestInterface
* and array of transfer options, and must return a
* GuzzleHttp\Promise\PromiseInterface that is fulfilled with a
* Psr7\Http\Message\ResponseInterface on success. "handler" is a
* constructor only option that cannot be overridden in per/request
* options. If no handler is provided, a default handler will be created
* Psr7\Http\Message\ResponseInterface on success.
* If no handler is provided, a default handler will be created
* that enables all of the request options below by attaching all of the
* default middleware to the handler.
* - base_uri: (string|UriInterface) Base URI of the client that is merged
......@@ -75,6 +75,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 +95,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 +114,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 +162,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 +200,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 +214,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 = Utils::idnUriConvert($uri, $idnOptions);
}
return $uri->getScheme() === '' && $uri->getHost() !== '' ? $uri->withScheme('http') : $uri;
}
......@@ -154,6 +226,7 @@ class Client implements ClientInterface
* Configures the default options for a client.
*
* @param array $config
* @return void
*/
private function configureDefaults(array $config)
{
......@@ -162,7 +235,8 @@ class Client implements ClientInterface
'http_errors' => true,
'decode_content' => true,
'verify' => true,
'cookies' => false
'cookies' => false,
'idn_conversion' => true,
];
// Use the standard Linux HTTP_PROXY and HTTPS_PROXY if set.
......@@ -170,7 +244,7 @@ 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')) {
if (php_sapi_name() === 'cli' && getenv('HTTP_PROXY')) {
$defaults['proxy']['http'] = getenv('HTTP_PROXY');
}
......@@ -210,7 +284,7 @@ class Client implements ClientInterface
*
* @return array
*/
private function prepareDefaults($options)
private function prepareDefaults(array $options)
{
$defaults = $this->config;
......@@ -225,7 +299,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 +325,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 +344,7 @@ class Client implements ClientInterface
}
$request = $this->applyOptions($request, $options);
/** @var HandlerStack $handler */
$handler = $options['handler'];
try {
......@@ -411,6 +485,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 '
......
<?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.5';
/**
* Send an HTTP request.
......
......@@ -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);
}
);
......
......@@ -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
*/
......
......@@ -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}");
}
}
......
......@@ -22,6 +22,7 @@ class SessionCookieJar extends CookieJar
*/
public function __construct($sessionKey, $storeSessionCookies = false)
{
parent::__construct();
$this->sessionKey = $sessionKey;
$this->storeSessionCookies = $storeSessionCookies;
$this->load();
......
......@@ -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()
{
......
......@@ -4,4 +4,6 @@ namespace GuzzleHttp\Exception;
/**
* Exception when a client error is encountered (4xx codes)
*/
class ClientException extends BadResponseException {}
class ClientException extends BadResponseException
{
}
<?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
{
}
}
<?php
namespace GuzzleHttp\Exception;
final class InvalidArgumentException extends \InvalidArgumentException implements GuzzleException
{
}
<?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();
......
......@@ -4,4 +4,6 @@ namespace GuzzleHttp\Exception;
/**
* Exception when a server error is encountered (5xx codes)
*/
class ServerException extends BadResponseException {}
class ServerException extends BadResponseException
{
}
<?php
namespace GuzzleHttp\Exception;
class TooManyRedirectsException extends RequestException {}
class TooManyRedirectsException extends RequestException
{
}
<?php
namespace GuzzleHttp\Exception;
class TransferException extends \RuntimeException implements GuzzleException {}
class TransferException extends \RuntimeException implements GuzzleException
{
}
<?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}"
......
......@@ -3,7 +3,7 @@ namespace GuzzleHttp\Handler;
use GuzzleHttp\Promise as P;
use GuzzleHttp\Promise\Promise;
use GuzzleHttp\Psr7;
use GuzzleHttp\Utils;
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 = Utils::currentTime();
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] = Utils::currentTime() + ($easy->options['delay'] / 1000);
}
}
......@@ -186,7 +206,7 @@ class CurlMultiHandler
private function timeToNext()
{
$currentTime = microtime(true);
$currentTime = Utils::currentTime();
$nextTime = PHP_INT_MAX;
foreach ($this->delays as $time) {
if ($time < $nextTime) {
......