summaryrefslogtreecommitdiff
path: root/inc/mailgun/php-http/message
diff options
context:
space:
mode:
Diffstat (limited to 'inc/mailgun/php-http/message')
-rw-r--r--inc/mailgun/php-http/message/CHANGELOG.md131
-rw-r--r--inc/mailgun/php-http/message/LICENSE19
-rw-r--r--inc/mailgun/php-http/message/README.md61
-rw-r--r--inc/mailgun/php-http/message/apigen.neon6
-rw-r--r--inc/mailgun/php-http/message/composer.json57
-rw-r--r--inc/mailgun/php-http/message/puli.json111
-rw-r--r--inc/mailgun/php-http/message/src/Authentication.php22
-rw-r--r--inc/mailgun/php-http/message/src/Authentication/AutoBasicAuth.php48
-rw-r--r--inc/mailgun/php-http/message/src/Authentication/BasicAuth.php44
-rw-r--r--inc/mailgun/php-http/message/src/Authentication/Bearer.php37
-rw-r--r--inc/mailgun/php-http/message/src/Authentication/Chain.php47
-rw-r--r--inc/mailgun/php-http/message/src/Authentication/Matching.php74
-rw-r--r--inc/mailgun/php-http/message/src/Authentication/QueryParam.php50
-rw-r--r--inc/mailgun/php-http/message/src/Authentication/RequestConditional.php47
-rw-r--r--inc/mailgun/php-http/message/src/Authentication/Wsse.php58
-rw-r--r--inc/mailgun/php-http/message/src/Builder/ResponseBuilder.php148
-rw-r--r--inc/mailgun/php-http/message/src/Cookie.php526
-rw-r--r--inc/mailgun/php-http/message/src/CookieJar.php220
-rw-r--r--inc/mailgun/php-http/message/src/Decorator/MessageDecorator.php133
-rw-r--r--inc/mailgun/php-http/message/src/Decorator/RequestDecorator.php88
-rw-r--r--inc/mailgun/php-http/message/src/Decorator/ResponseDecorator.php57
-rw-r--r--inc/mailgun/php-http/message/src/Decorator/StreamDecorator.php138
-rw-r--r--inc/mailgun/php-http/message/src/Encoding/ChunkStream.php39
-rw-r--r--inc/mailgun/php-http/message/src/Encoding/CompressStream.php42
-rw-r--r--inc/mailgun/php-http/message/src/Encoding/DechunkStream.php29
-rw-r--r--inc/mailgun/php-http/message/src/Encoding/DecompressStream.php42
-rw-r--r--inc/mailgun/php-http/message/src/Encoding/DeflateStream.php38
-rw-r--r--inc/mailgun/php-http/message/src/Encoding/Filter/Chunk.php30
-rw-r--r--inc/mailgun/php-http/message/src/Encoding/FilteredStream.php198
-rw-r--r--inc/mailgun/php-http/message/src/Encoding/GzipDecodeStream.php42
-rw-r--r--inc/mailgun/php-http/message/src/Encoding/GzipEncodeStream.php42
-rw-r--r--inc/mailgun/php-http/message/src/Encoding/InflateStream.php42
-rw-r--r--inc/mailgun/php-http/message/src/Formatter.php32
-rw-r--r--inc/mailgun/php-http/message/src/Formatter/CurlCommandFormatter.php80
-rw-r--r--inc/mailgun/php-http/message/src/Formatter/FullHttpMessageFormatter.php91
-rw-r--r--inc/mailgun/php-http/message/src/Formatter/SimpleFormatter.php42
-rw-r--r--inc/mailgun/php-http/message/src/MessageFactory/DiactorosMessageFactory.php61
-rw-r--r--inc/mailgun/php-http/message/src/MessageFactory/GuzzleMessageFactory.php53
-rw-r--r--inc/mailgun/php-http/message/src/MessageFactory/SlimMessageFactory.php72
-rw-r--r--inc/mailgun/php-http/message/src/RequestMatcher.php26
-rw-r--r--inc/mailgun/php-http/message/src/RequestMatcher/CallbackRequestMatcher.php35
-rw-r--r--inc/mailgun/php-http/message/src/RequestMatcher/RegexRequestMatcher.php41
-rw-r--r--inc/mailgun/php-http/message/src/RequestMatcher/RequestMatcher.php78
-rw-r--r--inc/mailgun/php-http/message/src/Stream/BufferedStream.php270
-rw-r--r--inc/mailgun/php-http/message/src/StreamFactory/DiactorosStreamFactory.php36
-rw-r--r--inc/mailgun/php-http/message/src/StreamFactory/GuzzleStreamFactory.php21
-rw-r--r--inc/mailgun/php-http/message/src/StreamFactory/SlimStreamFactory.php37
-rw-r--r--inc/mailgun/php-http/message/src/UriFactory/DiactorosUriFactory.php29
-rw-r--r--inc/mailgun/php-http/message/src/UriFactory/GuzzleUriFactory.php22
-rw-r--r--inc/mailgun/php-http/message/src/UriFactory/SlimUriFactory.php31
-rw-r--r--inc/mailgun/php-http/message/src/filters.php6
51 files changed, 3729 insertions, 0 deletions
diff --git a/inc/mailgun/php-http/message/CHANGELOG.md b/inc/mailgun/php-http/message/CHANGELOG.md
new file mode 100644
index 0000000..4113311
--- /dev/null
+++ b/inc/mailgun/php-http/message/CHANGELOG.md
@@ -0,0 +1,131 @@
+# Change Log
+
+
+## Unreleased
+
+## 1.5.0 - 2017-02-14
+
+### Added
+
+- Check for empty string in Stream factories
+- Cookie::createWithoutValidation Static constructor to create a cookie. Will not perform any attribute validation during instantiation.
+- Cookie::isValid Method to check if cookie attributes are valid.
+
+### Fixed
+
+- FilteredStream::getSize returns null because the contents size is unknown.
+- Stream factories does not rewinds streams. The previous behavior was not coherent between factories and inputs.
+
+### Deprecated
+
+- FilteredStream::getReadFilter The read filter is internal and should never be used by consuming code.
+- FilteredStream::getWriteFilter We did not implement writing to the streams at all. And if we do, the filter is an internal information and should not be used by consuming code.
+
+
+## 1.4.1 - 2016-12-16
+
+### Fixed
+
+- Cookie::matchPath Cookie with root path (`/`) will not match sub path (e.g. `/cookie`).
+
+
+## 1.4.0 - 2016-10-20
+
+### Added
+
+- Message, stream and URI factories for [Slim Framework](https://github.com/slimphp/Slim)
+- BufferedStream that allow you to decorate a non-seekable stream with a seekable one.
+- cUrlFormatter to be able to redo the request with a cURL command
+
+
+## 1.3.1 - 2016-07-15
+
+### Fixed
+
+- FullHttpMessageFormatter will not read from streams that you cannot rewind (non-seekable)
+- FullHttpMessageFormatter will not read from the stream if $maxBodyLength is zero
+- FullHttpMessageFormatter rewinds streams after they are read
+
+
+## 1.3.0 - 2016-07-14
+
+### Added
+
+- FullHttpMessageFormatter to include headers and body in the formatted message
+
+### Fixed
+
+- #41: Response builder broke header value
+
+
+## 1.2.0 - 2016-03-29
+
+### Added
+
+- The RequestMatcher is built after the Symfony RequestMatcher and separates
+ scheme, host and path expressions and provides an option to filter on the
+ method
+- New RequestConditional authentication method using request matchers
+- Add automatic basic auth info detection based on the URL
+
+### Changed
+
+- Improved ResponseBuilder
+
+### Deprecated
+
+- RegexRequestMatcher, use RequestMatcher instead
+- Matching authenitcation method, use RequestConditional instead
+
+
+## 1.1.0 - 2016-02-25
+
+### Added
+
+ - Add a request matcher interface and regex implementation
+ - Add a callback request matcher implementation
+ - Add a ResponseBuilder, to create PSR7 Response from a string
+
+### Fixed
+
+ - Fix casting string on a FilteredStream not filtering the output
+
+
+## 1.0.0 - 2016-01-27
+
+
+## 0.2.0 - 2015-12-29
+
+### Added
+
+- Autoregistration of stream filters using Composer autoload
+- Cookie
+- [Apigen](http://www.apigen.org/) configuration
+
+
+## 0.1.2 - 2015-12-26
+
+### Added
+
+- Request and response factory bindings
+
+### Fixed
+
+- Chunk filter namespace in Dechunk stream
+
+
+## 0.1.1 - 2015-12-25
+
+### Added
+
+- Formatter
+
+
+## 0.1.0 - 2015-12-24
+
+### Added
+
+- Authentication
+- Encoding
+- Message decorator
+- Message factory (Guzzle, Diactoros)
diff --git a/inc/mailgun/php-http/message/LICENSE b/inc/mailgun/php-http/message/LICENSE
new file mode 100644
index 0000000..4558d6f
--- /dev/null
+++ b/inc/mailgun/php-http/message/LICENSE
@@ -0,0 +1,19 @@
+Copyright (c) 2015-2016 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/message/README.md b/inc/mailgun/php-http/message/README.md
new file mode 100644
index 0000000..338b415
--- /dev/null
+++ b/inc/mailgun/php-http/message/README.md
@@ -0,0 +1,61 @@
+# HTTP Message
+
+[![Latest Version](https://img.shields.io/github/release/php-http/message.svg?style=flat-square)](https://github.com/php-http/message/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/message.svg?style=flat-square)](https://travis-ci.org/php-http/message)
+[![Code Coverage](https://img.shields.io/scrutinizer/coverage/g/php-http/message.svg?style=flat-square)](https://scrutinizer-ci.com/g/php-http/message)
+[![Quality Score](https://img.shields.io/scrutinizer/g/php-http/message.svg?style=flat-square)](https://scrutinizer-ci.com/g/php-http/message)
+[![Total Downloads](https://img.shields.io/packagist/dt/php-http/message.svg?style=flat-square)](https://packagist.org/packages/php-http/message)
+
+**HTTP Message related tools.**
+
+
+## Install
+
+Via Composer
+
+``` bash
+$ composer require php-http/message
+```
+
+
+## Intro
+
+This package contains various PSR-7 tools which might be useful in an HTTP workflow:
+
+- Authentication method implementations
+- Various Stream encoding tools
+- Message decorators
+- Message factory implementations for Guzzle PSR-7 and Diactoros
+- Cookie implementation
+- Request matchers
+
+
+## Documentation
+
+Please see the [official documentation](http://docs.php-http.org/en/latest/message.html).
+
+
+## Testing
+
+``` bash
+$ composer test
+```
+
+
+## Contributing
+
+Please see our [contributing guide](http://docs.php-http.org/en/latest/development/contributing.html).
+
+## Cretids
+
+Thanks to [Cuzzle](https://github.com/namshi/cuzzle) for inpiration for the `CurlCommandFormatter`.
+
+## 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/message/apigen.neon b/inc/mailgun/php-http/message/apigen.neon
new file mode 100644
index 0000000..0ba1a18
--- /dev/null
+++ b/inc/mailgun/php-http/message/apigen.neon
@@ -0,0 +1,6 @@
+source:
+ - src/
+
+destination: build/api/
+
+templateTheme: bootstrap
diff --git a/inc/mailgun/php-http/message/composer.json b/inc/mailgun/php-http/message/composer.json
new file mode 100644
index 0000000..2a0fa45
--- /dev/null
+++ b/inc/mailgun/php-http/message/composer.json
@@ -0,0 +1,57 @@
+{
+ "name": "php-http/message",
+ "description": "HTTP Message related tools",
+ "license": "MIT",
+ "keywords": ["message", "http", "psr-7"],
+ "homepage": "http://php-http.org",
+ "authors": [
+ {
+ "name": "Márk Sági-Kazár",
+ "email": "mark.sagikazar@gmail.com"
+ }
+ ],
+ "require": {
+ "php": ">=5.4",
+ "psr/http-message": "^1.0",
+ "php-http/message-factory": "^1.0.2",
+ "clue/stream-filter": "^1.3"
+ },
+ "require-dev": {
+ "zendframework/zend-diactoros": "^1.0",
+ "guzzlehttp/psr7": "^1.0",
+ "ext-zlib": "*",
+ "phpspec/phpspec": "^2.4",
+ "henrikbjorn/phpspec-code-coverage" : "^1.0",
+ "coduo/phpspec-data-provider-extension": "^1.0",
+ "akeneo/phpspec-skip-example-extension": "^1.0",
+ "slim/slim": "^3.0"
+ },
+ "suggest": {
+ "zendframework/zend-diactoros": "Used with Diactoros Factories",
+ "guzzlehttp/psr7": "Used with Guzzle PSR-7 Factories",
+ "slim/slim": "Used with Slim Framework PSR-7 implementation",
+ "ext-zlib": "Used with compressor/decompressor streams"
+ },
+ "autoload": {
+ "psr-4": {
+ "Http\\Message\\": "src/"
+ },
+ "files": [
+ "src/filters.php"
+ ]
+ },
+ "autoload-dev": {
+ "psr-4": {
+ "spec\\Http\\Message\\": "spec/"
+ }
+ },
+ "scripts": {
+ "test": "vendor/bin/phpspec run",
+ "test-ci": "vendor/bin/phpspec run -c phpspec.ci.yml"
+ },
+ "extra": {
+ "branch-alias": {
+ "dev-master": "1.6-dev"
+ }
+ }
+}
diff --git a/inc/mailgun/php-http/message/puli.json b/inc/mailgun/php-http/message/puli.json
new file mode 100644
index 0000000..024a85d
--- /dev/null
+++ b/inc/mailgun/php-http/message/puli.json
@@ -0,0 +1,111 @@
+{
+ "version": "1.0",
+ "name": "php-http/message",
+ "bindings": {
+ "064d003d-78a1-48c4-8f3b-1f92ff25da69": {
+ "_class": "Puli\\Discovery\\Binding\\ClassBinding",
+ "class": "Http\\Message\\MessageFactory\\DiactorosMessageFactory",
+ "type": "Http\\Message\\MessageFactory",
+ "parameters": {
+ "depends": "Zend\\Diactoros\\Request"
+ }
+ },
+ "0836751e-6558-4d1b-8993-4a52012947c3": {
+ "_class": "Puli\\Discovery\\Binding\\ClassBinding",
+ "class": "Http\\Message\\MessageFactory\\SlimMessageFactory",
+ "type": "Http\\Message\\ResponseFactory"
+ },
+ "1d127622-dc61-4bfa-b9da-d221548d72c3": {
+ "_class": "Puli\\Discovery\\Binding\\ClassBinding",
+ "class": "Http\\Message\\MessageFactory\\SlimMessageFactory",
+ "type": "Http\\Message\\RequestFactory"
+ },
+ "2438c2d0-0658-441f-8855-ddaf0f87d54d": {
+ "_class": "Puli\\Discovery\\Binding\\ClassBinding",
+ "class": "Http\\Message\\MessageFactory\\GuzzleMessageFactory",
+ "type": "Http\\Message\\MessageFactory",
+ "parameters": {
+ "depends": "GuzzleHttp\\Psr7\\Request"
+ }
+ },
+ "253aa08c-d705-46e7-b1d2-e28c97eef792": {
+ "_class": "Puli\\Discovery\\Binding\\ClassBinding",
+ "class": "Http\\Message\\MessageFactory\\GuzzleMessageFactory",
+ "type": "Http\\Message\\RequestFactory",
+ "parameters": {
+ "depends": "GuzzleHttp\\Psr7\\Request"
+ }
+ },
+ "273a34f9-62f4-4ba1-9801-b1284d49ff89": {
+ "_class": "Puli\\Discovery\\Binding\\ClassBinding",
+ "class": "Http\\Message\\StreamFactory\\GuzzleStreamFactory",
+ "type": "Http\\Message\\StreamFactory",
+ "parameters": {
+ "depends": "GuzzleHttp\\Psr7\\Stream"
+ }
+ },
+ "304b83db-b594-4d83-ae75-1f633adf92f7": {
+ "_class": "Puli\\Discovery\\Binding\\ClassBinding",
+ "class": "Http\\Message\\UriFactory\\GuzzleUriFactory",
+ "type": "Http\\Message\\UriFactory",
+ "parameters": {
+ "depends": "GuzzleHttp\\Psr7\\Uri"
+ }
+ },
+ "3f4bc1cd-aa95-4702-9fa7-65408e471691": {
+ "_class": "Puli\\Discovery\\Binding\\ClassBinding",
+ "class": "Http\\Message\\UriFactory\\DiactorosUriFactory",
+ "type": "Http\\Message\\UriFactory",
+ "parameters": {
+ "depends": "Zend\\Diactoros\\Uri"
+ }
+ },
+ "4672a6ee-ad9e-4109-a5d1-b7d46f26c7a1": {
+ "_class": "Puli\\Discovery\\Binding\\ClassBinding",
+ "class": "Http\\Message\\MessageFactory\\SlimMessageFactory",
+ "type": "Http\\Message\\MessageFactory"
+ },
+ "6234e947-d3bd-43eb-97d5-7f9e22e6bb1b": {
+ "_class": "Puli\\Discovery\\Binding\\ClassBinding",
+ "class": "Http\\Message\\MessageFactory\\DiactorosMessageFactory",
+ "type": "Http\\Message\\ResponseFactory",
+ "parameters": {
+ "depends": "Zend\\Diactoros\\Response"
+ }
+ },
+ "6a9ad6ce-d82c-470f-8e30-60f21d9d95bf": {
+ "_class": "Puli\\Discovery\\Binding\\ClassBinding",
+ "class": "Http\\Message\\UriFactory\\SlimUriFactory",
+ "type": "Http\\Message\\UriFactory"
+ },
+ "72c2afa0-ea56-4d03-adb6-a9f241a8a734": {
+ "_class": "Puli\\Discovery\\Binding\\ClassBinding",
+ "class": "Http\\Message\\StreamFactory\\SlimStreamFactory",
+ "type": "Http\\Message\\StreamFactory"
+ },
+ "95c1be8f-39fe-4abd-8351-92cb14379a75": {
+ "_class": "Puli\\Discovery\\Binding\\ClassBinding",
+ "class": "Http\\Message\\StreamFactory\\DiactorosStreamFactory",
+ "type": "Http\\Message\\StreamFactory",
+ "parameters": {
+ "depends": "Zend\\Diactoros\\Stream"
+ }
+ },
+ "a018af27-7590-4dcf-83a1-497f95604cd6": {
+ "_class": "Puli\\Discovery\\Binding\\ClassBinding",
+ "class": "Http\\Message\\MessageFactory\\GuzzleMessageFactory",
+ "type": "Http\\Message\\ResponseFactory",
+ "parameters": {
+ "depends": "GuzzleHttp\\Psr7\\Response"
+ }
+ },
+ "c07955b1-de46-43db-923b-d07fae9382cb": {
+ "_class": "Puli\\Discovery\\Binding\\ClassBinding",
+ "class": "Http\\Message\\MessageFactory\\DiactorosMessageFactory",
+ "type": "Http\\Message\\RequestFactory",
+ "parameters": {
+ "depends": "Zend\\Diactoros\\Request"
+ }
+ }
+ }
+}
diff --git a/inc/mailgun/php-http/message/src/Authentication.php b/inc/mailgun/php-http/message/src/Authentication.php
new file mode 100644
index 0000000..b50366f
--- /dev/null
+++ b/inc/mailgun/php-http/message/src/Authentication.php
@@ -0,0 +1,22 @@
+<?php
+
+namespace Http\Message;
+
+use Psr\Http\Message\RequestInterface;
+
+/**
+ * Authenticate a PSR-7 Request.
+ *
+ * @author Márk Sági-Kazár <mark.sagikazar@gmail.com>
+ */
+interface Authentication
+{
+ /**
+ * Authenticates a request.
+ *
+ * @param RequestInterface $request
+ *
+ * @return RequestInterface
+ */
+ public function authenticate(RequestInterface $request);
+}
diff --git a/inc/mailgun/php-http/message/src/Authentication/AutoBasicAuth.php b/inc/mailgun/php-http/message/src/Authentication/AutoBasicAuth.php
new file mode 100644
index 0000000..7b6a429
--- /dev/null
+++ b/inc/mailgun/php-http/message/src/Authentication/AutoBasicAuth.php
@@ -0,0 +1,48 @@
+<?php
+
+namespace Http\Message\Authentication;
+
+use Http\Message\Authentication;
+use Psr\Http\Message\RequestInterface;
+
+/**
+ * Authenticate a PSR-7 Request using Basic Auth based on credentials in the URI.
+ *
+ * @author Márk Sági-Kazár <mark.sagikazar@gmail.com>
+ */
+final class AutoBasicAuth implements Authentication
+{
+ /**
+ * Whether user info should be removed from the URI.
+ *
+ * @var bool
+ */
+ private $shouldRemoveUserInfo;
+
+ /**
+ * @param bool|true $shouldRremoveUserInfo
+ */
+ public function __construct($shouldRremoveUserInfo = true)
+ {
+ $this->shouldRemoveUserInfo = (bool) $shouldRremoveUserInfo;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function authenticate(RequestInterface $request)
+ {
+ $uri = $request->getUri();
+ $userInfo = $uri->getUserInfo();
+
+ if (!empty($userInfo)) {
+ if ($this->shouldRemoveUserInfo) {
+ $request = $request->withUri($uri->withUserInfo(''));
+ }
+
+ $request = $request->withHeader('Authorization', sprintf('Basic %s', base64_encode($userInfo)));
+ }
+
+ return $request;
+ }
+}
diff --git a/inc/mailgun/php-http/message/src/Authentication/BasicAuth.php b/inc/mailgun/php-http/message/src/Authentication/BasicAuth.php
new file mode 100644
index 0000000..23618a5
--- /dev/null
+++ b/inc/mailgun/php-http/message/src/Authentication/BasicAuth.php
@@ -0,0 +1,44 @@
+<?php
+
+namespace Http\Message\Authentication;
+
+use Http\Message\Authentication;
+use Psr\Http\Message\RequestInterface;
+
+/**
+ * Authenticate a PSR-7 Request using Basic Auth.
+ *
+ * @author Márk Sági-Kazár <mark.sagikazar@gmail.com>
+ */
+final class BasicAuth implements Authentication
+{
+ /**
+ * @var string
+ */
+ private $username;
+
+ /**
+ * @var string
+ */
+ private $password;
+
+ /**
+ * @param string $username
+ * @param string $password
+ */
+ public function __construct($username, $password)
+ {
+ $this->username = $username;
+ $this->password = $password;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function authenticate(RequestInterface $request)
+ {
+ $header = sprintf('Basic %s', base64_encode(sprintf('%s:%s', $this->username, $this->password)));
+
+ return $request->withHeader('Authorization', $header);
+ }
+}
diff --git a/inc/mailgun/php-http/message/src/Authentication/Bearer.php b/inc/mailgun/php-http/message/src/Authentication/Bearer.php
new file mode 100644
index 0000000..a8fb21a
--- /dev/null
+++ b/inc/mailgun/php-http/message/src/Authentication/Bearer.php
@@ -0,0 +1,37 @@
+<?php
+
+namespace Http\Message\Authentication;
+
+use Http\Message\Authentication;
+use Psr\Http\Message\RequestInterface;
+
+/**
+ * Authenticate a PSR-7 Request using a token.
+ *
+ * @author Márk Sági-Kazár <mark.sagikazar@gmail.com>
+ */
+final class Bearer implements Authentication
+{
+ /**
+ * @var string
+ */
+ private $token;
+
+ /**
+ * @param string $token
+ */
+ public function __construct($token)
+ {
+ $this->token = $token;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function authenticate(RequestInterface $request)
+ {
+ $header = sprintf('Bearer %s', $this->token);
+
+ return $request->withHeader('Authorization', $header);
+ }
+}
diff --git a/inc/mailgun/php-http/message/src/Authentication/Chain.php b/inc/mailgun/php-http/message/src/Authentication/Chain.php
new file mode 100644
index 0000000..71002bb
--- /dev/null
+++ b/inc/mailgun/php-http/message/src/Authentication/Chain.php
@@ -0,0 +1,47 @@
+<?php
+
+namespace Http\Message\Authentication;
+
+use Http\Message\Authentication;
+use Psr\Http\Message\RequestInterface;
+
+/**
+ * Authenticate a PSR-7 Request with a multiple authentication methods.
+ *
+ * @author Márk Sági-Kazár <mark.sagikazar@gmail.com>
+ */
+final class Chain implements Authentication
+{
+ /**
+ * @var Authentication[]
+ */
+ private $authenticationChain = [];
+
+ /**
+ * @param Authentication[] $authenticationChain
+ */
+ public function __construct(array $authenticationChain = [])
+ {
+ foreach ($authenticationChain as $authentication) {
+ if (!$authentication instanceof Authentication) {
+ throw new \InvalidArgumentException(
+ 'Members of the authentication chain must be of type Http\Message\Authentication'
+ );
+ }
+ }
+
+ $this->authenticationChain = $authenticationChain;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function authenticate(RequestInterface $request)
+ {
+ foreach ($this->authenticationChain as $authentication) {
+ $request = $authentication->authenticate($request);
+ }
+
+ return $request;
+ }
+}
diff --git a/inc/mailgun/php-http/message/src/Authentication/Matching.php b/inc/mailgun/php-http/message/src/Authentication/Matching.php
new file mode 100644
index 0000000..4b89b50
--- /dev/null
+++ b/inc/mailgun/php-http/message/src/Authentication/Matching.php
@@ -0,0 +1,74 @@
+<?php
+
+namespace Http\Message\Authentication;
+
+use Http\Message\Authentication;
+use Http\Message\RequestMatcher\CallbackRequestMatcher;
+use Psr\Http\Message\RequestInterface;
+
+@trigger_error('The '.__NAMESPACE__.'\Matching class is deprecated since version 1.2 and will be removed in 2.0. Use Http\Message\Authentication\RequestConditional instead.', E_USER_DEPRECATED);
+
+/**
+ * Authenticate a PSR-7 Request if the request is matching.
+ *
+ * @author Márk Sági-Kazár <mark.sagikazar@gmail.com>
+ *
+ * @deprecated since since version 1.2, and will be removed in 2.0. Use {@link RequestConditional} instead.
+ */
+final class Matching implements Authentication
+{
+ /**
+ * @var Authentication
+ */
+ private $authentication;
+
+ /**
+ * @var CallbackRequestMatcher
+ */
+ private $matcher;
+
+ /**
+ * @param Authentication $authentication
+ * @param callable|null $matcher
+ */
+ public function __construct(Authentication $authentication, callable $matcher = null)
+ {
+ if (is_null($matcher)) {
+ $matcher = function () {
+ return true;
+ };
+ }
+
+ $this->authentication = $authentication;
+ $this->matcher = new CallbackRequestMatcher($matcher);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function authenticate(RequestInterface $request)
+ {
+ if ($this->matcher->matches($request)) {
+ return $this->authentication->authenticate($request);
+ }
+
+ return $request;
+ }
+
+ /**
+ * Creates a matching authentication for an URL.
+ *
+ * @param Authentication $authentication
+ * @param string $url
+ *
+ * @return self
+ */
+ public static function createUrlMatcher(Authentication $authentication, $url)
+ {
+ $matcher = function (RequestInterface $request) use ($url) {
+ return preg_match($url, $request->getRequestTarget());
+ };
+
+ return new static($authentication, $matcher);
+ }
+}
diff --git a/inc/mailgun/php-http/message/src/Authentication/QueryParam.php b/inc/mailgun/php-http/message/src/Authentication/QueryParam.php
new file mode 100644
index 0000000..14b58ff
--- /dev/null
+++ b/inc/mailgun/php-http/message/src/Authentication/QueryParam.php
@@ -0,0 +1,50 @@
+<?php
+
+namespace Http\Message\Authentication;
+
+use Http\Message\Authentication;
+use Psr\Http\Message\RequestInterface;
+
+/**
+ * Authenticate a PSR-7 Request by adding parameters to its query.
+ *
+ * Note: Although in some cases it can be useful, we do not recommend using query parameters for authentication.
+ * Credentials in the URL is generally unsafe as they are not encrypted, anyone can see them.
+ *
+ * @author Márk Sági-Kazár <mark.sagikazar@gmail.com>
+ */
+final class QueryParam implements Authentication
+{
+ /**
+ * @var array
+ */
+ private $params = [];
+
+ /**
+ * @param array $params
+ */
+ public function __construct(array $params)
+ {
+ $this->params = $params;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function authenticate(RequestInterface $request)
+ {
+ $uri = $request->getUri();
+ $query = $uri->getQuery();
+ $params = [];
+
+ parse_str($query, $params);
+
+ $params = array_merge($params, $this->params);
+
+ $query = http_build_query($params);
+
+ $uri = $uri->withQuery($query);
+
+ return $request->withUri($uri);
+ }
+}
diff --git a/inc/mailgun/php-http/message/src/Authentication/RequestConditional.php b/inc/mailgun/php-http/message/src/Authentication/RequestConditional.php
new file mode 100644
index 0000000..5477440
--- /dev/null
+++ b/inc/mailgun/php-http/message/src/Authentication/RequestConditional.php
@@ -0,0 +1,47 @@
+<?php
+
+namespace Http\Message\Authentication;
+
+use Http\Message\Authentication;
+use Http\Message\RequestMatcher;
+use Psr\Http\Message\RequestInterface;
+
+/**
+ * Authenticate a PSR-7 Request if the request is matching the given request matcher.
+ *
+ * @author Márk Sági-Kazár <mark.sagikazar@gmail.com>
+ */
+final class RequestConditional implements Authentication
+{
+ /**
+ * @var RequestMatcher
+ */
+ private $requestMatcher;
+
+ /**
+ * @var Authentication
+ */
+ private $authentication;
+
+ /**
+ * @param RequestMatcher $requestMatcher
+ * @param Authentication $authentication
+ */
+ public function __construct(RequestMatcher $requestMatcher, Authentication $authentication)
+ {
+ $this->requestMatcher = $requestMatcher;
+ $this->authentication = $authentication;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function authenticate(RequestInterface $request)
+ {
+ if ($this->requestMatcher->matches($request)) {
+ return $this->authentication->authenticate($request);
+ }
+
+ return $request;
+ }
+}
diff --git a/inc/mailgun/php-http/message/src/Authentication/Wsse.php b/inc/mailgun/php-http/message/src/Authentication/Wsse.php
new file mode 100644
index 0000000..fbbde33
--- /dev/null
+++ b/inc/mailgun/php-http/message/src/Authentication/Wsse.php
@@ -0,0 +1,58 @@
+<?php
+
+namespace Http\Message\Authentication;
+
+use Http\Message\Authentication;
+use Psr\Http\Message\RequestInterface;
+
+/**
+ * Authenticate a PSR-7 Request using WSSE.
+ *
+ * @author Márk Sági-Kazár <mark.sagikazar@gmail.com>
+ */
+final class Wsse implements Authentication
+{
+ /**
+ * @var string
+ */
+ private $username;
+
+ /**
+ * @var string
+ */
+ private $password;
+
+ /**
+ * @param string $username
+ * @param string $password
+ */
+ public function __construct($username, $password)
+ {
+ $this->username = $username;
+ $this->password = $password;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function authenticate(RequestInterface $request)
+ {
+ // TODO: generate better nonce?
+ $nonce = substr(md5(uniqid(uniqid().'_', true)), 0, 16);
+ $created = date('c');
+ $digest = base64_encode(sha1(base64_decode($nonce).$created.$this->password, true));
+
+ $wsse = sprintf(
+ 'UsernameToken Username="%s", PasswordDigest="%s", Nonce="%s", Created="%s"',
+ $this->username,
+ $digest,
+ $nonce,
+ $created
+ );
+
+ return $request
+ ->withHeader('Authorization', 'WSSE profile="UsernameToken"')
+ ->withHeader('X-WSSE', $wsse)
+ ;
+ }
+}
diff --git a/inc/mailgun/php-http/message/src/Builder/ResponseBuilder.php b/inc/mailgun/php-http/message/src/Builder/ResponseBuilder.php
new file mode 100644
index 0000000..e6933a0
--- /dev/null
+++ b/inc/mailgun/php-http/message/src/Builder/ResponseBuilder.php
@@ -0,0 +1,148 @@
+<?php
+
+namespace Http\Message\Builder;
+
+use Psr\Http\Message\ResponseInterface;
+
+/**
+ * Fills response object with values.
+ */
+class ResponseBuilder
+{
+ /**
+ * The response to be built.
+ *
+ * @var ResponseInterface
+ */
+ protected $response;
+
+ /**
+ * Create builder for the given response.
+ *
+ * @param ResponseInterface $response
+ */
+ public function __construct(ResponseInterface $response)
+ {
+ $this->response = $response;
+ }
+
+ /**
+ * Return response.
+ *
+ * @return ResponseInterface
+ */
+ public function getResponse()
+ {
+ return $this->response;
+ }
+
+ /**
+ * Add headers represented by an array of header lines.
+ *
+ * @param string[] $headers Response headers as array of header lines.
+ *
+ * @return $this
+ *
+ * @throws \UnexpectedValueException For invalid header values.
+ * @throws \InvalidArgumentException For invalid status code arguments.
+ */
+ public function setHeadersFromArray(array $headers)
+ {
+ $status = array_shift($headers);
+ $this->setStatus($status);
+
+ foreach ($headers as $headerLine) {
+ $headerLine = trim($headerLine);
+ if ('' === $headerLine) {
+ continue;
+ }
+
+ $this->addHeader($headerLine);
+ }
+
+ return $this;
+ }
+
+ /**
+ * Add headers represented by a single string.
+ *
+ * @param string $headers Response headers as single string.
+ *
+ * @return $this
+ *
+ * @throws \InvalidArgumentException if $headers is not a string on object with __toString()
+ * @throws \UnexpectedValueException For invalid header values.
+ */
+ public function setHeadersFromString($headers)
+ {
+ if (!(is_string($headers)
+ || (is_object($headers) && method_exists($headers, '__toString')))
+ ) {
+ throw new \InvalidArgumentException(
+ sprintf(
+ '%s expects parameter 1 to be a string, %s given',
+ __METHOD__,
+ is_object($headers) ? get_class($headers) : gettype($headers)
+ )
+ );
+ }
+
+ $this->setHeadersFromArray(explode("\r\n", $headers));
+
+ return $this;
+ }
+
+ /**
+ * Set response status from a status string.
+ *
+ * @param string $statusLine Response status as a string.
+ *
+ * @return $this
+ *
+ * @throws \InvalidArgumentException For invalid status line.
+ */
+ public function setStatus($statusLine)
+ {
+ $parts = explode(' ', $statusLine, 3);
+ if (count($parts) < 2 || strpos(strtolower($parts[0]), 'http/') !== 0) {
+ throw new \InvalidArgumentException(
+ sprintf('"%s" is not a valid HTTP status line', $statusLine)
+ );
+ }
+
+ $reasonPhrase = count($parts) > 2 ? $parts[2] : '';
+ $this->response = $this->response
+ ->withStatus((int) $parts[1], $reasonPhrase)
+ ->withProtocolVersion(substr($parts[0], 5));
+
+ return $this;
+ }
+
+ /**
+ * Add header represented by a string.
+ *
+ * @param string $headerLine Response header as a string.
+ *
+ * @return $this
+ *
+ * @throws \InvalidArgumentException For invalid header names or values.
+ */
+ public function addHeader($headerLine)
+ {
+ $parts = explode(':', $headerLine, 2);
+ if (count($parts) !== 2) {
+ throw new \InvalidArgumentException(
+ sprintf('"%s" is not a valid HTTP header line', $headerLine)
+ );
+ }
+ $name = trim($parts[0]);
+ $value = trim($parts[1]);
+ if ($this->response->hasHeader($name)) {
+ $this->response = $this->response->withAddedHeader($name, $value);
+ } else {
+ $this->response = $this->response->withHeader($name, $value);
+ }
+
+ return $this;
+ }
+}
diff --git a/inc/mailgun/php-http/message/src/Cookie.php b/inc/mailgun/php-http/message/src/Cookie.php
new file mode 100644
index 0000000..5f61b90
--- /dev/null
+++ b/inc/mailgun/php-http/message/src/Cookie.php
@@ -0,0 +1,526 @@
+<?php
+
+namespace Http\Message;
+
+/**
+ * Cookie Value Object.
+ *
+ * @author Márk Sági-Kazár <mark.sagikazar@gmail.com>
+ *
+ * @see http://tools.ietf.org/search/rfc6265
+ */
+final class Cookie
+{
+ /**
+ * @var string
+ */
+ private $name;
+
+ /**
+ * @var string|null
+ */
+ private $value;
+
+ /**
+ * @var int|null
+ */
+ private $maxAge;
+
+ /**
+ * @var string|null
+ */
+ private $domain;
+
+ /**
+ * @var string
+ */
+ private $path;
+
+ /**
+ * @var bool
+ */
+ private $secure;
+
+ /**
+ * @var bool
+ */
+ private $httpOnly;
+
+ /**
+ * Expires attribute is HTTP 1.0 only and should be avoided.
+ *
+ * @var \DateTime|null
+ */
+ private $expires;
+
+ /**
+ * @param string $name
+ * @param string|null $value
+ * @param int $maxAge
+ * @param string|null $domain
+ * @param string|null $path
+ * @param bool $secure
+ * @param bool $httpOnly
+ * @param \DateTime|null $expires Expires attribute is HTTP 1.0 only and should be avoided.
+ *
+ * @throws \InvalidArgumentException If name, value or max age is not valid.
+ */
+ public function __construct(
+ $name,
+ $value = null,
+ $maxAge = null,
+ $domain = null,
+ $path = null,
+ $secure = false,
+ $httpOnly = false,
+ \DateTime $expires = null
+ ) {
+ $this->validateName($name);
+ $this->validateValue($value);
+ $this->validateMaxAge($maxAge);
+
+ $this->name = $name;
+ $this->value = $value;
+ $this->maxAge = $maxAge;
+ $this->expires = $expires;
+ $this->domain = $this->normalizeDomain($domain);
+ $this->path = $this->normalizePath($path);
+ $this->secure = (bool) $secure;
+ $this->httpOnly = (bool) $httpOnly;
+ }
+
+ /**
+ * Creates a new cookie without any attribute validation.
+ *
+ * @param string $name
+ * @param string|null $value
+ * @param int $maxAge
+ * @param string|null $domain
+ * @param string|null $path
+ * @param bool $secure
+ * @param bool $httpOnly
+ * @param \DateTime|null $expires Expires attribute is HTTP 1.0 only and should be avoided.
+ */
+ public static function createWithoutValidation(
+ $name,
+ $value = null,
+ $maxAge = null,
+ $domain = null,
+ $path = null,
+ $secure = false,
+ $httpOnly = false,
+ \DateTime $expires = null
+ ) {
+ $cookie = new self('name', null, null, $domain, $path, $secure, $httpOnly, $expires);
+ $cookie->name = $name;
+ $cookie->value = $value;
+ $cookie->maxAge = $maxAge;
+
+ return $cookie;
+ }
+
+ /**
+ * Returns the name.
+ *
+ * @return string
+ */
+ public function getName()
+ {
+ return $this->name;
+ }
+
+ /**
+ * Returns the value.
+ *
+ * @return string|null
+ */
+ public function getValue()
+ {
+ return $this->value;
+ }
+
+ /**
+ * Checks if there is a value.
+ *
+ * @return bool
+ */
+ public function hasValue()
+ {
+ return isset($this->value);
+ }
+
+ /**
+ * Sets the value.
+ *
+ * @param string|null $value
+ *
+ * @return Cookie
+ */
+ public function withValue($value)
+ {
+ $this->validateValue($value);
+
+ $new = clone $this;
+ $new->value = $value;
+
+ return $new;
+ }
+
+ /**
+ * Returns the max age.
+ *
+ * @return int|null
+ */
+ public function getMaxAge()
+ {
+ return $this->maxAge;
+ }
+
+ /**
+ * Checks if there is a max age.
+ *
+ * @return bool
+ */
+ public function hasMaxAge()
+ {
+ return isset($this->maxAge);
+ }
+
+ /**
+ * Sets the max age.
+ *
+ * @param int|null $maxAge
+ *
+ * @return Cookie
+ */
+ public function withMaxAge($maxAge)
+ {
+ $this->validateMaxAge($maxAge);
+
+ $new = clone $this;
+ $new->maxAge = $maxAge;
+
+ return $new;
+ }
+
+ /**
+ * Returns the expiration time.
+ *
+ * @return \DateTime|null
+ */
+ public function getExpires()
+ {
+ return $this->expires;
+ }
+
+ /**
+ * Checks if there is an expiration time.
+ *
+ * @return bool
+ */
+ public function hasExpires()
+ {
+ return isset($this->expires);
+ }
+
+ /**
+ * Sets the expires.
+ *
+ * @param \DateTime|null $expires
+ *
+ * @return Cookie
+ */
+ public function withExpires(\DateTime $expires = null)
+ {
+ $new = clone $this;
+ $new->expires = $expires;
+
+ return $new;
+ }
+
+ /**
+ * Checks if the cookie is expired.
+ *
+ * @return bool
+ */
+ public function isExpired()
+ {
+ return isset($this->expires) and $this->expires < new \DateTime();
+ }
+
+ /**
+ * Returns the domain.
+ *
+ * @return string|null
+ */
+ public function getDomain()
+ {
+ return $this->domain;
+ }
+
+ /**
+ * Checks if there is a domain.
+ *
+ * @return bool
+ */
+ public function hasDomain()
+ {
+ return isset($this->domain);
+ }
+
+ /**
+ * Sets the domain.
+ *
+ * @param string|null $domain
+ *
+ * @return Cookie
+ */
+ public function withDomain($domain)
+ {
+ $new = clone $this;
+ $new->domain = $this->normalizeDomain($domain);
+
+ return $new;
+ }
+
+ /**
+ * Checks whether this cookie is meant for this domain.
+ *
+ * @see http://tools.ietf.org/html/rfc6265#section-5.1.3
+ *
+ * @param string $domain
+ *
+ * @return bool
+ */
+ public function matchDomain($domain)
+ {
+ // Domain is not set or exact match
+ if (!$this->hasDomain() || strcasecmp($domain, $this->domain) === 0) {
+ return true;
+ }
+
+ // Domain is not an IP address
+ if (filter_var($domain, FILTER_VALIDATE_IP)) {
+ return false;
+ }
+
+ return (bool) preg_match(sprintf('/\b%s$/i', preg_quote($this->domain)), $domain);
+ }
+
+ /**
+ * Returns the path.
+ *
+ * @return string
+ */
+ public function getPath()
+ {
+ return $this->path;
+ }
+
+ /**
+ * Sets the path.
+ *
+ * @param string|null $path
+ *
+ * @return Cookie
+ */
+ public function withPath($path)
+ {
+ $new = clone $this;
+ $new->path = $this->normalizePath($path);
+
+ return $new;
+ }
+
+ /**
+ * Checks whether this cookie is meant for this path.
+ *
+ * @see http://tools.ietf.org/html/rfc6265#section-5.1.4
+ *
+ * @param string $path
+ *
+ * @return bool
+ */
+ public function matchPath($path)
+ {
+ return $this->path === $path || (strpos($path, rtrim($this->path, '/').'/') === 0);
+ }
+
+ /**
+ * Checks whether this cookie may only be sent over HTTPS.
+ *
+ * @return bool
+ */
+ public function isSecure()
+ {
+ return $this->secure;
+ }
+
+ /**
+ * Sets whether this cookie should only be sent over HTTPS.
+ *
+ * @param bool $secure
+ *
+ * @return Cookie
+ */
+ public function withSecure($secure)
+ {
+ $new = clone $this;
+ $new->secure = (bool) $secure;
+
+ return $new;
+ }
+
+ /**
+ * Check whether this cookie may not be accessed through Javascript.
+ *
+ * @return bool
+ */
+ public function isHttpOnly()
+ {
+ return $this->httpOnly;
+ }
+
+ /**
+ * Sets whether this cookie may not be accessed through Javascript.
+ *
+ * @param bool $httpOnly
+ *
+ * @return Cookie
+ */
+ public function withHttpOnly($httpOnly)
+ {
+ $new = clone $this;
+ $new->httpOnly = (bool) $httpOnly;
+
+ return $new;
+ }
+
+ /**
+ * Checks if this cookie represents the same cookie as $cookie.
+ *
+ * This does not compare the values, only name, domain and path.
+ *
+ * @param Cookie $cookie
+ *
+ * @return bool
+ */
+ public function match(Cookie $cookie)
+ {
+ return $this->name === $cookie->name && $this->domain === $cookie->domain and $this->path === $cookie->path;
+ }
+
+ /**
+ * Validates cookie attributes.
+ *
+ * @return bool
+ */
+ public function isValid()
+ {
+ try {
+ $this->validateName($this->name);
+ $this->validateValue($this->value);
+ $this->validateMaxAge($this->maxAge);
+ } catch (\InvalidArgumentException $e) {
+ return false;
+ }
+
+ return true;
+ }
+
+ /**
+ * Validates the name attribute.
+ *
+ * @see http://tools.ietf.org/search/rfc2616#section-2.2
+ *
+ * @param string $name
+ *
+ * @throws \InvalidArgumentException If the name is empty or contains invalid characters.
+ */
+ private function validateName($name)
+ {
+ if (strlen($name) < 1) {
+ throw new \InvalidArgumentException('The name cannot be empty');
+ }
+
+ // Name attribute is a token as per spec in RFC 2616
+ if (preg_match('/[\x00-\x20\x22\x28-\x29\x2C\x2F\x3A-\x40\x5B-\x5D\x7B\x7D\x7F]/', $name)) {
+ throw new \InvalidArgumentException(sprintf('The cookie name "%s" contains invalid characters.', $name));
+ }
+ }
+
+ /**
+ * Validates a value.
+ *
+ * @see http://tools.ietf.org/html/rfc6265#section-4.1.1
+ *
+ * @param string|null $value
+ *
+ * @throws \InvalidArgumentException If the value contains invalid characters.
+ */
+ private function validateValue($value)
+ {
+ if (isset($value)) {
+ if (preg_match('/[^\x21\x23-\x2B\x2D-\x3A\x3C-\x5B\x5D-\x7E]/', $value)) {
+ throw new \InvalidArgumentException(sprintf('The cookie value "%s" contains invalid characters.', $value));
+ }
+ }
+ }
+
+ /**
+ * Validates a Max-Age attribute.
+ *
+ * @param int|null $maxAge
+ *
+ * @throws \InvalidArgumentException If the Max-Age is not an empty or integer value.
+ */
+ private function validateMaxAge($maxAge)
+ {
+ if (isset($maxAge)) {
+ if (!is_int($maxAge)) {
+ throw new \InvalidArgumentException('Max-Age must be integer');
+ }
+ }
+ }
+
+ /**
+ * Remove the leading '.' and lowercase the domain as per spec in RFC 6265.
+ *
+ * @see http://tools.ietf.org/html/rfc6265#section-4.1.2.3
+ * @see http://tools.ietf.org/html/rfc6265#section-5.1.3
+ * @see http://tools.ietf.org/html/rfc6265#section-5.2.3
+ *
+ * @param string|null $domain
+ *
+ * @return string
+ */
+ private function normalizeDomain($domain)
+ {
+ if (isset($domain)) {
+ $domain = ltrim(strtolower($domain), '.');
+ }
+
+ return $domain;
+ }
+
+ /**
+ * Processes path as per spec in RFC 6265.
+ *
+ * @see http://tools.ietf.org/html/rfc6265#section-5.1.4
+ * @see http://tools.ietf.org/html/rfc6265#section-5.2.4
+ *
+ * @param string|null $path
+ *
+ * @return string
+ */
+ private function normalizePath($path)
+ {
+ $path = rtrim($path, '/');
+
+ if (empty($path) or substr($path, 0, 1) !== '/') {
+ $path = '/';
+ }
+
+ return $path;
+ }
+}
diff --git a/inc/mailgun/php-http/message/src/CookieJar.php b/inc/mailgun/php-http/message/src/CookieJar.php
new file mode 100644
index 0000000..ab267d3
--- /dev/null
+++ b/inc/mailgun/php-http/message/src/CookieJar.php
@@ -0,0 +1,220 @@
+<?php
+
+namespace Http\Message;
+
+/**
+ * Cookie Jar holds a set of Cookies.
+ *
+ * @author Márk Sági-Kazár <mark.sagikazar@gmail.com>
+ */
+final class CookieJar implements \Countable, \IteratorAggregate
+{
+ /**
+ * @var \SplObjectStorage
+ */
+ protected $cookies;
+
+ public function __construct()
+ {
+ $this->cookies = new \SplObjectStorage();
+ }
+
+ /**
+ * Checks if there is a cookie.
+ *
+ * @param Cookie $cookie
+ *
+ * @return bool
+ */
+ public function hasCookie(Cookie $cookie)
+ {
+ return $this->cookies->contains($cookie);
+ }
+
+ /**
+ * Adds a cookie.
+ *
+ * @param Cookie $cookie
+ */
+ public function addCookie(Cookie $cookie)
+ {
+ if (!$this->hasCookie($cookie)) {
+ $cookies = $this->getMatchingCookies($cookie);
+
+ foreach ($cookies as $matchingCookie) {
+ if ($cookie->getValue() !== $matchingCookie->getValue() || $cookie->getMaxAge() > $matchingCookie->getMaxAge()) {
+ $this->removeCookie($matchingCookie);
+
+ continue;
+ }
+ }
+
+ if ($cookie->hasValue()) {
+ $this->cookies->attach($cookie);
+ }
+ }
+ }
+
+ /**
+ * Removes a cookie.
+ *
+ * @param Cookie $cookie
+ */
+ public function removeCookie(Cookie $cookie)
+ {
+ $this->cookies->detach($cookie);
+ }
+
+ /**
+ * Returns the cookies.
+ *
+ * @return Cookie[]
+ */
+ public function getCookies()
+ {
+ $match = function ($matchCookie) {
+ return true;
+ };
+
+ return $this->findMatchingCookies($match);
+ }
+
+ /**
+ * Returns all matching cookies.
+ *
+ * @param Cookie $cookie
+ *
+ * @return Cookie[]
+ */
+ public function getMatchingCookies(Cookie $cookie)
+ {
+ $match = function ($matchCookie) use ($cookie) {
+ return $matchCookie->match($cookie);
+ };
+
+ return $this->findMatchingCookies($match);
+ }
+
+ /**
+ * Finds matching cookies based on a callable.
+ *
+ * @param callable $match
+ *
+ * @return Cookie[]
+ */
+ protected function findMatchingCookies(callable $match)
+ {
+ $cookies = [];
+
+ foreach ($this->cookies as $cookie) {
+ if ($match($cookie)) {
+ $cookies[] = $cookie;
+ }
+ }
+
+ return $cookies;
+ }
+
+ /**
+ * Checks if there are cookies.
+ *
+ * @return bool
+ */
+ public function hasCookies()
+ {
+ return $this->cookies->count() > 0;
+ }
+
+ /**
+ * Sets the cookies and removes any previous one.
+ *
+ * @param Cookie[] $cookies
+ */
+ public function setCookies(array $cookies)
+ {
+ $this->clear();
+ $this->addCookies($cookies);
+ }
+
+ /**
+ * Adds some cookies.
+ *
+ * @param Cookie[] $cookies
+ */
+ public function addCookies(array $cookies)
+ {
+ foreach ($cookies as $cookie) {
+ $this->addCookie($cookie);
+ }
+ }
+
+ /**
+ * Removes some cookies.
+ *
+ * @param Cookie[] $cookies
+ */
+ public function removeCookies(array $cookies)
+ {
+ foreach ($cookies as $cookie) {
+ $this->removeCookie($cookie);
+ }
+ }
+
+ /**
+ * Removes cookies which match the given parameters.
+ *
+ * Null means that parameter should not be matched
+ *
+ * @param string|null $name
+ * @param string|null $domain
+ * @param string|null $path
+ */
+ public function removeMatchingCookies($name = null, $domain = null, $path = null)
+ {
+ $match = function ($cookie) use ($name, $domain, $path) {
+ $match = true;
+
+ if (isset($name)) {
+ $match = $match && ($cookie->getName() === $name);
+ }
+
+ if (isset($domain)) {
+ $match = $match && $cookie->matchDomain($domain);
+ }
+
+ if (isset($path)) {
+ $match = $match && $cookie->matchPath($path);
+ }
+
+ return $match;
+ };
+
+ $cookies = $this->findMatchingCookies($match);
+
+ $this->removeCookies($cookies);
+ }
+
+ /**
+ * Removes all cookies.
+ */
+ public function clear()
+ {
+ $this->cookies = new \SplObjectStorage();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function count()
+ {
+ return $this->cookies->count();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getIterator()
+ {
+ return clone $this->cookies;
+ }
+}
diff --git a/inc/mailgun/php-http/message/src/Decorator/MessageDecorator.php b/inc/mailgun/php-http/message/src/Decorator/MessageDecorator.php
new file mode 100644
index 0000000..0ffc7ca
--- /dev/null
+++ b/inc/mailgun/php-http/message/src/Decorator/MessageDecorator.php
@@ -0,0 +1,133 @@
+<?php
+
+namespace Http\Message\Decorator;
+
+use Psr\Http\Message\MessageInterface;
+use Psr\Http\Message\StreamInterface;
+
+/**
+ * @author Márk Sági-Kazár <mark.sagikazar@gmail.com>
+ */
+trait MessageDecorator
+{
+ /**
+ * @var MessageInterface
+ */
+ private $message;
+
+ /**
+ * Returns the decorated message.
+ *
+ * Since the underlying Message is immutable as well
+ * exposing it is not an issue, because it's state cannot be altered
+ *
+ * @return MessageInterface
+ */
+ public function getMessage()
+ {
+ return $this->message;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getProtocolVersion()
+ {
+ return $this->message->getProtocolVersion();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function withProtocolVersion($version)
+ {
+ $new = clone $this;
+ $new->message = $this->message->withProtocolVersion($version);
+
+ return $new;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getHeaders()
+ {
+ return $this->message->getHeaders();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function hasHeader($header)
+ {
+ return $this->message->hasHeader($header);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getHeader($header)
+ {
+ return $this->message->getHeader($header);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getHeaderLine($header)
+ {
+ return $this->message->getHeaderLine($header);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function withHeader($header, $value)
+ {
+ $new = clone $this;
+ $new->message = $this->message->withHeader($header, $value);
+
+ return $new;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function withAddedHeader($header, $value)
+ {
+ $new = clone $this;
+ $new->message = $this->message->withAddedHeader($header, $value);
+
+ return $new;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function withoutHeader($header)
+ {
+ $new = clone $this;
+ $new->message = $this->message->withoutHeader($header);
+
+ return $new;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getBody()
+ {
+ return $this->message->getBody();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function withBody(StreamInterface $body)
+ {
+ $new = clone $this;
+ $new->message = $this->message->withBody($body);
+
+ return $new;
+ }
+}
diff --git a/inc/mailgun/php-http/message/src/Decorator/RequestDecorator.php b/inc/mailgun/php-http/message/src/Decorator/RequestDecorator.php
new file mode 100644
index 0000000..7c50e58
--- /dev/null
+++ b/inc/mailgun/php-http/message/src/Decorator/RequestDecorator.php
@@ -0,0 +1,88 @@
+<?php
+
+namespace Http\Message\Decorator;
+
+use Psr\Http\Message\RequestInterface;
+use Psr\Http\Message\UriInterface;
+
+/**
+ * @author Márk Sági-Kazár <mark.sagikazar@gmail.com>
+ */
+trait RequestDecorator
+{
+ use MessageDecorator {
+ getMessage as getRequest;
+ }
+
+ /**
+ * Exchanges the underlying request with another.
+ *
+ * @param RequestInterface $request
+ *
+ * @return self
+ */
+ public function withRequest(RequestInterface $request)
+ {
+ $new = clone $this;
+ $new->message = $request;
+
+ return $new;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getRequestTarget()
+ {
+ return $this->message->getRequestTarget();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function withRequestTarget($requestTarget)
+ {
+ $new = clone $this;
+ $new->message = $this->message->withRequestTarget($requestTarget);
+
+ return $new;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getMethod()
+ {
+ return $this->message->getMethod();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function withMethod($method)
+ {
+ $new = clone $this;
+ $new->message = $this->message->withMethod($method);
+
+ return $new;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getUri()
+ {
+ return $this->message->getUri();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function withUri(UriInterface $uri, $preserveHost = false)
+ {
+ $new = clone $this;
+ $new->message = $this->message->withUri($uri, $preserveHost);
+
+ return $new;
+ }
+}
diff --git a/inc/mailgun/php-http/message/src/Decorator/ResponseDecorator.php b/inc/mailgun/php-http/message/src/Decorator/ResponseDecorator.php
new file mode 100644
index 0000000..82d9ae0
--- /dev/null
+++ b/inc/mailgun/php-http/message/src/Decorator/ResponseDecorator.php
@@ -0,0 +1,57 @@
+<?php
+
+namespace Http\Message\Decorator;
+
+use Psr\Http\Message\ResponseInterface;
+
+/**
+ * @author Márk Sági-Kazár <mark.sagikazar@gmail.com>
+ */
+trait ResponseDecorator
+{
+ use MessageDecorator {
+ getMessage as getResponse;
+ }
+
+ /**
+ * Exchanges the underlying response with another.
+ *
+ * @param ResponseInterface $response
+ *
+ * @return self
+ */
+ public function withResponse(ResponseInterface $response)
+ {
+ $new = clone $this;
+ $new->message = $response;
+
+ return $new;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getStatusCode()
+ {
+ return $this->message->getStatusCode();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function withStatus($code, $reasonPhrase = '')
+ {
+ $new = clone $this;
+ $new->message = $this->message->withStatus($code, $reasonPhrase);
+
+ return $new;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getReasonPhrase()
+ {
+ return $this->message->getReasonPhrase();
+ }
+}
diff --git a/inc/mailgun/php-http/message/src/Decorator/StreamDecorator.php b/inc/mailgun/php-http/message/src/Decorator/StreamDecorator.php
new file mode 100644
index 0000000..f405c7a
--- /dev/null
+++ b/inc/mailgun/php-http/message/src/Decorator/StreamDecorator.php
@@ -0,0 +1,138 @@
+<?php
+
+namespace Http\Message\Decorator;
+
+use Psr\Http\Message\StreamInterface;
+
+/**
+ * Decorates a stream.
+ *
+ * @author Márk Sági-Kazár <mark.sagikazar@gmail.com>
+ */
+trait StreamDecorator
+{
+ /**
+ * @var StreamInterface
+ */
+ protected $stream;
+
+ /**
+ * {@inheritdoc}
+ */
+ public function __toString()
+ {
+ return $this->stream->__toString();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function close()
+ {
+ $this->stream->close();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function detach()
+ {
+ return $this->stream->detach();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getSize()
+ {
+ return $this->stream->getSize();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function tell()
+ {
+ return $this->stream->tell();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function eof()
+ {
+ return $this->stream->eof();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function isSeekable()
+ {
+ return $this->stream->isSeekable();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function seek($offset, $whence = SEEK_SET)
+ {
+ $this->stream->seek($offset, $whence);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function rewind()
+ {
+ $this->stream->rewind();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function isWritable()
+ {
+ return $this->stream->isWritable();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function write($string)
+ {
+ return $this->stream->write($string);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function isReadable()
+ {
+ return $this->stream->isReadable();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function read($length)
+ {
+ return $this->stream->read($length);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getContents()
+ {
+ return $this->stream->getContents();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getMetadata($key = null)
+ {
+ return $this->stream->getMetadata($key);
+ }
+}
diff --git a/inc/mailgun/php-http/message/src/Encoding/ChunkStream.php b/inc/mailgun/php-http/message/src/Encoding/ChunkStream.php
new file mode 100644
index 0000000..74c2fbd
--- /dev/null
+++ b/inc/mailgun/php-http/message/src/Encoding/ChunkStream.php
@@ -0,0 +1,39 @@
+<?php
+
+namespace Http\Message\Encoding;
+
+/**
+ * Transform a regular stream into a chunked one.
+ *
+ * @author Joel Wurtz <joel.wurtz@gmail.com>
+ */
+class ChunkStream extends FilteredStream
+{
+ /**
+ * {@inheritdoc}
+ */
+ protected function readFilter()
+ {
+ return 'chunk';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function writeFilter()
+ {
+ return 'dechunk';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function fill()
+ {
+ parent::fill();
+
+ if ($this->stream->eof()) {
+ $this->buffer .= "0\r\n\r\n";
+ }
+ }
+}
diff --git a/inc/mailgun/php-http/message/src/Encoding/CompressStream.php b/inc/mailgun/php-http/message/src/Encoding/CompressStream.php
new file mode 100644
index 0000000..d1013dc
--- /dev/null
+++ b/inc/mailgun/php-http/message/src/Encoding/CompressStream.php
@@ -0,0 +1,42 @@
+<?php
+
+namespace Http\Message\Encoding;
+
+use Psr\Http\Message\StreamInterface;
+
+/**
+ * Stream compress (RFC 1950).
+ *
+ * @author Joel Wurtz <joel.wurtz@gmail.com>
+ */
+class CompressStream extends FilteredStream
+{
+ /**
+ * @param StreamInterface $stream
+ * @param int $level
+ */
+ public function __construct(StreamInterface $stream, $level = -1)
+ {
+ if (!extension_loaded('zlib')) {
+ throw new \RuntimeException('The zlib extension must be enabled to use this stream');
+ }
+
+ parent::__construct($stream, ['window' => 15, 'level' => $level], ['window' => 15]);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function readFilter()
+ {
+ return 'zlib.deflate';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function writeFilter()
+ {
+ return 'zlib.inflate';
+ }
+}
diff --git a/inc/mailgun/php-http/message/src/Encoding/DechunkStream.php b/inc/mailgun/php-http/message/src/Encoding/DechunkStream.php
new file mode 100644
index 0000000..4cade83
--- /dev/null
+++ b/inc/mailgun/php-http/message/src/Encoding/DechunkStream.php
@@ -0,0 +1,29 @@
+<?php
+
+namespace Http\Message\Encoding;
+
+/**
+ * Decorate a stream which is chunked.
+ *
+ * Allow to decode a chunked stream
+ *
+ * @author Joel Wurtz <joel.wurtz@gmail.com>
+ */
+class DechunkStream extends FilteredStream
+{
+ /**
+ * {@inheritdoc}
+ */
+ protected function readFilter()
+ {
+ return 'dechunk';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function writeFilter()
+ {
+ return 'chunk';
+ }
+}
diff --git a/inc/mailgun/php-http/message/src/Encoding/DecompressStream.php b/inc/mailgun/php-http/message/src/Encoding/DecompressStream.php
new file mode 100644
index 0000000..4e3a723
--- /dev/null
+++ b/inc/mailgun/php-http/message/src/Encoding/DecompressStream.php
@@ -0,0 +1,42 @@
+<?php
+
+namespace Http\Message\Encoding;
+
+use Psr\Http\Message\StreamInterface;
+
+/**
+ * Stream decompress (RFC 1950).
+ *
+ * @author Joel Wurtz <joel.wurtz@gmail.com>
+ */
+class DecompressStream extends FilteredStream
+{
+ /**
+ * @param StreamInterface $stream
+ * @param int $level
+ */
+ public function __construct(StreamInterface $stream, $level = -1)
+ {
+ if (!extension_loaded('zlib')) {
+ throw new \RuntimeException('The zlib extension must be enabled to use this stream');
+ }
+
+ parent::__construct($stream, ['window' => 15], ['window' => 15, 'level' => $level]);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function readFilter()
+ {
+ return 'zlib.inflate';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function writeFilter()
+ {
+ return 'zlib.deflate';
+ }
+}
diff --git a/inc/mailgun/php-http/message/src/Encoding/DeflateStream.php b/inc/mailgun/php-http/message/src/Encoding/DeflateStream.php
new file mode 100644
index 0000000..1d7344b
--- /dev/null
+++ b/inc/mailgun/php-http/message/src/Encoding/DeflateStream.php
@@ -0,0 +1,38 @@
+<?php
+
+namespace Http\Message\Encoding;
+
+use Psr\Http\Message\StreamInterface;
+
+/**
+ * Stream deflate (RFC 1951).
+ *
+ * @author Joel Wurtz <joel.wurtz@gmail.com>
+ */
+class DeflateStream extends FilteredStream
+{
+ /**
+ * @param StreamInterface $stream
+ * @param int $level
+ */
+ public function __construct(StreamInterface $stream, $level = -1)
+ {
+ parent::__construct($stream, ['window' => -15, 'level' => $level], ['window' => -15]);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function readFilter()
+ {
+ return 'zlib.deflate';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function writeFilter()
+ {
+ return 'zlib.inflate';
+ }
+}
diff --git a/inc/mailgun/php-http/message/src/Encoding/Filter/Chunk.php b/inc/mailgun/php-http/message/src/Encoding/Filter/Chunk.php
new file mode 100644
index 0000000..0f8f53b
--- /dev/null
+++ b/inc/mailgun/php-http/message/src/Encoding/Filter/Chunk.php
@@ -0,0 +1,30 @@
+<?php
+
+namespace Http\Message\Encoding\Filter;
+
+/**
+ * Userland implementation of the chunk stream filter.
+ *
+ * @author Joel Wurtz <joel.wurtz@gmail.com>
+ */
+class Chunk extends \php_user_filter
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function filter($in, $out, &$consumed, $closing)
+ {
+ while ($bucket = stream_bucket_make_writeable($in)) {
+ $lenbucket = stream_bucket_new($this->stream, dechex($bucket->datalen)."\r\n");
+ stream_bucket_append($out, $lenbucket);
+
+ $consumed += $bucket->datalen;
+ stream_bucket_append($out, $bucket);
+
+ $lenbucket = stream_bucket_new($this->stream, "\r\n");
+ stream_bucket_append($out, $lenbucket);
+ }
+
+ return PSFS_PASS_ON;
+ }
+}
diff --git a/inc/mailgun/php-http/message/src/Encoding/FilteredStream.php b/inc/mailgun/php-http/message/src/Encoding/FilteredStream.php
new file mode 100644
index 0000000..a32554b
--- /dev/null
+++ b/inc/mailgun/php-http/message/src/Encoding/FilteredStream.php
@@ -0,0 +1,198 @@
+<?php
+
+namespace Http\Message\Encoding;
+
+use Clue\StreamFilter as Filter;
+use Http\Message\Decorator\StreamDecorator;
+use Psr\Http\Message\StreamInterface;
+
+/**
+ * A filtered stream has a filter for filtering output and a filter for filtering input made to a underlying stream.
+ *
+ * @author Joel Wurtz <joel.wurtz@gmail.com>
+ */
+abstract class FilteredStream implements StreamInterface
+{
+ const BUFFER_SIZE = 8192;
+
+ use StreamDecorator;
+
+ /**
+ * @var callable
+ */
+ protected $readFilterCallback;
+
+ /**
+ * @var resource
+ *
+ * @deprecated since version 1.5, will be removed in 2.0
+ */
+ protected $readFilter;
+
+ /**
+ * @var callable
+ *
+ * @deprecated since version 1.5, will be removed in 2.0
+ */
+ protected $writeFilterCallback;
+
+ /**
+ * @var resource
+ *
+ * @deprecated since version 1.5, will be removed in 2.0
+ */
+ protected $writeFilter;
+
+ /**
+ * Internal buffer.
+ *
+ * @var string
+ */
+ protected $buffer = '';
+
+ /**
+ * @param StreamInterface $stream
+ * @param mixed|null $readFilterOptions
+ * @param mixed|null $writeFilterOptions deprecated since 1.5, will be removed in 2.0
+ */
+ public function __construct(StreamInterface $stream, $readFilterOptions = null, $writeFilterOptions = null)
+ {
+ $this->readFilterCallback = Filter\fun($this->readFilter(), $readFilterOptions);
+ $this->writeFilterCallback = Filter\fun($this->writeFilter(), $writeFilterOptions);
+
+ if (null !== $writeFilterOptions) {
+ @trigger_error('The $writeFilterOptions argument is deprecated since version 1.5 and will be removed in 2.0.', E_USER_DEPRECATED);
+ }
+
+ $this->stream = $stream;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function read($length)
+ {
+ if (strlen($this->buffer) >= $length) {
+ $read = substr($this->buffer, 0, $length);
+ $this->buffer = substr($this->buffer, $length);
+
+ return $read;
+ }
+
+ if ($this->stream->eof()) {
+ $buffer = $this->buffer;
+ $this->buffer = '';
+
+ return $buffer;
+ }
+
+ $read = $this->buffer;
+ $this->buffer = '';
+ $this->fill();
+
+ return $read.$this->read($length - strlen($read));
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function eof()
+ {
+ return $this->stream->eof() && $this->buffer === '';
+ }
+
+ /**
+ * Buffer is filled by reading underlying stream.
+ *
+ * Callback is reading once more even if the stream is ended.
+ * This allow to get last data in the PHP buffer otherwise this
+ * bug is present : https://bugs.php.net/bug.php?id=48725
+ */
+ protected function fill()
+ {
+ $readFilterCallback = $this->readFilterCallback;
+ $this->buffer .= $readFilterCallback($this->stream->read(self::BUFFER_SIZE));
+
+ if ($this->stream->eof()) {
+ $this->buffer .= $readFilterCallback();
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getContents()
+ {
+ $buffer = '';
+
+ while (!$this->eof()) {
+ $buf = $this->read(self::BUFFER_SIZE);
+ // Using a loose equality here to match on '' and false.
+ if ($buf == null) {
+ break;
+ }
+
+ $buffer .= $buf;
+ }
+
+ return $buffer;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getSize()
+ {
+ return;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function __toString()
+ {
+ return $this->getContents();
+ }
+
+ /**
+ * Returns the read filter name.
+ *
+ * @return string
+ *
+ * @deprecated since version 1.5, will be removed in 2.0
+ */
+ public function getReadFilter()
+ {
+ @trigger_error('The '.__CLASS__.'::'.__METHOD__.' method is deprecated since version 1.5 and will be removed in 2.0.', E_USER_DEPRECATED);
+
+ return $this->readFilter();
+ }
+
+ /**
+ * Returns the write filter name.
+ *
+ * @return string
+ */
+ abstract protected function readFilter();
+
+ /**
+ * Returns the write filter name.
+ *
+ * @return string
+ *
+ * @deprecated since version 1.5, will be removed in 2.0
+ */
+ public function getWriteFilter()
+ {
+ @trigger_error('The '.__CLASS__.'::'.__METHOD__.' method is deprecated since version 1.5 and will be removed in 2.0.', E_USER_DEPRECATED);
+
+ return $this->writeFilter();
+ }
+
+ /**
+ * Returns the write filter name.
+ *
+ * @return string
+ */
+ abstract protected function writeFilter();
+}
diff --git a/inc/mailgun/php-http/message/src/Encoding/GzipDecodeStream.php b/inc/mailgun/php-http/message/src/Encoding/GzipDecodeStream.php
new file mode 100644
index 0000000..4f958ed
--- /dev/null
+++ b/inc/mailgun/php-http/message/src/Encoding/GzipDecodeStream.php
@@ -0,0 +1,42 @@
+<?php
+
+namespace Http\Message\Encoding;
+
+use Psr\Http\Message\StreamInterface;
+
+/**
+ * Stream for decoding from gzip format (RFC 1952).
+ *
+ * @author Joel Wurtz <joel.wurtz@gmail.com>
+ */
+class GzipDecodeStream extends FilteredStream
+{
+ /**
+ * @param StreamInterface $stream
+ * @param int $level
+ */
+ public function __construct(StreamInterface $stream, $level = -1)
+ {
+ if (!extension_loaded('zlib')) {
+ throw new \RuntimeException('The zlib extension must be enabled to use this stream');
+ }
+
+ parent::__construct($stream, ['window' => 31], ['window' => 31, 'level' => $level]);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function readFilter()
+ {
+ return 'zlib.inflate';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function writeFilter()
+ {
+ return 'zlib.deflate';
+ }
+}
diff --git a/inc/mailgun/php-http/message/src/Encoding/GzipEncodeStream.php b/inc/mailgun/php-http/message/src/Encoding/GzipEncodeStream.php
new file mode 100644
index 0000000..1066eec
--- /dev/null
+++ b/inc/mailgun/php-http/message/src/Encoding/GzipEncodeStream.php
@@ -0,0 +1,42 @@
+<?php
+
+namespace Http\Message\Encoding;
+
+use Psr\Http\Message\StreamInterface;
+
+/**
+ * Stream for encoding to gzip format (RFC 1952).
+ *
+ * @author Joel Wurtz <joel.wurtz@gmail.com>
+ */
+class GzipEncodeStream extends FilteredStream
+{
+ /**
+ * @param StreamInterface $stream
+ * @param int $level
+ */
+ public function __construct(StreamInterface $stream, $level = -1)
+ {
+ if (!extension_loaded('zlib')) {
+ throw new \RuntimeException('The zlib extension must be enabled to use this stream');
+ }
+
+ parent::__construct($stream, ['window' => 31, 'level' => $level], ['window' => 31]);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function readFilter()
+ {
+ return 'zlib.deflate';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function writeFilter()
+ {
+ return 'zlib.inflate';
+ }
+}
diff --git a/inc/mailgun/php-http/message/src/Encoding/InflateStream.php b/inc/mailgun/php-http/message/src/Encoding/InflateStream.php
new file mode 100644
index 0000000..7070230
--- /dev/null
+++ b/inc/mailgun/php-http/message/src/Encoding/InflateStream.php
@@ -0,0 +1,42 @@
+<?php
+
+namespace Http\Message\Encoding;
+
+use Psr\Http\Message\StreamInterface;
+
+/**
+ * Stream inflate (RFC 1951).
+ *
+ * @author Joel Wurtz <joel.wurtz@gmail.com>
+ */
+class InflateStream extends FilteredStream
+{
+ /**
+ * @param StreamInterface $stream
+ * @param int $level
+ */
+ public function __construct(StreamInterface $stream, $level = -1)
+ {
+ if (!extension_loaded('zlib')) {
+ throw new \RuntimeException('The zlib extension must be enabled to use this stream');
+ }
+
+ parent::__construct($stream, ['window' => -15], ['window' => -15, 'level' => $level]);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function readFilter()
+ {
+ return 'zlib.inflate';
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ protected function writeFilter()
+ {
+ return 'zlib.deflate';
+ }
+}
diff --git a/inc/mailgun/php-http/message/src/Formatter.php b/inc/mailgun/php-http/message/src/Formatter.php
new file mode 100644
index 0000000..d04d2c3
--- /dev/null
+++ b/inc/mailgun/php-http/message/src/Formatter.php
@@ -0,0 +1,32 @@
+<?php
+
+namespace Http\Message;
+
+use Psr\Http\Message\RequestInterface;
+use Psr\Http\Message\ResponseInterface;
+
+/**
+ * Formats a request and/or a response as a string.
+ *
+ * @author Márk Sági-Kazár <mark.sagikazar@gmail.com>
+ */
+interface Formatter
+{
+ /**
+ * Formats a request.
+ *
+ * @param RequestInterface $request
+ *
+ * @return string
+ */
+ public function formatRequest(RequestInterface $request);
+
+ /**
+ * Formats a response.
+ *
+ * @param ResponseInterface $response
+ *
+ * @return string
+ */
+ public function formatResponse(ResponseInterface $response);
+}
diff --git a/inc/mailgun/php-http/message/src/Formatter/CurlCommandFormatter.php b/inc/mailgun/php-http/message/src/Formatter/CurlCommandFormatter.php
new file mode 100644
index 0000000..5364ccc
--- /dev/null
+++ b/inc/mailgun/php-http/message/src/Formatter/CurlCommandFormatter.php
@@ -0,0 +1,80 @@
+<?php
+
+namespace Http\Message\Formatter;
+
+use Http\Message\Formatter;
+use Psr\Http\Message\RequestInterface;
+use Psr\Http\Message\ResponseInterface;
+
+/**
+ * A formatter that prints a cURL command for HTTP requests.
+ *
+ * @author Tobias Nyholm <tobias.nyholm@gmail.com>
+ */
+class CurlCommandFormatter implements Formatter
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function formatRequest(RequestInterface $request)
+ {
+ $command = sprintf('curl %s', escapeshellarg((string) $request->getUri()->withFragment('')));
+ if ($request->getProtocolVersion() === '1.0') {
+ $command .= ' --http1.0';
+ } elseif ($request->getProtocolVersion() === '2.0') {
+ $command .= ' --http2';
+ }
+
+ $method = strtoupper($request->getMethod());
+ if ('HEAD' === $method) {
+ $command .= ' --head';
+ } elseif ('GET' !== $method) {
+ $command .= ' --request '.$method;
+ }
+
+ $command .= $this->getHeadersAsCommandOptions($request);
+
+ $body = $request->getBody();
+ if ($body->getSize() > 0) {
+ if (!$body->isSeekable()) {
+ return 'Cant format Request as cUrl command if body stream is not seekable.';
+ }
+ $command .= sprintf(' --data %s', escapeshellarg($body->__toString()));
+ $body->rewind();
+ }
+
+ return $command;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function formatResponse(ResponseInterface $response)
+ {
+ return '';
+ }
+
+ /**
+ * @param RequestInterface $request
+ *
+ * @return string
+ */
+ private function getHeadersAsCommandOptions(RequestInterface $request)
+ {
+ $command = '';
+ foreach ($request->getHeaders() as $name => $values) {
+ if ('host' === strtolower($name) && $values[0] === $request->getUri()->getHost()) {
+ continue;
+ }
+
+ if ('user-agent' === strtolower($name)) {
+ $command .= sprintf('-A %s', escapeshellarg($values[0]));
+ continue;
+ }
+
+ $command .= sprintf(' -H %s', escapeshellarg($name.': '.$request->getHeaderLine($name)));
+ }
+
+ return $command;
+ }
+}
diff --git a/inc/mailgun/php-http/message/src/Formatter/FullHttpMessageFormatter.php b/inc/mailgun/php-http/message/src/Formatter/FullHttpMessageFormatter.php
new file mode 100644
index 0000000..3fa1029
--- /dev/null
+++ b/inc/mailgun/php-http/message/src/Formatter/FullHttpMessageFormatter.php
@@ -0,0 +1,91 @@
+<?php
+
+namespace Http\Message\Formatter;
+
+use Http\Message\Formatter;
+use Psr\Http\Message\MessageInterface;
+use Psr\Http\Message\RequestInterface;
+use Psr\Http\Message\ResponseInterface;
+
+/**
+ * A formatter that prints the complete HTTP message.
+ *
+ * @author Tobias Nyholm <tobias.nyholm@gmail.com>
+ */
+class FullHttpMessageFormatter implements Formatter
+{
+ /**
+ * The maximum length of the body.
+ *
+ * @var int
+ */
+ private $maxBodyLength;
+
+ /**
+ * @param int $maxBodyLength
+ */
+ public function __construct($maxBodyLength = 1000)
+ {
+ $this->maxBodyLength = $maxBodyLength;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function formatRequest(RequestInterface $request)
+ {
+ $message = sprintf(
+ "%s %s HTTP/%s\n",
+ $request->getMethod(),
+ $request->getRequestTarget(),
+ $request->getProtocolVersion()
+ );
+
+ foreach ($request->getHeaders() as $name => $values) {
+ $message .= $name.': '.implode(', ', $values)."\n";
+ }
+
+ return $this->addBody($request, $message);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function formatResponse(ResponseInterface $response)
+ {
+ $message = sprintf(
+ "HTTP/%s %s %s\n",
+ $response->getProtocolVersion(),
+ $response->getStatusCode(),
+ $response->getReasonPhrase()
+ );
+
+ foreach ($response->getHeaders() as $name => $values) {
+ $message .= $name.': '.implode(', ', $values)."\n";
+ }
+
+ return $this->addBody($response, $message);
+ }
+
+ /**
+ * Add the message body if the stream is seekable.
+ *
+ * @param MessageInterface $request
+ * @param string $message
+ *
+ * @return string
+ */
+ private function addBody(MessageInterface $request, $message)
+ {
+ $stream = $request->getBody();
+ if (!$stream->isSeekable() || $this->maxBodyLength === 0) {
+ // Do not read the stream
+ $message .= "\n";
+ } else {
+ $message .= "\n".mb_substr($stream->__toString(), 0, $this->maxBodyLength);
+ $stream->rewind();
+ }
+
+ return $message;
+ }
+}
diff --git a/inc/mailgun/php-http/message/src/Formatter/SimpleFormatter.php b/inc/mailgun/php-http/message/src/Formatter/SimpleFormatter.php
new file mode 100644
index 0000000..b1fcabd
--- /dev/null
+++ b/inc/mailgun/php-http/message/src/Formatter/SimpleFormatter.php
@@ -0,0 +1,42 @@
+<?php
+
+namespace Http\Message\Formatter;
+
+use Http\Message\Formatter;
+use Psr\Http\Message\RequestInterface;
+use Psr\Http\Message\ResponseInterface;
+
+/**
+ * Normalize a request or a response into a string or an array.
+ *
+ * @author Joel Wurtz <joel.wurtz@gmail.com>
+ * @author Márk Sági-Kazár <mark.sagikazar@gmail.com>
+ */
+class SimpleFormatter implements Formatter
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function formatRequest(RequestInterface $request)
+ {
+ return sprintf(
+ '%s %s %s',
+ $request->getMethod(),
+ $request->getUri()->__toString(),
+ $request->getProtocolVersion()
+ );
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function formatResponse(ResponseInterface $response)
+ {
+ return sprintf(
+ '%s %s %s',
+ $response->getStatusCode(),
+ $response->getReasonPhrase(),
+ $response->getProtocolVersion()
+ );
+ }
+}
diff --git a/inc/mailgun/php-http/message/src/MessageFactory/DiactorosMessageFactory.php b/inc/mailgun/php-http/message/src/MessageFactory/DiactorosMessageFactory.php
new file mode 100644
index 0000000..53f08ae
--- /dev/null
+++ b/inc/mailgun/php-http/message/src/MessageFactory/DiactorosMessageFactory.php
@@ -0,0 +1,61 @@
+<?php
+
+namespace Http\Message\MessageFactory;
+
+use Http\Message\StreamFactory\DiactorosStreamFactory;
+use Http\Message\MessageFactory;
+use Zend\Diactoros\Request;
+use Zend\Diactoros\Response;
+
+/**
+ * Creates Diactoros messages.
+ *
+ * @author GeLo <geloen.eric@gmail.com>
+ */
+final class DiactorosMessageFactory implements MessageFactory
+{
+ /**
+ * @var DiactorosStreamFactory
+ */
+ private $streamFactory;
+
+ public function __construct()
+ {
+ $this->streamFactory = new DiactorosStreamFactory();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function createRequest(
+ $method,
+ $uri,
+ array $headers = [],
+ $body = null,
+ $protocolVersion = '1.1'
+ ) {
+ return (new Request(
+ $uri,
+ $method,
+ $this->streamFactory->createStream($body),
+ $headers
+ ))->withProtocolVersion($protocolVersion);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function createResponse(
+ $statusCode = 200,
+ $reasonPhrase = null,
+ array $headers = [],
+ $body = null,
+ $protocolVersion = '1.1'
+ ) {
+ return (new Response(
+ $this->streamFactory->createStream($body),
+ $statusCode,
+ $headers
+ ))->withProtocolVersion($protocolVersion);
+ }
+}
diff --git a/inc/mailgun/php-http/message/src/MessageFactory/GuzzleMessageFactory.php b/inc/mailgun/php-http/message/src/MessageFactory/GuzzleMessageFactory.php
new file mode 100644
index 0000000..59eb655
--- /dev/null
+++ b/inc/mailgun/php-http/message/src/MessageFactory/GuzzleMessageFactory.php
@@ -0,0 +1,53 @@
+<?php
+
+namespace Http\Message\MessageFactory;
+
+use GuzzleHttp\Psr7\Request;
+use GuzzleHttp\Psr7\Response;
+use Http\Message\MessageFactory;
+
+/**
+ * Creates Guzzle messages.
+ *
+ * @author Márk Sági-Kazár <mark.sagikazar@gmail.com>
+ */
+final class GuzzleMessageFactory implements MessageFactory
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function createRequest(
+ $method,
+ $uri,
+ array $headers = [],
+ $body = null,
+ $protocolVersion = '1.1'
+ ) {
+ return new Request(
+ $method,
+ $uri,
+ $headers,
+ $body,
+ $protocolVersion
+ );
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function createResponse(
+ $statusCode = 200,
+ $reasonPhrase = null,
+ array $headers = [],
+ $body = null,
+ $protocolVersion = '1.1'
+ ) {
+ return new Response(
+ $statusCode,
+ $headers,
+ $body,
+ $protocolVersion,
+ $reasonPhrase
+ );
+ }
+}
diff --git a/inc/mailgun/php-http/message/src/MessageFactory/SlimMessageFactory.php b/inc/mailgun/php-http/message/src/MessageFactory/SlimMessageFactory.php
new file mode 100644
index 0000000..cdad2ec
--- /dev/null
+++ b/inc/mailgun/php-http/message/src/MessageFactory/SlimMessageFactory.php
@@ -0,0 +1,72 @@
+<?php
+
+namespace Http\Message\MessageFactory;
+
+use Http\Message\StreamFactory\SlimStreamFactory;
+use Http\Message\UriFactory\SlimUriFactory;
+use Http\Message\MessageFactory;
+use Slim\Http\Request;
+use Slim\Http\Response;
+use Slim\Http\Headers;
+
+/**
+ * Creates Slim 3 messages.
+ *
+ * @author Mika Tuupola <tuupola@appelsiini.net>
+ */
+final class SlimMessageFactory implements MessageFactory
+{
+ /**
+ * @var SlimStreamFactory
+ */
+ private $streamFactory;
+
+ /**
+ * @var SlimUriFactory
+ */
+ private $uriFactory;
+
+ public function __construct()
+ {
+ $this->streamFactory = new SlimStreamFactory();
+ $this->uriFactory = new SlimUriFactory();
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function createRequest(
+ $method,
+ $uri,
+ array $headers = [],
+ $body = null,
+ $protocolVersion = '1.1'
+ ) {
+ return (new Request(
+ $method,
+ $this->uriFactory->createUri($uri),
+ new Headers($headers),
+ [],
+ [],
+ $this->streamFactory->createStream($body),
+ []
+ ))->withProtocolVersion($protocolVersion);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function createResponse(
+ $statusCode = 200,
+ $reasonPhrase = null,
+ array $headers = [],
+ $body = null,
+ $protocolVersion = '1.1'
+ ) {
+ return (new Response(
+ $statusCode,
+ new Headers($headers),
+ $this->streamFactory->createStream($body)
+ ))->withProtocolVersion($protocolVersion);
+ }
+}
diff --git a/inc/mailgun/php-http/message/src/RequestMatcher.php b/inc/mailgun/php-http/message/src/RequestMatcher.php
new file mode 100644
index 0000000..94fe532
--- /dev/null
+++ b/inc/mailgun/php-http/message/src/RequestMatcher.php
@@ -0,0 +1,26 @@
+<?php
+
+namespace Http\Message;
+
+use Psr\Http\Message\RequestInterface;
+
+/**
+ * Match a request.
+ *
+ * PSR-7 equivalent of Symfony's RequestMatcher
+ *
+ * @see https://github.com/symfony/symfony/blob/master/src/Symfony/Component/HttpFoundation/RequestMatcherInterface.php
+ *
+ * @author Joel Wurtz <joel.wurtz@gmail.com>
+ */
+interface RequestMatcher
+{
+ /**
+ * Decides whether the rule(s) implemented by the strategy matches the supplied request.
+ *
+ * @param RequestInterface $request The PSR7 request to check for a match
+ *
+ * @return bool true if the request matches, false otherwise
+ */
+ public function matches(RequestInterface $request);
+}
diff --git a/inc/mailgun/php-http/message/src/RequestMatcher/CallbackRequestMatcher.php b/inc/mailgun/php-http/message/src/RequestMatcher/CallbackRequestMatcher.php
new file mode 100644
index 0000000..4d45e32
--- /dev/null
+++ b/inc/mailgun/php-http/message/src/RequestMatcher/CallbackRequestMatcher.php
@@ -0,0 +1,35 @@
+<?php
+
+namespace Http\Message\RequestMatcher;
+
+use Http\Message\RequestMatcher;
+use Psr\Http\Message\RequestInterface;
+
+/**
+ * Match a request with a callback.
+ *
+ * @author Márk Sági-Kazár <mark.sagikazar@gmail.com>
+ */
+final class CallbackRequestMatcher implements RequestMatcher
+{
+ /**
+ * @var callable
+ */
+ private $callback;
+
+ /**
+ * @param callable $callback
+ */
+ public function __construct(callable $callback)
+ {
+ $this->callback = $callback;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function matches(RequestInterface $request)
+ {
+ return (bool) call_user_func($this->callback, $request);
+ }
+}
diff --git a/inc/mailgun/php-http/message/src/RequestMatcher/RegexRequestMatcher.php b/inc/mailgun/php-http/message/src/RequestMatcher/RegexRequestMatcher.php
new file mode 100644
index 0000000..91f3729
--- /dev/null
+++ b/inc/mailgun/php-http/message/src/RequestMatcher/RegexRequestMatcher.php
@@ -0,0 +1,41 @@
+<?php
+
+namespace Http\Message\RequestMatcher;
+
+use Http\Message\RequestMatcher;
+use Psr\Http\Message\RequestInterface;
+
+@trigger_error('The '.__NAMESPACE__.'\RegexRequestMatcher class is deprecated since version 1.2 and will be removed in 2.0. Use Http\Message\RequestMatcher\RequestMatcher instead.', E_USER_DEPRECATED);
+
+/**
+ * Match a request with a regex on the uri.
+ *
+ * @author Joel Wurtz <joel.wurtz@gmail.com>
+ *
+ * @deprecated since version 1.2 and will be removed in 2.0. Use {@link RequestMatcher} instead.
+ */
+final class RegexRequestMatcher implements RequestMatcher
+{
+ /**
+ * Matching regex.
+ *
+ * @var string
+ */
+ private $regex;
+
+ /**
+ * @param string $regex
+ */
+ public function __construct($regex)
+ {
+ $this->regex = $regex;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function matches(RequestInterface $request)
+ {
+ return (bool) preg_match($this->regex, (string) $request->getUri());
+ }
+}
diff --git a/inc/mailgun/php-http/message/src/RequestMatcher/RequestMatcher.php b/inc/mailgun/php-http/message/src/RequestMatcher/RequestMatcher.php
new file mode 100644
index 0000000..e2aa021
--- /dev/null
+++ b/inc/mailgun/php-http/message/src/RequestMatcher/RequestMatcher.php
@@ -0,0 +1,78 @@
+<?php
+
+namespace Http\Message\RequestMatcher;
+
+use Http\Message\RequestMatcher as RequestMatcherInterface;
+use Psr\Http\Message\RequestInterface;
+
+/**
+ * A port of the Symfony RequestMatcher for PSR-7.
+ *
+ * @author Fabien Potencier <fabien@symfony.com>
+ * @author Joel Wurtz <joel.wurtz@gmail.com>
+ */
+final class RequestMatcher implements RequestMatcherInterface
+{
+ /**
+ * @var string
+ */
+ private $path;
+
+ /**
+ * @var string
+ */
+ private $host;
+
+ /**
+ * @var array
+ */
+ private $methods = [];
+
+ /**
+ * @var string[]
+ */
+ private $schemes = [];
+
+ /**
+ * The regular expressions used for path or host must be specified without delimiter.
+ * You do not need to escape the forward slash / to match it.
+ *
+ * @param string|null $path Regular expression for the path
+ * @param string|null $host Regular expression for the hostname
+ * @param string|string[]|null $methods Method or list of methods to match
+ * @param string|string[]|null $schemes Scheme or list of schemes to match (e.g. http or https)
+ */
+ public function __construct($path = null, $host = null, $methods = [], $schemes = [])
+ {
+ $this->path = $path;
+ $this->host = $host;
+ $this->methods = array_map('strtoupper', (array) $methods);
+ $this->schemes = array_map('strtolower', (array) $schemes);
+ }
+
+ /**
+ * {@inheritdoc}
+ *
+ * @api
+ */
+ public function matches(RequestInterface $request)
+ {
+ if ($this->schemes && !in_array($request->getUri()->getScheme(), $this->schemes)) {
+ return false;
+ }
+
+ if ($this->methods && !in_array($request->getMethod(), $this->methods)) {
+ return false;
+ }
+
+ if (null !== $this->path && !preg_match('{'.$this->path.'}', rawurldecode($request->getUri()->getPath()))) {
+ return false;
+ }
+
+ if (null !== $this->host && !preg_match('{'.$this->host.'}i', $request->getUri()->getHost())) {
+ return false;
+ }
+
+ return true;
+ }
+}
diff --git a/inc/mailgun/php-http/message/src/Stream/BufferedStream.php b/inc/mailgun/php-http/message/src/Stream/BufferedStream.php
new file mode 100644
index 0000000..1eac974
--- /dev/null
+++ b/inc/mailgun/php-http/message/src/Stream/BufferedStream.php
@@ -0,0 +1,270 @@
+<?php
+
+namespace Http\Message\Stream;
+
+use Psr\Http\Message\StreamInterface;
+
+/**
+ * Decorator to make any stream seekable.
+ *
+ * Internally it buffers an existing StreamInterface into a php://temp resource (or memory). By default it will use
+ * 2 megabytes of memory before writing to a temporary disk file.
+ *
+ * Due to this, very large stream can suffer performance issue (i/o slowdown).
+ */
+class BufferedStream implements StreamInterface
+{
+ /** @var resource The buffered resource used to seek previous data */
+ private $resource;
+
+ /** @var int size of the stream if available */
+ private $size;
+
+ /** @var StreamInterface The underlying stream decorated by this class */
+ private $stream;
+
+ /** @var int How many bytes were written */
+ private $written = 0;
+
+ /**
+ * @param StreamInterface $stream Decorated stream
+ * @param bool $useFileBuffer Whether to use a file buffer (write to a file, if data exceed a certain size)
+ * by default, set this to false to only use memory
+ * @param int $memoryBuffer In conjunction with using file buffer, limit (in bytes) from which it begins to buffer
+ * the data in a file
+ */
+ public function __construct(StreamInterface $stream, $useFileBuffer = true, $memoryBuffer = 2097152)
+ {
+ $this->stream = $stream;
+ $this->size = $stream->getSize();
+
+ if ($useFileBuffer) {
+ $this->resource = fopen('php://temp/maxmemory:'.$memoryBuffer, 'rw+');
+ } else {
+ $this->resource = fopen('php://memory', 'rw+');
+ }
+
+ if (false === $this->resource) {
+ throw new \RuntimeException('Cannot create a resource over temp or memory implementation');
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function __toString()
+ {
+ try {
+ $this->rewind();
+
+ return $this->getContents();
+ } catch (\Throwable $throwable) {
+ return '';
+ } catch (\Exception $exception) { // Layer to be BC with PHP 5, remove this when we only support PHP 7+
+ return '';
+ }
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function close()
+ {
+ if (null === $this->resource) {
+ throw new \RuntimeException('Cannot close on a detached stream');
+ }
+
+ $this->stream->close();
+ fclose($this->resource);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function detach()
+ {
+ if (null === $this->resource) {
+ return;
+ }
+
+ // Force reading the remaining data of the stream
+ $this->getContents();
+
+ $resource = $this->resource;
+ $this->stream->close();
+ $this->stream = null;
+ $this->resource = null;
+
+ return $resource;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getSize()
+ {
+ if (null === $this->resource) {
+ return;
+ }
+
+ if (null === $this->size && $this->stream->eof()) {
+ return $this->written;
+ }
+
+ return $this->size;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function tell()
+ {
+ if (null === $this->resource) {
+ throw new \RuntimeException('Cannot tell on a detached stream');
+ }
+
+ return ftell($this->resource);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function eof()
+ {
+ if (null === $this->resource) {
+ throw new \RuntimeException('Cannot call eof on a detached stream');
+ }
+
+ // We are at the end only when both our resource and underlying stream are at eof
+ return $this->stream->eof() && (ftell($this->resource) === $this->written);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function isSeekable()
+ {
+ return null !== $this->resource;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function seek($offset, $whence = SEEK_SET)
+ {
+ if (null === $this->resource) {
+ throw new \RuntimeException('Cannot seek on a detached stream');
+ }
+
+ fseek($this->resource, $offset, $whence);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function rewind()
+ {
+ if (null === $this->resource) {
+ throw new \RuntimeException('Cannot rewind on a detached stream');
+ }
+
+ rewind($this->resource);
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function isWritable()
+ {
+ return false;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function write($string)
+ {
+ throw new \RuntimeException('Cannot write on this stream');
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function isReadable()
+ {
+ return null !== $this->resource;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function read($length)
+ {
+ if (null === $this->resource) {
+ throw new \RuntimeException('Cannot read on a detached stream');
+ }
+
+ $read = '';
+
+ // First read from the resource
+ if (ftell($this->resource) !== $this->written) {
+ $read = fread($this->resource, $length);
+ }
+
+ $bytesRead = strlen($read);
+
+ if ($bytesRead < $length) {
+ $streamRead = $this->stream->read($length - $bytesRead);
+
+ // Write on the underlying stream what we read
+ $this->written += fwrite($this->resource, $streamRead);
+ $read .= $streamRead;
+ }
+
+ return $read;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getContents()
+ {
+ if (null === $this->resource) {
+ throw new \RuntimeException('Cannot read on a detached stream');
+ }
+
+ $read = '';
+
+ while (!$this->eof()) {
+ $read .= $this->read(8192);
+ }
+
+ return $read;
+ }
+
+ /**
+ * {@inheritdoc}
+ */
+ public function getMetadata($key = null)
+ {
+ if (null === $this->resource) {
+ if (null === $key) {
+ return [];
+ }
+
+ return;
+ }
+
+ $metadata = stream_get_meta_data($this->resource);
+
+ if (null === $key) {
+ return $metadata;
+ }
+
+ if (!array_key_exists($key, $metadata)) {
+ return;
+ }
+
+ return $metadata[$key];
+ }
+}
diff --git a/inc/mailgun/php-http/message/src/StreamFactory/DiactorosStreamFactory.php b/inc/mailgun/php-http/message/src/StreamFactory/DiactorosStreamFactory.php
new file mode 100644
index 0000000..a75ec98
--- /dev/null
+++ b/inc/mailgun/php-http/message/src/StreamFactory/DiactorosStreamFactory.php
@@ -0,0 +1,36 @@
+<?php
+
+namespace Http\Message\StreamFactory;
+
+use Http\Message\StreamFactory;
+use Psr\Http\Message\StreamInterface;
+use Zend\Diactoros\Stream;
+
+/**
+ * Creates Diactoros streams.
+ *
+ * @author Михаил Красильников <m.krasilnikov@yandex.ru>
+ */
+final class DiactorosStreamFactory implements StreamFactory
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function createStream($body = null)
+ {
+ if ($body instanceof StreamInterface) {
+ return $body;
+ }
+
+ if (is_resource($body)) {
+ return new Stream($body);
+ }
+
+ $stream = new Stream('php://memory', 'rw');
+ if (null !== $body && '' !== $body) {
+ $stream->write((string) $body);
+ }
+
+ return $stream;
+ }
+}
diff --git a/inc/mailgun/php-http/message/src/StreamFactory/GuzzleStreamFactory.php b/inc/mailgun/php-http/message/src/StreamFactory/GuzzleStreamFactory.php
new file mode 100644
index 0000000..10f4d3f
--- /dev/null
+++ b/inc/mailgun/php-http/message/src/StreamFactory/GuzzleStreamFactory.php
@@ -0,0 +1,21 @@
+<?php
+
+namespace Http\Message\StreamFactory;
+
+use Http\Message\StreamFactory;
+
+/**
+ * Creates Guzzle streams.
+ *
+ * @author Михаил Красильников <m.krasilnikov@yandex.ru>
+ */
+final class GuzzleStreamFactory implements StreamFactory
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function createStream($body = null)
+ {
+ return \GuzzleHttp\Psr7\stream_for($body);
+ }
+}
diff --git a/inc/mailgun/php-http/message/src/StreamFactory/SlimStreamFactory.php b/inc/mailgun/php-http/message/src/StreamFactory/SlimStreamFactory.php
new file mode 100644
index 0000000..efcadc4
--- /dev/null
+++ b/inc/mailgun/php-http/message/src/StreamFactory/SlimStreamFactory.php
@@ -0,0 +1,37 @@
+<?php
+
+namespace Http\Message\StreamFactory;
+
+use Http\Message\StreamFactory;
+use Psr\Http\Message\StreamInterface;
+use Slim\Http\Stream;
+
+/**
+ * Creates Slim 3 streams.
+ *
+ * @author Mika Tuupola <tuupola@appelsiini.net>
+ */
+final class SlimStreamFactory implements StreamFactory
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function createStream($body = null)
+ {
+ if ($body instanceof StreamInterface) {
+ return $body;
+ }
+
+ if (is_resource($body)) {
+ return new Stream($body);
+ }
+
+ $resource = fopen('php://memory', 'r+');
+ $stream = new Stream($resource);
+ if (null !== $body && '' !== $body) {
+ $stream->write((string) $body);
+ }
+
+ return $stream;
+ }
+}
diff --git a/inc/mailgun/php-http/message/src/UriFactory/DiactorosUriFactory.php b/inc/mailgun/php-http/message/src/UriFactory/DiactorosUriFactory.php
new file mode 100644
index 0000000..268c361
--- /dev/null
+++ b/inc/mailgun/php-http/message/src/UriFactory/DiactorosUriFactory.php
@@ -0,0 +1,29 @@
+<?php
+
+namespace Http\Message\UriFactory;
+
+use Http\Message\UriFactory;
+use Psr\Http\Message\UriInterface;
+use Zend\Diactoros\Uri;
+
+/**
+ * Creates Diactoros URI.
+ *
+ * @author David de Boer <david@ddeboer.nl>
+ */
+final class DiactorosUriFactory implements UriFactory
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function createUri($uri)
+ {
+ if ($uri instanceof UriInterface) {
+ return $uri;
+ } elseif (is_string($uri)) {
+ return new Uri($uri);
+ }
+
+ throw new \InvalidArgumentException('URI must be a string or UriInterface');
+ }
+}
diff --git a/inc/mailgun/php-http/message/src/UriFactory/GuzzleUriFactory.php b/inc/mailgun/php-http/message/src/UriFactory/GuzzleUriFactory.php
new file mode 100644
index 0000000..4c1c286
--- /dev/null
+++ b/inc/mailgun/php-http/message/src/UriFactory/GuzzleUriFactory.php
@@ -0,0 +1,22 @@
+<?php
+
+namespace Http\Message\UriFactory;
+
+use GuzzleHttp\Psr7;
+use Http\Message\UriFactory;
+
+/**
+ * Creates Guzzle URI.
+ *
+ * @author David de Boer <david@ddeboer.nl>
+ */
+final class GuzzleUriFactory implements UriFactory
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function createUri($uri)
+ {
+ return Psr7\uri_for($uri);
+ }
+}
diff --git a/inc/mailgun/php-http/message/src/UriFactory/SlimUriFactory.php b/inc/mailgun/php-http/message/src/UriFactory/SlimUriFactory.php
new file mode 100644
index 0000000..c013d54
--- /dev/null
+++ b/inc/mailgun/php-http/message/src/UriFactory/SlimUriFactory.php
@@ -0,0 +1,31 @@
+<?php
+
+namespace Http\Message\UriFactory;
+
+use Http\Message\UriFactory;
+use Psr\Http\Message\UriInterface;
+use Slim\Http\Uri;
+
+/**
+ * Creates Slim 3 URI.
+ *
+ * @author Mika Tuupola <tuupola@appelsiini.net>
+ */
+final class SlimUriFactory implements UriFactory
+{
+ /**
+ * {@inheritdoc}
+ */
+ public function createUri($uri)
+ {
+ if ($uri instanceof UriInterface) {
+ return $uri;
+ }
+
+ if (is_string($uri)) {
+ return Uri::createFromString($uri);
+ }
+
+ throw new \InvalidArgumentException('URI must be a string or UriInterface');
+ }
+}
diff --git a/inc/mailgun/php-http/message/src/filters.php b/inc/mailgun/php-http/message/src/filters.php
new file mode 100644
index 0000000..15ed73d
--- /dev/null
+++ b/inc/mailgun/php-http/message/src/filters.php
@@ -0,0 +1,6 @@
+<?php
+
+// Register chunk filter if not found
+if (!array_key_exists('chunk', stream_get_filters())) {
+ stream_filter_register('chunk', 'Http\Message\Encoding\Filter\Chunk');
+}