summaryrefslogtreecommitdiff
path: root/inc/mailgun/php-http/curl-client
diff options
context:
space:
mode:
authorCarson Fleming <cflems@cflems.net>2017-03-02 22:49:24 -0500
committerCarson Fleming <cflems@cflems.net>2017-03-02 22:49:24 -0500
commitb76e2ff898b23745d4c9aaee49eeb7d88f2896ab (patch)
tree9b794be8db310a575d70165d9ebde0a183b61b01 /inc/mailgun/php-http/curl-client
parentbfcc9f7a7656a2db0c905b3c13114664f00f6c37 (diff)
downloadbulletin-b76e2ff898b23745d4c9aaee49eeb7d88f2896ab.tar.gz
Updated mailgun plugin
Diffstat (limited to 'inc/mailgun/php-http/curl-client')
-rw-r--r--inc/mailgun/php-http/curl-client/.php_cs9
-rw-r--r--inc/mailgun/php-http/curl-client/.styleci.yml4
-rw-r--r--inc/mailgun/php-http/curl-client/CHANGELOG.md163
-rw-r--r--inc/mailgun/php-http/curl-client/LICENSE19
-rw-r--r--inc/mailgun/php-http/curl-client/README.md44
-rw-r--r--inc/mailgun/php-http/curl-client/composer.json50
-rw-r--r--inc/mailgun/php-http/curl-client/puli.json242
-rw-r--r--inc/mailgun/php-http/curl-client/src/Client.php371
-rw-r--r--inc/mailgun/php-http/curl-client/src/CurlPromise.php108
-rw-r--r--inc/mailgun/php-http/curl-client/src/MultiRunner.php127
-rw-r--r--inc/mailgun/php-http/curl-client/src/PromiseCore.php224
-rw-r--r--inc/mailgun/php-http/curl-client/src/ResponseBuilder.php21
12 files changed, 1382 insertions, 0 deletions
diff --git a/inc/mailgun/php-http/curl-client/.php_cs b/inc/mailgun/php-http/curl-client/.php_cs
new file mode 100644
index 0000000..febeee5
--- /dev/null
+++ b/inc/mailgun/php-http/curl-client/.php_cs
@@ -0,0 +1,9 @@
+<?php
+
+return Symfony\CS\Config\Config::create()
+ ->level(Symfony\CS\FixerInterface::PSR2_LEVEL)
+ ->fixers([])
+ ->finder(
+ Symfony\CS\Finder\DefaultFinder::create()->in(__DIR__ . '/src')
+ )
+;
diff --git a/inc/mailgun/php-http/curl-client/.styleci.yml b/inc/mailgun/php-http/curl-client/.styleci.yml
new file mode 100644
index 0000000..4d43c93
--- /dev/null
+++ b/inc/mailgun/php-http/curl-client/.styleci.yml
@@ -0,0 +1,4 @@
+preset: psr2
+finder:
+ path:
+ - "src"
diff --git a/inc/mailgun/php-http/curl-client/CHANGELOG.md b/inc/mailgun/php-http/curl-client/CHANGELOG.md
new file mode 100644
index 0000000..a3f52d1
--- /dev/null
+++ b/inc/mailgun/php-http/curl-client/CHANGELOG.md
@@ -0,0 +1,163 @@
+# Change Log
+
+## 1.7 - 2017-02-09
+
+### Changed
+
+- #30: Make sure we rewind streams
+
+## 1.6.2 - 2017-01-02
+
+### Fixed
+
+- #29: Request not using CURLOPT_POSTFIELDS have content-length set to
+
+### Changed
+
+- Use binary mode to create response body stream.
+
+
+## 1.6.1 - 2016-11-11
+
+### Fixed
+
+- #27: ErrorPlugin and sendAsyncRequest() incompatibility
+
+
+## 1.6 - 2016-09-12
+
+### Changed
+
+- `Client::sendRequest` now throws `Http\Client\Exception\NetworkException` on network errors.
+- `\UnexpectedValueException` replaced with `Http\Client\Exception\RequestException` in
+ `Client::sendRequest` and `Client::sendAsyncRequest`
+
+
+## 1.5.1 - 2016-08-29
+
+### Fixed
+
+- #26: Combining CurlClient with StopwatchPlugin causes Promise onRejected handler to never be
+ invoked.
+
+
+## 1.5 - 2016-08-03
+
+### Changed
+
+- Request body can be send with any method except GET, HEAD and TRACE.
+- #25: Make discovery a hard dependency.
+
+
+## 1.4.2 - 2016-06-14
+
+### Added
+
+- #23: "php-http/async-client-implementation" added to "provide" section.
+
+
+## 1.4.1 - 2016-05-30
+
+### Fixed
+
+- #22: Cannot create the client using `HttpClientDiscovery`.
+
+
+## 1.4 - 2016-03-30
+
+### Changed
+
+- #20: Minimize memory usage when reading large response body.
+
+
+## 1.3 - 2016-03-14
+
+### Fixed
+
+- #18: Invalid "Expect" header.
+
+### Removed
+
+- #13: Remove HeaderParser.
+
+
+## 1.2 - 2016-03-09
+
+### Added
+
+- #16: Make sure discovery can find the curl client
+
+### Fixed
+
+- #15: "Out of memory" sending large files.
+
+
+## 1.1.0 - 2016-01-29
+
+### Changed
+
+- Switch to php-http/message 1.0.
+
+
+## 1.0.0 - 2016-01-28
+
+First stable release.
+
+
+## 0.7.0 - 2016-01-26
+
+### Changed
+
+- Migrate from `php-http/discovery` and `php-http/utils` to `php-http/message`.
+
+## 0.6.0 - 2016-01-12
+
+### Changed
+
+- Root namespace changed from `Http\Curl` to `Http\Client\Curl`.
+- Main client class name renamed from `CurlHttpClient` to `Client`.
+- Minimum required [php-http/discovery](https://packagist.org/packages/php-http/discovery)
+ version changed to 0.5.
+
+
+## 0.5.0 - 2015-12-18
+
+### Changed
+
+- Compatibility with php-http/httplug 1.0 beta
+- Switch to php-http/discovery 0.4
+
+
+## 0.4.0 - 2015-12-16
+
+### Changed
+
+- Switch to php-http/message-factory 1.0
+
+
+## 0.3.1 - 2015-12-14
+
+### Changed
+
+- Requirements fixed.
+
+
+## 0.3.0 - 2015-11-24
+
+### Changed
+
+- Use cURL constants as options keys.
+
+
+## 0.2.0 - 2015-11-17
+
+### Added
+
+- HttpAsyncClient support.
+
+
+## 0.1.0 - 2015-11-11
+
+### Added
+
+- Initial release
diff --git a/inc/mailgun/php-http/curl-client/LICENSE b/inc/mailgun/php-http/curl-client/LICENSE
new file mode 100644
index 0000000..8e2c4a0
--- /dev/null
+++ b/inc/mailgun/php-http/curl-client/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2015 PHP HTTP Team <team@php-http.org>
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is furnished
+to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
diff --git a/inc/mailgun/php-http/curl-client/README.md b/inc/mailgun/php-http/curl-client/README.md
new file mode 100644
index 0000000..fc60b7e
--- /dev/null
+++ b/inc/mailgun/php-http/curl-client/README.md
@@ -0,0 +1,44 @@
+# Curl client for PHP HTTP
+
+[![Latest Version](https://img.shields.io/github/release/php-http/curl-client.svg?style=flat-square)](https://github.com/php-http/curl-client/releases)
+[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](LICENSE)
+[![Build Status](https://img.shields.io/travis/php-http/curl-client.svg?style=flat-square)](https://travis-ci.org/php-http/curl-client)
+[![Code Coverage](https://img.shields.io/scrutinizer/coverage/g/php-http/curl-client.svg?style=flat-square)](https://scrutinizer-ci.com/g/php-http/curl-client)
+[![Quality Score](https://img.shields.io/scrutinizer/g/php-http/curl-client.svg?style=flat-square)](https://scrutinizer-ci.com/g/php-http/curl-client)
+[![Total Downloads](https://img.shields.io/packagist/dt/php-http/curl-client.svg?style=flat-square)](https://packagist.org/packages/php-http/curl-client)
+
+The cURL client use the cURL PHP extension which must be activated in your `php.ini`.
+
+
+## Install
+
+Via Composer
+
+``` bash
+$ composer require php-http/curl-client
+```
+
+## Documentation
+
+Please see the [official documentation](http://docs.php-http.org/en/latest/clients/curl-client.html).
+
+## Testing
+
+``` bash
+$ composer test
+```
+
+## Contributing
+
+Please see [CONTRIBUTING](CONTRIBUTING.md) and [CONDUCT](CONDUCT.md) for details.
+
+
+## Security
+
+If you discover any security related issues, please contact us at
+[security@php-http.org](mailto:security@php-http.org).
+
+
+## License
+
+The MIT License (MIT). Please see [License File](LICENSE) for more information.
diff --git a/inc/mailgun/php-http/curl-client/composer.json b/inc/mailgun/php-http/curl-client/composer.json
new file mode 100644
index 0000000..5d16222
--- /dev/null
+++ b/inc/mailgun/php-http/curl-client/composer.json
@@ -0,0 +1,50 @@
+{
+ "name": "php-http/curl-client",
+ "description": "cURL client for PHP-HTTP",
+ "license": "MIT",
+ "keywords": ["http", "curl"],
+ "homepage": "http://php-http.org",
+ "authors": [
+ {
+ "name": "Михаил Красильников",
+ "email": "m.krasilnikov@yandex.ru"
+ }
+ ],
+ "prefer-stable": true,
+ "minimum-stability": "beta",
+ "config": {
+ "bin-dir": "vendor/bin"
+ },
+ "require": {
+ "php": "^5.5 || ^7.0",
+ "ext-curl": "*",
+ "php-http/httplug": "^1.0",
+ "php-http/message-factory": "^1.0.2",
+ "php-http/message": "^1.2",
+ "php-http/discovery": "^1.0"
+ },
+ "require-dev": {
+ "guzzlehttp/psr7": "^1.0",
+ "php-http/client-integration-tests": "^0.5.1",
+ "phpunit/phpunit": "^4.8.27",
+ "zendframework/zend-diactoros": "^1.0"
+ },
+ "autoload": {
+ "psr-4": {
+ "Http\\Client\\Curl\\": "src/"
+ }
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "Http\\Client\\Curl\\Tests\\": "tests/"
+ }
+ },
+ "provide": {
+ "php-http/client-implementation": "1.0",
+ "php-http/async-client-implementation": "1.0"
+ },
+ "scripts": {
+ "test": "vendor/bin/phpunit",
+ "test-ci": "vendor/bin/phpunit --coverage-clover build/coverage.xml"
+ }
+}
diff --git a/inc/mailgun/php-http/curl-client/puli.json b/inc/mailgun/php-http/curl-client/puli.json
new file mode 100644
index 0000000..b35768d
--- /dev/null
+++ b/inc/mailgun/php-http/curl-client/puli.json
@@ -0,0 +1,242 @@
+{
+ "version": "1.0",
+ "name": "php-http/curl-client",
+ "bindings": {
+ "98239b8b-103b-4f47-94c7-4cba49a05a1f": {
+ "_class": "Puli\\Discovery\\Binding\\ClassBinding",
+ "class": "Http\\Client\\Curl\\Client",
+ "type": "Http\\Client\\HttpAsyncClient"
+ },
+ "a6a79968-2aa5-427c-bbe1-a581d9a48321": {
+ "_class": "Puli\\Discovery\\Binding\\ClassBinding",
+ "class": "Http\\Client\\Curl\\Client",
+ "type": "Http\\Client\\HttpClient"
+ }
+ },
+ "config": {
+ "bootstrap-file": "vendor/autoload.php"
+ },
+ "packages": {
+ "clue/stream-filter": {
+ "install-path": "vendor/clue/stream-filter",
+ "installer": "composer",
+ "env": "dev"
+ },
+ "doctrine/instantiator": {
+ "install-path": "vendor/doctrine/instantiator",
+ "installer": "composer",
+ "env": "dev"
+ },
+ "guzzlehttp/psr7": {
+ "install-path": "vendor/guzzlehttp/psr7",
+ "installer": "composer",
+ "env": "dev"
+ },
+ "justinrainbow/json-schema": {
+ "install-path": "vendor/justinrainbow/json-schema",
+ "installer": "composer",
+ "env": "dev"
+ },
+ "paragonie/random_compat": {
+ "install-path": "vendor/paragonie/random_compat",
+ "installer": "composer",
+ "env": "dev"
+ },
+ "php-http/adapter-integration-tests": {
+ "install-path": "vendor/php-http/adapter-integration-tests",
+ "installer": "composer",
+ "env": "dev"
+ },
+ "php-http/discovery": {
+ "install-path": "vendor/php-http/discovery",
+ "installer": "composer",
+ "env": "dev"
+ },
+ "php-http/httplug": {
+ "install-path": "vendor/php-http/httplug",
+ "installer": "composer"
+ },
+ "php-http/message": {
+ "install-path": "vendor/php-http/message",
+ "installer": "composer",
+ "env": "dev"
+ },
+ "php-http/message-factory": {
+ "install-path": "vendor/php-http/message-factory",
+ "installer": "composer"
+ },
+ "php-http/promise": {
+ "install-path": "vendor/php-http/promise",
+ "installer": "composer"
+ },
+ "phpdocumentor/reflection-docblock": {
+ "install-path": "vendor/phpdocumentor/reflection-docblock",
+ "installer": "composer",
+ "env": "dev"
+ },
+ "phpspec/prophecy": {
+ "install-path": "vendor/phpspec/prophecy",
+ "installer": "composer",
+ "env": "dev"
+ },
+ "phpunit/php-code-coverage": {
+ "install-path": "vendor/phpunit/php-code-coverage",
+ "installer": "composer",
+ "env": "dev"
+ },
+ "phpunit/php-file-iterator": {
+ "install-path": "vendor/phpunit/php-file-iterator",
+ "installer": "composer",
+ "env": "dev"
+ },
+ "phpunit/php-text-template": {
+ "install-path": "vendor/phpunit/php-text-template",
+ "installer": "composer",
+ "env": "dev"
+ },
+ "phpunit/php-timer": {
+ "install-path": "vendor/phpunit/php-timer",
+ "installer": "composer",
+ "env": "dev"
+ },
+ "phpunit/php-token-stream": {
+ "install-path": "vendor/phpunit/php-token-stream",
+ "installer": "composer",
+ "env": "dev"
+ },
+ "phpunit/phpunit": {
+ "install-path": "vendor/phpunit/phpunit",
+ "installer": "composer",
+ "env": "dev"
+ },
+ "phpunit/phpunit-mock-objects": {
+ "install-path": "vendor/phpunit/phpunit-mock-objects",
+ "installer": "composer",
+ "env": "dev"
+ },
+ "psr/http-message": {
+ "install-path": "vendor/psr/http-message",
+ "installer": "composer"
+ },
+ "psr/log": {
+ "install-path": "vendor/psr/log",
+ "installer": "composer",
+ "env": "dev"
+ },
+ "puli/composer-plugin": {
+ "install-path": "vendor/puli/composer-plugin",
+ "installer": "composer",
+ "env": "dev"
+ },
+ "puli/discovery": {
+ "install-path": "vendor/puli/discovery",
+ "installer": "composer",
+ "env": "dev"
+ },
+ "puli/repository": {
+ "install-path": "vendor/puli/repository",
+ "installer": "composer",
+ "env": "dev"
+ },
+ "puli/url-generator": {
+ "install-path": "vendor/puli/url-generator",
+ "installer": "composer",
+ "env": "dev"
+ },
+ "ramsey/uuid": {
+ "install-path": "vendor/ramsey/uuid",
+ "installer": "composer",
+ "env": "dev"
+ },
+ "sebastian/comparator": {
+ "install-path": "vendor/sebastian/comparator",
+ "installer": "composer",
+ "env": "dev"
+ },
+ "sebastian/diff": {
+ "install-path": "vendor/sebastian/diff",
+ "installer": "composer",
+ "env": "dev"
+ },
+ "sebastian/environment": {
+ "install-path": "vendor/sebastian/environment",
+ "installer": "composer",
+ "env": "dev"
+ },
+ "sebastian/exporter": {
+ "install-path": "vendor/sebastian/exporter",
+ "installer": "composer",
+ "env": "dev"
+ },
+ "sebastian/global-state": {
+ "install-path": "vendor/sebastian/global-state",
+ "installer": "composer",
+ "env": "dev"
+ },
+ "sebastian/recursion-context": {
+ "install-path": "vendor/sebastian/recursion-context",
+ "installer": "composer",
+ "env": "dev"
+ },
+ "sebastian/version": {
+ "install-path": "vendor/sebastian/version",
+ "installer": "composer",
+ "env": "dev"
+ },
+ "seld/jsonlint": {
+ "install-path": "vendor/seld/jsonlint",
+ "installer": "composer",
+ "env": "dev"
+ },
+ "symfony/filesystem": {
+ "install-path": "vendor/symfony/filesystem",
+ "installer": "composer",
+ "env": "dev"
+ },
+ "symfony/process": {
+ "install-path": "vendor/symfony/process",
+ "installer": "composer",
+ "env": "dev"
+ },
+ "symfony/yaml": {
+ "install-path": "vendor/symfony/yaml",
+ "installer": "composer",
+ "env": "dev"
+ },
+ "th3n3rd/cartesian-product": {
+ "install-path": "vendor/th3n3rd/cartesian-product",
+ "installer": "composer",
+ "env": "dev"
+ },
+ "webmozart/assert": {
+ "install-path": "vendor/webmozart/assert",
+ "installer": "composer",
+ "env": "dev"
+ },
+ "webmozart/expression": {
+ "install-path": "vendor/webmozart/expression",
+ "installer": "composer",
+ "env": "dev"
+ },
+ "webmozart/glob": {
+ "install-path": "vendor/webmozart/glob",
+ "installer": "composer",
+ "env": "dev"
+ },
+ "webmozart/json": {
+ "install-path": "vendor/webmozart/json",
+ "installer": "composer",
+ "env": "dev"
+ },
+ "webmozart/path-util": {
+ "install-path": "vendor/webmozart/path-util",
+ "installer": "composer",
+ "env": "dev"
+ },
+ "zendframework/zend-diactoros": {
+ "install-path": "vendor/zendframework/zend-diactoros",
+ "installer": "composer",
+ "env": "dev"
+ }
+ }
+}
diff --git a/inc/mailgun/php-http/curl-client/src/Client.php b/inc/mailgun/php-http/curl-client/src/Client.php
new file mode 100644
index 0000000..5696ab3
--- /dev/null
+++ b/inc/mailgun/php-http/curl-client/src/Client.php
@@ -0,0 +1,371 @@
+<?php
+namespace Http\Client\Curl;
+
+use Http\Client\Exception;
+use Http\Client\HttpAsyncClient;
+use Http\Client\HttpClient;
+use Http\Discovery\MessageFactoryDiscovery;
+use Http\Discovery\StreamFactoryDiscovery;
+use Http\Message\MessageFactory;
+use Http\Message\StreamFactory;
+use Http\Promise\Promise;
+use Psr\Http\Message\RequestInterface;
+use Psr\Http\Message\ResponseInterface;
+
+/**
+ * PSR-7 compatible cURL based HTTP client
+ *
+ * @license http://opensource.org/licenses/MIT MIT
+ *
+ * @author Михаил Красильников <m.krasilnikov@yandex.ru>
+ * @author Blake Williams <github@shabbyrobe.org>
+ *
+ * @api
+ * @since 1.0
+ */
+class Client implements HttpClient, HttpAsyncClient
+{
+ /**
+ * cURL options
+ *
+ * @var array
+ */
+ private $options;
+
+ /**
+ * PSR-7 message factory
+ *
+ * @var MessageFactory
+ */
+ private $messageFactory;
+
+ /**
+ * PSR-7 stream factory
+ *
+ * @var StreamFactory
+ */
+ private $streamFactory;
+
+ /**
+ * cURL synchronous requests handle
+ *
+ * @var resource|null
+ */
+ private $handle = null;
+
+ /**
+ * Simultaneous requests runner
+ *
+ * @var MultiRunner|null
+ */
+ private $multiRunner = null;
+
+ /**
+ * Create new client
+ *
+ * @param MessageFactory|null $messageFactory HTTP Message factory
+ * @param StreamFactory|null $streamFactory HTTP Stream factory
+ * @param array $options cURL options (see http://php.net/curl_setopt)
+ *
+ * @throws \Http\Discovery\Exception\NotFoundException If factory discovery failed.
+ *
+ * @since 1.0
+ */
+ public function __construct(
+ MessageFactory $messageFactory = null,
+ StreamFactory $streamFactory = null,
+ array $options = []
+ ) {
+ $this->messageFactory = $messageFactory ?: MessageFactoryDiscovery::find();
+ $this->streamFactory = $streamFactory ?: StreamFactoryDiscovery::find();
+ $this->options = $options;
+ }
+
+ /**
+ * Release resources if still active
+ */
+ public function __destruct()
+ {
+ if (is_resource($this->handle)) {
+ curl_close($this->handle);
+ }
+ }
+
+ /**
+ * Sends a PSR-7 request.
+ *
+ * @param RequestInterface $request
+ *
+ * @return ResponseInterface
+ *
+ * @throws \Http\Client\Exception\NetworkException In case of network problems.
+ * @throws \Http\Client\Exception\RequestException On invalid request.
+ * @throws \InvalidArgumentException For invalid header names or values.
+ * @throws \RuntimeException If creating the body stream fails.
+ *
+ * @since 1.6 \UnexpectedValueException replaced with RequestException.
+ * @since 1.6 Throw NetworkException on network errors.
+ * @since 1.0
+ */
+ public function sendRequest(RequestInterface $request)
+ {
+ $responseBuilder = $this->createResponseBuilder();
+ $options = $this->createCurlOptions($request, $responseBuilder);
+
+ if (is_resource($this->handle)) {
+ curl_reset($this->handle);
+ } else {
+ $this->handle = curl_init();
+ }
+
+ curl_setopt_array($this->handle, $options);
+ curl_exec($this->handle);
+
+ $errno = curl_errno($this->handle);
+ switch ($errno) {
+ case CURLE_OK:
+ // All OK, no actions needed.
+ break;
+ case CURLE_COULDNT_RESOLVE_PROXY:
+ case CURLE_COULDNT_RESOLVE_HOST:
+ case CURLE_COULDNT_CONNECT:
+ case CURLE_OPERATION_TIMEOUTED:
+ case CURLE_SSL_CONNECT_ERROR:
+ throw new Exception\NetworkException(curl_error($this->handle), $request);
+ default:
+ throw new Exception\RequestException(curl_error($this->handle), $request);
+ }
+
+ $response = $responseBuilder->getResponse();
+ $response->getBody()->seek(0);
+
+ return $response;
+ }
+
+ /**
+ * Sends a PSR-7 request in an asynchronous way.
+ *
+ * @param RequestInterface $request
+ *
+ * @return Promise
+ *
+ * @throws \Http\Client\Exception\RequestException On invalid request.
+ * @throws \InvalidArgumentException For invalid header names or values.
+ * @throws \RuntimeException If creating the body stream fails.
+ *
+ * @since 1.6 \UnexpectedValueException replaced with RequestException.
+ * @since 1.0
+ */
+ public function sendAsyncRequest(RequestInterface $request)
+ {
+ if (!$this->multiRunner instanceof MultiRunner) {
+ $this->multiRunner = new MultiRunner();
+ }
+
+ $handle = curl_init();
+ $responseBuilder = $this->createResponseBuilder();
+ $options = $this->createCurlOptions($request, $responseBuilder);
+ curl_setopt_array($handle, $options);
+
+ $core = new PromiseCore($request, $handle, $responseBuilder);
+ $promise = new CurlPromise($core, $this->multiRunner);
+ $this->multiRunner->add($core);
+
+ return $promise;
+ }
+
+ /**
+ * Generates cURL options
+ *
+ * @param RequestInterface $request
+ * @param ResponseBuilder $responseBuilder
+ *
+ * @throws \Http\Client\Exception\RequestException On invalid request.
+ * @throws \InvalidArgumentException For invalid header names or values.
+ * @throws \RuntimeException if can not read body
+ *
+ * @return array
+ */
+ private function createCurlOptions(RequestInterface $request, ResponseBuilder $responseBuilder)
+ {
+ $options = $this->options;
+
+ $options[CURLOPT_HEADER] = false;
+ $options[CURLOPT_RETURNTRANSFER] = false;
+ $options[CURLOPT_FOLLOWLOCATION] = false;
+
+ try {
+ $options[CURLOPT_HTTP_VERSION]
+ = $this->getProtocolVersion($request->getProtocolVersion());
+ } catch (\UnexpectedValueException $e) {
+ throw new Exception\RequestException($e->getMessage(), $request);
+ }
+ $options[CURLOPT_URL] = (string) $request->getUri();
+
+ $options = $this->addRequestBodyOptions($request, $options);
+
+ $options[CURLOPT_HTTPHEADER] = $this->createHeaders($request, $options);
+
+ if ($request->getUri()->getUserInfo()) {
+ $options[CURLOPT_USERPWD] = $request->getUri()->getUserInfo();
+ }
+
+ $options[CURLOPT_HEADERFUNCTION] = function ($ch, $data) use ($responseBuilder) {
+ $str = trim($data);
+ if ('' !== $str) {
+ if (strpos(strtolower($str), 'http/') === 0) {
+ $responseBuilder->setStatus($str)->getResponse();
+ } else {
+ $responseBuilder->addHeader($str);
+ }
+ }
+
+ return strlen($data);
+ };
+
+ $options[CURLOPT_WRITEFUNCTION] = function ($ch, $data) use ($responseBuilder) {
+ return $responseBuilder->getResponse()->getBody()->write($data);
+ };
+
+ return $options;
+ }
+
+ /**
+ * Return cURL constant for specified HTTP version
+ *
+ * @param string $requestVersion
+ *
+ * @throws \UnexpectedValueException if unsupported version requested
+ *
+ * @return int
+ */
+ private function getProtocolVersion($requestVersion)
+ {
+ switch ($requestVersion) {
+ case '1.0':
+ return CURL_HTTP_VERSION_1_0;
+ case '1.1':
+ return CURL_HTTP_VERSION_1_1;
+ case '2.0':
+ if (defined('CURL_HTTP_VERSION_2_0')) {
+ return CURL_HTTP_VERSION_2_0;
+ }
+ throw new \UnexpectedValueException('libcurl 7.33 needed for HTTP 2.0 support');
+ }
+
+ return CURL_HTTP_VERSION_NONE;
+ }
+
+ /**
+ * Add request body related cURL options.
+ *
+ * @param RequestInterface $request
+ * @param array $options
+ *
+ * @return array
+ */
+ private function addRequestBodyOptions(RequestInterface $request, array $options)
+ {
+ /*
+ * Some HTTP methods cannot have payload:
+ *
+ * - GET — cURL will automatically change method to PUT or POST if we set CURLOPT_UPLOAD or
+ * CURLOPT_POSTFIELDS.
+ * - HEAD — cURL treats HEAD as GET request with a same restrictions.
+ * - TRACE — According to RFC7231: a client MUST NOT send a message body in a TRACE request.
+ */
+ if (!in_array($request->getMethod(), ['GET', 'HEAD', 'TRACE'], true)) {
+ $body = $request->getBody();
+ $bodySize = $body->getSize();
+ if ($bodySize !== 0) {
+ if ($body->isSeekable()) {
+ $body->rewind();
+ }
+
+ // Message has non empty body.
+ if (null === $bodySize || $bodySize > 1024 * 1024) {
+ // Avoid full loading large or unknown size body into memory
+ $options[CURLOPT_UPLOAD] = true;
+ if (null !== $bodySize) {
+ $options[CURLOPT_INFILESIZE] = $bodySize;
+ }
+ $options[CURLOPT_READFUNCTION] = function ($ch, $fd, $length) use ($body) {
+ return $body->read($length);
+ };
+ } else {
+ // Small body can be loaded into memory
+ $options[CURLOPT_POSTFIELDS] = (string) $body;
+ }
+ }
+ }
+
+ if ($request->getMethod() === 'HEAD') {
+ // This will set HTTP method to "HEAD".
+ $options[CURLOPT_NOBODY] = true;
+ } elseif ($request->getMethod() !== 'GET') {
+ // GET is a default method. Other methods should be specified explicitly.
+ $options[CURLOPT_CUSTOMREQUEST] = $request->getMethod();
+ }
+
+ return $options;
+ }
+
+ /**
+ * Create headers array for CURLOPT_HTTPHEADER
+ *
+ * @param RequestInterface $request
+ * @param array $options cURL options
+ *
+ * @return string[]
+ */
+ private function createHeaders(RequestInterface $request, array $options)
+ {
+ $curlHeaders = [];
+ $headers = $request->getHeaders();
+ foreach ($headers as $name => $values) {
+ $header = strtolower($name);
+ if ('expect' === $header) {
+ // curl-client does not support "Expect-Continue", so dropping "expect" headers
+ continue;
+ }
+ if ('content-length' === $header) {
+ if (array_key_exists(CURLOPT_POSTFIELDS, $options)) {
+ // Small body content length can be calculated here.
+ $values = [strlen($options[CURLOPT_POSTFIELDS])];
+ } elseif (!array_key_exists(CURLOPT_READFUNCTION, $options)) {
+ // Else if there is no body, forcing "Content-length" to 0
+ $values = [0];
+ }
+ }
+ foreach ($values as $value) {
+ $curlHeaders[] = $name . ': ' . $value;
+ }
+ }
+ /*
+ * curl-client does not support "Expect-Continue", but cURL adds "Expect" header by default.
+ * We can not suppress it, but we can set it to empty.
+ */
+ $curlHeaders[] = 'Expect:';
+
+ return $curlHeaders;
+ }
+
+ /**
+ * Create new ResponseBuilder instance
+ *
+ * @return ResponseBuilder
+ *
+ * @throws \RuntimeException If creating the stream from $body fails.
+ */
+ private function createResponseBuilder()
+ {
+ try {
+ $body = $this->streamFactory->createStream(fopen('php://temp', 'w+b'));
+ } catch (\InvalidArgumentException $e) {
+ throw new \RuntimeException('Can not create "php://temp" stream.');
+ }
+ $response = $this->messageFactory->createResponse(200, null, [], $body);
+
+ return new ResponseBuilder($response);
+ }
+}
diff --git a/inc/mailgun/php-http/curl-client/src/CurlPromise.php b/inc/mailgun/php-http/curl-client/src/CurlPromise.php
new file mode 100644
index 0000000..68a775c
--- /dev/null
+++ b/inc/mailgun/php-http/curl-client/src/CurlPromise.php
@@ -0,0 +1,108 @@
+<?php
+namespace Http\Client\Curl;
+
+use Http\Promise\Promise;
+
+/**
+ * Promise represents a response that may not be available yet, but will be resolved at some point
+ * in future. It acts like a proxy to the actual response.
+ *
+ * This interface is an extension of the promises/a+ specification https://promisesaplus.com/
+ * Value is replaced by an object where its class implement a Psr\Http\Message\RequestInterface.
+ * Reason is replaced by an object where its class implement a Http\Client\Exception.
+ *
+ * @license http://opensource.org/licenses/MIT MIT
+ *
+ * @author Михаил Красильников <m.krasilnikov@yandex.ru>
+ */
+class CurlPromise implements Promise
+{
+ /**
+ * Shared promise core
+ *
+ * @var PromiseCore
+ */
+ private $core;
+
+ /**
+ * Requests runner
+ *
+ * @var MultiRunner
+ */
+ private $runner;
+
+ /**
+ * Create new promise.
+ *
+ * @param PromiseCore $core Shared promise core
+ * @param MultiRunner $runner Simultaneous requests runner
+ */
+ public function __construct(PromiseCore $core, MultiRunner $runner)
+ {
+ $this->core = $core;
+ $this->runner = $runner;
+ }
+
+ /**
+ * Add behavior for when the promise is resolved or rejected.
+ *
+ * If you do not care about one of the cases, you can set the corresponding callable to null
+ * The callback will be called when the response or exception arrived and never more than once.
+ *
+ * @param callable $onFulfilled Called when a response will be available.
+ * @param callable $onRejected Called when an error happens.
+ *
+ * You must always return the Response in the interface or throw an Exception.
+ *
+ * @return Promise Always returns a new promise which is resolved with value of the executed
+ * callback (onFulfilled / onRejected).
+ */
+ public function then(callable $onFulfilled = null, callable $onRejected = null)
+ {
+ if ($onFulfilled) {
+ $this->core->addOnFulfilled($onFulfilled);
+ }
+ if ($onRejected) {
+ $this->core->addOnRejected($onRejected);
+ }
+
+ return new self($this->core, $this->runner);
+ }
+
+ /**
+ * Get the state of the promise, one of PENDING, FULFILLED or REJECTED.
+ *
+ * @return string
+ */
+ public function getState()
+ {
+ return $this->core->getState();
+ }
+
+ /**
+ * Wait for the promise to be fulfilled or rejected.
+ *
+ * When this method returns, the request has been resolved and the appropriate callable has terminated.
+ *
+ * When called with the unwrap option
+ *
+ * @param bool $unwrap Whether to return resolved value / throw reason or not
+ *
+ * @return \Psr\Http\Message\ResponseInterface|null Resolved value, null if $unwrap is set to false
+ *
+ * @throws \Http\Client\Exception The rejection reason.
+ */
+ public function wait($unwrap = true)
+ {
+ $this->runner->wait($this->core);
+
+ if ($unwrap) {
+ if ($this->core->getState() === self::REJECTED) {
+ throw $this->core->getException();
+ }
+
+ return $this->core->getResponse();
+ }
+ return null;
+ }
+}
diff --git a/inc/mailgun/php-http/curl-client/src/MultiRunner.php b/inc/mailgun/php-http/curl-client/src/MultiRunner.php
new file mode 100644
index 0000000..9094c0f
--- /dev/null
+++ b/inc/mailgun/php-http/curl-client/src/MultiRunner.php
@@ -0,0 +1,127 @@
+<?php
+namespace Http\Client\Curl;
+
+use Http\Client\Exception\RequestException;
+
+/**
+ * Simultaneous requests runner
+ *
+ * @license http://opensource.org/licenses/MIT MIT
+ *
+ * @author Михаил Красильников <m.krasilnikov@yandex.ru>
+ */
+class MultiRunner
+{
+ /**
+ * cURL multi handle
+ *
+ * @var resource|null
+ */
+ private $multiHandle = null;
+
+ /**
+ * Awaiting cores
+ *
+ * @var PromiseCore[]
+ */
+ private $cores = [];
+
+ /**
+ * Release resources if still active
+ */
+ public function __destruct()
+ {
+ if (is_resource($this->multiHandle)) {
+ curl_multi_close($this->multiHandle);
+ }
+ }
+
+ /**
+ * Add promise to runner
+ *
+ * @param PromiseCore $core
+ */
+ public function add(PromiseCore $core)
+ {
+ foreach ($this->cores as $existed) {
+ if ($existed === $core) {
+ return;
+ }
+ }
+
+ $this->cores[] = $core;
+
+ if (null === $this->multiHandle) {
+ $this->multiHandle = curl_multi_init();
+ }
+ curl_multi_add_handle($this->multiHandle, $core->getHandle());
+ }
+
+ /**
+ * Remove promise from runner
+ *
+ * @param PromiseCore $core
+ */
+ public function remove(PromiseCore $core)
+ {
+ foreach ($this->cores as $index => $existed) {
+ if ($existed === $core) {
+ curl_multi_remove_handle($this->multiHandle, $core->getHandle());
+ unset($this->cores[$index]);
+ return;
+ }
+ }
+ }
+
+ /**
+ * Wait for request(s) to be completed.
+ *
+ * @param PromiseCore|null $targetCore
+ */
+ public function wait(PromiseCore $targetCore = null)
+ {
+ do {
+ $status = curl_multi_exec($this->multiHandle, $active);
+ $info = curl_multi_info_read($this->multiHandle);
+ if (false !== $info) {
+ $core = $this->findCoreByHandle($info['handle']);
+
+ if (null === $core) {
+ // We have no promise for this handle. Drop it.
+ curl_multi_remove_handle($this->multiHandle, $info['handle']);
+ continue;
+ }
+
+ if (CURLE_OK === $info['result']) {
+ $core->fulfill();
+ } else {
+ $error = curl_error($core->getHandle());
+ $core->reject(new RequestException($error, $core->getRequest()));
+ }
+ $this->remove($core);
+
+ // This is a promise we are waited for. So exiting wait().
+ if ($core === $targetCore) {
+ return;
+ }
+ }
+ } while ($status === CURLM_CALL_MULTI_PERFORM || $active);
+ }
+
+ /**
+ * Find core by handle.
+ *
+ * @param resource $handle
+ *
+ * @return PromiseCore|null
+ */
+ private function findCoreByHandle($handle)
+ {
+ foreach ($this->cores as $core) {
+ if ($core->getHandle() === $handle) {
+ return $core;
+ }
+ }
+ return null;
+ }
+}
diff --git a/inc/mailgun/php-http/curl-client/src/PromiseCore.php b/inc/mailgun/php-http/curl-client/src/PromiseCore.php
new file mode 100644
index 0000000..f1a3aa5
--- /dev/null
+++ b/inc/mailgun/php-http/curl-client/src/PromiseCore.php
@@ -0,0 +1,224 @@
+<?php
+namespace Http\Client\Curl;
+
+use Http\Client\Exception;
+use Http\Promise\Promise;
+use Psr\Http\Message\RequestInterface;
+use Psr\Http\Message\ResponseInterface;
+
+/**
+ * Shared promises core.
+ *
+ * @license http://opensource.org/licenses/MIT MIT
+ *
+ * @author Михаил Красильников <m.krasilnikov@yandex.ru>
+ */
+class PromiseCore
+{
+ /**
+ * HTTP request
+ *
+ * @var RequestInterface
+ */
+ private $request;
+
+ /**
+ * cURL handle
+ *
+ * @var resource
+ */
+ private $handle;
+
+ /**
+ * Response builder
+ *
+ * @var ResponseBuilder
+ */
+ private $responseBuilder;
+
+ /**
+ * Promise state
+ *
+ * @var string
+ */
+ private $state;
+
+ /**
+ * Exception
+ *
+ * @var Exception|null
+ */
+ private $exception = null;
+
+ /**
+ * Functions to call when a response will be available.
+ *
+ * @var callable[]
+ */
+ private $onFulfilled = [];
+
+ /**
+ * Functions to call when an error happens.
+ *
+ * @var callable[]
+ */
+ private $onRejected = [];
+
+ /**
+ * Create shared core.
+ *
+ * @param RequestInterface $request HTTP request
+ * @param resource $handle cURL handle
+ * @param ResponseBuilder $responseBuilder
+ */
+ public function __construct(
+ RequestInterface $request,
+ $handle,
+ ResponseBuilder $responseBuilder
+ ) {
+ assert('is_resource($handle)');
+ assert('get_resource_type($handle) === "curl"');
+
+ $this->request = $request;
+ $this->handle = $handle;
+ $this->responseBuilder = $responseBuilder;
+ $this->state = Promise::PENDING;
+ }
+
+ /**
+ * Add on fulfilled callback.
+ *
+ * @param callable $callback
+ */
+ public function addOnFulfilled(callable $callback)
+ {
+ if ($this->getState() === Promise::PENDING) {
+ $this->onFulfilled[] = $callback;
+ } elseif ($this->getState() === Promise::FULFILLED) {
+ $response = call_user_func($callback, $this->responseBuilder->getResponse());
+ if ($response instanceof ResponseInterface) {
+ $this->responseBuilder->setResponse($response);
+ }
+ }
+ }
+
+ /**
+ * Add on rejected callback.
+ *
+ * @param callable $callback
+ */
+ public function addOnRejected(callable $callback)
+ {
+ if ($this->getState() === Promise::PENDING) {
+ $this->onRejected[] = $callback;
+ } elseif ($this->getState() === Promise::REJECTED) {
+ $this->exception = call_user_func($callback, $this->exception);
+ }
+ }
+
+ /**
+ * Return cURL handle
+ *
+ * @return resource
+ */
+ public function getHandle()
+ {
+ return $this->handle;
+ }
+
+ /**
+ * Get the state of the promise, one of PENDING, FULFILLED or REJECTED.
+ *
+ * @return string
+ */
+ public function getState()
+ {
+ return $this->state;
+ }
+
+ /**
+ * Return request
+ *
+ * @return RequestInterface
+ */
+ public function getRequest()
+ {
+ return $this->request;
+ }
+
+ /**
+ * Return the value of the promise (fulfilled).
+ *
+ * @return ResponseInterface Response Object only when the Promise is fulfilled.
+ */
+ public function getResponse()
+ {
+ return $this->responseBuilder->getResponse();
+ }
+
+ /**
+ * Get the reason why the promise was rejected.
+ *
+ * If the exception is an instance of Http\Client\Exception\HttpException it will contain
+ * the response object with the status code and the http reason.
+ *
+ * @return Exception Exception Object only when the Promise is rejected.
+ *
+ * @throws \LogicException When the promise is not rejected.
+ */
+ public function getException()
+ {
+ if (null === $this->exception) {
+ throw new \LogicException('Promise is not rejected');
+ }
+
+ return $this->exception;
+ }
+
+ /**
+ * Fulfill promise.
+ */
+ public function fulfill()
+ {
+ $this->state = Promise::FULFILLED;
+ $response = $this->responseBuilder->getResponse();
+ try {
+ $response->getBody()->seek(0);
+ } catch (\RuntimeException $e) {
+ $exception = new Exception\TransferException($e->getMessage(), $e->getCode(), $e);
+ $this->reject($exception);
+
+ return;
+ }
+
+ while (count($this->onFulfilled) > 0) {
+ $callback = array_shift($this->onFulfilled);
+ $response = call_user_func($callback, $response);
+ }
+
+ if ($response instanceof ResponseInterface) {
+ $this->responseBuilder->setResponse($response);
+ }
+ }
+
+ /**
+ * Reject promise.
+ *
+ * @param Exception $exception Reject reason.
+ */
+ public function reject(Exception $exception)
+ {
+ $this->exception = $exception;
+ $this->state = Promise::REJECTED;
+
+ while (count($this->onRejected) > 0) {
+ $callback = array_shift($this->onRejected);
+ try {
+ $exception = call_user_func($callback, $this->exception);
+ $this->exception = $exception;
+ } catch (Exception $exception) {
+ $this->exception = $exception;
+ }
+ }
+ }
+}
diff --git a/inc/mailgun/php-http/curl-client/src/ResponseBuilder.php b/inc/mailgun/php-http/curl-client/src/ResponseBuilder.php
new file mode 100644
index 0000000..99e79db
--- /dev/null
+++ b/inc/mailgun/php-http/curl-client/src/ResponseBuilder.php
@@ -0,0 +1,21 @@
+<?php
+namespace Http\Client\Curl;
+
+use Http\Message\Builder\ResponseBuilder as OriginalResponseBuilder;
+use Psr\Http\Message\ResponseInterface;
+
+/**
+ * Extended response builder
+ */
+class ResponseBuilder extends OriginalResponseBuilder
+{
+ /**
+ * Replace response with a new instance
+ *
+ * @param ResponseInterface $response
+ */
+ public function setResponse(ResponseInterface $response)
+ {
+ $this->response = $response;
+ }
+}