Init Server Composer Components
This commit is contained in:
parent
35db27b0e6
commit
a44cc1d2e3
177 changed files with 24745 additions and 0 deletions
40
server/vendor/guzzlehttp/guzzle/.travis.yml
vendored
Normal file
40
server/vendor/guzzlehttp/guzzle/.travis.yml
vendored
Normal file
|
@ -0,0 +1,40 @@
|
|||
language: php
|
||||
|
||||
sudo: false
|
||||
|
||||
php:
|
||||
- 5.5
|
||||
- 5.6
|
||||
- 7.0
|
||||
- hhvm
|
||||
|
||||
before_script:
|
||||
- curl --version
|
||||
- composer self-update
|
||||
- composer install --no-interaction --prefer-source --dev
|
||||
- ~/.nvm/nvm.sh install v0.6.14
|
||||
- ~/.nvm/nvm.sh run v0.6.14
|
||||
|
||||
script: make test
|
||||
|
||||
matrix:
|
||||
allow_failures:
|
||||
- php: hhvm
|
||||
- php: 7.0
|
||||
fast_finish: true
|
||||
|
||||
before_deploy:
|
||||
- make package
|
||||
|
||||
deploy:
|
||||
provider: releases
|
||||
api_key:
|
||||
secure: UpypqlYgsU68QT/x40YzhHXvzWjFwCNo9d+G8KAdm7U9+blFfcWhV1aMdzugvPMl6woXgvJj7qHq5tAL4v6oswCORhpSBfLgOQVFaica5LiHsvWlAedOhxGmnJqMTwuepjBCxXhs3+I8Kof1n4oUL9gKytXjOVCX/f7XU1HiinU=
|
||||
file:
|
||||
- build/artifacts/guzzle.phar
|
||||
- build/artifacts/guzzle.zip
|
||||
on:
|
||||
repo: guzzle/guzzle
|
||||
tags: true
|
||||
all_branches: true
|
||||
php: 5.5
|
1203
server/vendor/guzzlehttp/guzzle/CHANGELOG.md
vendored
Normal file
1203
server/vendor/guzzlehttp/guzzle/CHANGELOG.md
vendored
Normal file
File diff suppressed because it is too large
Load diff
19
server/vendor/guzzlehttp/guzzle/LICENSE
vendored
Normal file
19
server/vendor/guzzlehttp/guzzle/LICENSE
vendored
Normal file
|
@ -0,0 +1,19 @@
|
|||
Copyright (c) 2011-2015 Michael Dowling, https://github.com/mtdowling <mtdowling@gmail.com>
|
||||
|
||||
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.
|
90
server/vendor/guzzlehttp/guzzle/README.md
vendored
Normal file
90
server/vendor/guzzlehttp/guzzle/README.md
vendored
Normal file
|
@ -0,0 +1,90 @@
|
|||
Guzzle, PHP HTTP client
|
||||
=======================
|
||||
|
||||
[](http://travis-ci.org/guzzle/guzzle)
|
||||
|
||||
Guzzle is a PHP HTTP client that makes it easy to send HTTP requests and
|
||||
trivial to integrate with web services.
|
||||
|
||||
- Simple interface for building query strings, POST requests, streaming large
|
||||
uploads, streaming large downloads, using HTTP cookies, uploading JSON data,
|
||||
etc...
|
||||
- Can send both synchronous and asynchronous requests using the same interface.
|
||||
- Uses PSR-7 interfaces for requests, responses, and streams. This allows you
|
||||
to utilize other PSR-7 compatible libraries with Guzzle.
|
||||
- Abstracts away the underlying HTTP transport, allowing you to write
|
||||
environment and transport agnostic code; i.e., no hard dependency on cURL,
|
||||
PHP streams, sockets, or non-blocking event loops.
|
||||
- Middleware system allows you to augment and compose client behavior.
|
||||
|
||||
```php
|
||||
$client = new GuzzleHttp\Client();
|
||||
$res = $client->request('GET', 'https://api.github.com/user', [
|
||||
'auth' => ['user', 'pass']
|
||||
]);
|
||||
echo $res->getStatusCode();
|
||||
// 200
|
||||
echo $res->getHeader('content-type');
|
||||
// 'application/json; charset=utf8'
|
||||
echo $res->getBody();
|
||||
// {"type":"User"...'
|
||||
|
||||
// Send an asynchronous request.
|
||||
$request = new \GuzzleHttp\Psr7\Request('GET', 'http://httpbin.org');
|
||||
$promise = $client->sendAsync($request)->then(function ($response) {
|
||||
echo 'I completed! ' . $response->getBody();
|
||||
});
|
||||
$promise->wait();
|
||||
```
|
||||
|
||||
## Help and docs
|
||||
|
||||
- [Documentation](http://guzzlephp.org/)
|
||||
- [stackoverflow](http://stackoverflow.com/questions/tagged/guzzle)
|
||||
- [Gitter](https://gitter.im/guzzle/guzzle)
|
||||
|
||||
|
||||
## Installing Guzzle
|
||||
|
||||
The recommended way to install Guzzle is through
|
||||
[Composer](http://getcomposer.org).
|
||||
|
||||
```bash
|
||||
# Install Composer
|
||||
curl -sS https://getcomposer.org/installer | php
|
||||
```
|
||||
|
||||
Next, run the Composer command to install the latest stable version of Guzzle:
|
||||
|
||||
```bash
|
||||
composer.phar require guzzlehttp/guzzle
|
||||
```
|
||||
|
||||
After installing, you need to require Composer's autoloader:
|
||||
|
||||
```php
|
||||
require 'vendor/autoload.php';
|
||||
```
|
||||
|
||||
You can then later update Guzzle using composer:
|
||||
|
||||
```bash
|
||||
composer.phar update
|
||||
```
|
||||
|
||||
|
||||
## Version Guidance
|
||||
|
||||
| Version | Status | Packagist | Namespace | Repo | Docs | PSR-7 |
|
||||
|---------|-------------|---------------------|--------------|---------------------|---------------------|-------|
|
||||
| 3.x | EOL | `guzzle/guzzle` | `Guzzle` | [v3][guzzle-3-repo] | [v3][guzzle-3-docs] | No |
|
||||
| 4.x | EOL | `guzzlehttp/guzzle` | `GuzzleHttp` | N/A | N/A | No |
|
||||
| 5.x | Maintained | `guzzlehttp/guzzle` | `GuzzleHttp` | [v5][guzzle-5-repo] | [v5][guzzle-5-docs] | No |
|
||||
| 6.x | Latest | `guzzlehttp/guzzle` | `GuzzleHttp` | [v6][guzzle-6-repo] | [v6][guzzle-6-docs] | Yes |
|
||||
|
||||
[guzzle-3-repo]: https://github.com/guzzle/guzzle3
|
||||
[guzzle-5-repo]: https://github.com/guzzle/guzzle/tree/5.3
|
||||
[guzzle-6-repo]: https://github.com/guzzle/guzzle
|
||||
[guzzle-3-docs]: http://guzzle3.readthedocs.org/en/latest/
|
||||
[guzzle-5-docs]: http://guzzle.readthedocs.org/en/5.3/
|
||||
[guzzle-6-docs]: http://guzzle.readthedocs.org/en/latest/
|
1203
server/vendor/guzzlehttp/guzzle/UPGRADING.md
vendored
Normal file
1203
server/vendor/guzzlehttp/guzzle/UPGRADING.md
vendored
Normal file
File diff suppressed because it is too large
Load diff
41
server/vendor/guzzlehttp/guzzle/composer.json
vendored
Normal file
41
server/vendor/guzzlehttp/guzzle/composer.json
vendored
Normal file
|
@ -0,0 +1,41 @@
|
|||
{
|
||||
"name": "guzzlehttp/guzzle",
|
||||
"type": "library",
|
||||
"description": "Guzzle is a PHP HTTP client library",
|
||||
"keywords": ["framework", "http", "rest", "web service", "curl", "client", "HTTP client"],
|
||||
"homepage": "http://guzzlephp.org/",
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Michael Dowling",
|
||||
"email": "mtdowling@gmail.com",
|
||||
"homepage": "https://github.com/mtdowling"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=5.5.0",
|
||||
"guzzlehttp/psr7": "~1.1",
|
||||
"guzzlehttp/promises": "~1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"ext-curl": "*",
|
||||
"phpunit/phpunit": "~4.0",
|
||||
"psr/log": "~1.0"
|
||||
},
|
||||
"autoload": {
|
||||
"files": ["src/functions_include.php"],
|
||||
"psr-4": {
|
||||
"GuzzleHttp\\": "src/"
|
||||
}
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"GuzzleHttp\\Tests\\": "tests/"
|
||||
}
|
||||
},
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "6.1-dev"
|
||||
}
|
||||
}
|
||||
}
|
397
server/vendor/guzzlehttp/guzzle/src/Client.php
vendored
Normal file
397
server/vendor/guzzlehttp/guzzle/src/Client.php
vendored
Normal file
|
@ -0,0 +1,397 @@
|
|||
<?php
|
||||
namespace GuzzleHttp;
|
||||
|
||||
use GuzzleHttp\Cookie\CookieJar;
|
||||
use GuzzleHttp\Promise;
|
||||
use GuzzleHttp\Psr7;
|
||||
use Psr\Http\Message\UriInterface;
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
/**
|
||||
* @method ResponseInterface get($uri, array $options = [])
|
||||
* @method ResponseInterface head($uri, array $options = [])
|
||||
* @method ResponseInterface put($uri, array $options = [])
|
||||
* @method ResponseInterface post($uri, array $options = [])
|
||||
* @method ResponseInterface patch($uri, array $options = [])
|
||||
* @method ResponseInterface delete($uri, array $options = [])
|
||||
* @method Promise\PromiseInterface getAsync($uri, array $options = [])
|
||||
* @method Promise\PromiseInterface headAsync($uri, array $options = [])
|
||||
* @method Promise\PromiseInterface putAsync($uri, array $options = [])
|
||||
* @method Promise\PromiseInterface postAsync($uri, array $options = [])
|
||||
* @method Promise\PromiseInterface patchAsync($uri, array $options = [])
|
||||
* @method Promise\PromiseInterface deleteAsync($uri, array $options = [])
|
||||
*/
|
||||
class Client implements ClientInterface
|
||||
{
|
||||
/** @var array Default request options */
|
||||
private $config;
|
||||
|
||||
/**
|
||||
* Clients accept an array of constructor parameters.
|
||||
*
|
||||
* Here's an example of creating a client using a base_uri and an array of
|
||||
* default request options to apply to each request:
|
||||
*
|
||||
* $client = new Client([
|
||||
* 'base_uri' => 'http://www.foo.com/1.0/',
|
||||
* 'timeout' => 0,
|
||||
* 'allow_redirects' => false,
|
||||
* 'proxy' => '192.168.16.1:10'
|
||||
* ]);
|
||||
*
|
||||
* Client configuration settings include the following options:
|
||||
*
|
||||
* - handler: (callable) Function that transfers HTTP requests over the
|
||||
* wire. The function is called with a Psr7\Http\Message\RequestInterface
|
||||
* and array of transfer options, and must return a
|
||||
* GuzzleHttp\Promise\PromiseInterface that is fulfilled with a
|
||||
* Psr7\Http\Message\ResponseInterface on success. "handler" is a
|
||||
* constructor only option that cannot be overridden in per/request
|
||||
* options. If no handler is provided, a default handler will be created
|
||||
* that enables all of the request options below by attaching all of the
|
||||
* default middleware to the handler.
|
||||
* - base_uri: (string|UriInterface) Base URI of the client that is merged
|
||||
* into relative URIs. Can be a string or instance of UriInterface.
|
||||
* - **: any request option
|
||||
*
|
||||
* @param array $config Client configuration settings.
|
||||
*
|
||||
* @see \GuzzleHttp\RequestOptions for a list of available request options.
|
||||
*/
|
||||
public function __construct(array $config = [])
|
||||
{
|
||||
if (!isset($config['handler'])) {
|
||||
$config['handler'] = HandlerStack::create();
|
||||
}
|
||||
|
||||
// Convert the base_uri to a UriInterface
|
||||
if (isset($config['base_uri'])) {
|
||||
$config['base_uri'] = Psr7\uri_for($config['base_uri']);
|
||||
}
|
||||
|
||||
$this->configureDefaults($config);
|
||||
}
|
||||
|
||||
public function __call($method, $args)
|
||||
{
|
||||
if (count($args) < 1) {
|
||||
throw new \InvalidArgumentException('Magic request methods require a URI and optional options array');
|
||||
}
|
||||
|
||||
$uri = $args[0];
|
||||
$opts = isset($args[1]) ? $args[1] : [];
|
||||
|
||||
return substr($method, -5) === 'Async'
|
||||
? $this->requestAsync(substr($method, 0, -5), $uri, $opts)
|
||||
: $this->request($method, $uri, $opts);
|
||||
}
|
||||
|
||||
public function sendAsync(RequestInterface $request, array $options = [])
|
||||
{
|
||||
// Merge the base URI into the request URI if needed.
|
||||
$options = $this->prepareDefaults($options);
|
||||
|
||||
return $this->transfer(
|
||||
$request->withUri($this->buildUri($request->getUri(), $options)),
|
||||
$options
|
||||
);
|
||||
}
|
||||
|
||||
public function send(RequestInterface $request, array $options = [])
|
||||
{
|
||||
$options[RequestOptions::SYNCHRONOUS] = true;
|
||||
return $this->sendAsync($request, $options)->wait();
|
||||
}
|
||||
|
||||
public function requestAsync($method, $uri = null, array $options = [])
|
||||
{
|
||||
$options = $this->prepareDefaults($options);
|
||||
// Remove request modifying parameter because it can be done up-front.
|
||||
$headers = isset($options['headers']) ? $options['headers'] : [];
|
||||
$body = isset($options['body']) ? $options['body'] : null;
|
||||
$version = isset($options['version']) ? $options['version'] : '1.1';
|
||||
// Merge the URI into the base URI.
|
||||
$uri = $this->buildUri($uri, $options);
|
||||
if (is_array($body)) {
|
||||
$this->invalidBody();
|
||||
}
|
||||
$request = new Psr7\Request($method, $uri, $headers, $body, $version);
|
||||
// Remove the option so that they are not doubly-applied.
|
||||
unset($options['headers'], $options['body'], $options['version']);
|
||||
|
||||
return $this->transfer($request, $options);
|
||||
}
|
||||
|
||||
public function request($method, $uri = null, array $options = [])
|
||||
{
|
||||
$options[RequestOptions::SYNCHRONOUS] = true;
|
||||
return $this->requestAsync($method, $uri, $options)->wait();
|
||||
}
|
||||
|
||||
public function getConfig($option = null)
|
||||
{
|
||||
return $option === null
|
||||
? $this->config
|
||||
: (isset($this->config[$option]) ? $this->config[$option] : null);
|
||||
}
|
||||
|
||||
private function buildUri($uri, array $config)
|
||||
{
|
||||
if (!isset($config['base_uri'])) {
|
||||
return $uri instanceof UriInterface ? $uri : new Psr7\Uri($uri);
|
||||
}
|
||||
|
||||
return Psr7\Uri::resolve(Psr7\uri_for($config['base_uri']), $uri);
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the default options for a client.
|
||||
*
|
||||
* @param array $config
|
||||
*/
|
||||
private function configureDefaults(array $config)
|
||||
{
|
||||
$defaults = [
|
||||
'allow_redirects' => RedirectMiddleware::$defaultSettings,
|
||||
'http_errors' => true,
|
||||
'decode_content' => true,
|
||||
'verify' => true,
|
||||
'cookies' => false
|
||||
];
|
||||
|
||||
// Use the standard Linux HTTP_PROXY and HTTPS_PROXY if set
|
||||
if ($proxy = getenv('HTTP_PROXY')) {
|
||||
$defaults['proxy']['http'] = $proxy;
|
||||
}
|
||||
|
||||
if ($proxy = getenv('HTTPS_PROXY')) {
|
||||
$defaults['proxy']['https'] = $proxy;
|
||||
}
|
||||
|
||||
if ($noProxy = getenv('NO_PROXY')) {
|
||||
$cleanedNoProxy = str_replace(' ', '', $noProxy);
|
||||
$defaults['proxy']['no'] = explode(',', $cleanedNoProxy);
|
||||
}
|
||||
|
||||
$this->config = $config + $defaults;
|
||||
|
||||
if (!empty($config['cookies']) && $config['cookies'] === true) {
|
||||
$this->config['cookies'] = new CookieJar();
|
||||
}
|
||||
|
||||
// Add the default user-agent header.
|
||||
if (!isset($this->config['headers'])) {
|
||||
$this->config['headers'] = ['User-Agent' => default_user_agent()];
|
||||
} else {
|
||||
// Add the User-Agent header if one was not already set.
|
||||
foreach (array_keys($this->config['headers']) as $name) {
|
||||
if (strtolower($name) === 'user-agent') {
|
||||
return;
|
||||
}
|
||||
}
|
||||
$this->config['headers']['User-Agent'] = default_user_agent();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Merges default options into the array.
|
||||
*
|
||||
* @param array $options Options to modify by reference
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function prepareDefaults($options)
|
||||
{
|
||||
$defaults = $this->config;
|
||||
|
||||
if (!empty($defaults['headers'])) {
|
||||
// Default headers are only added if they are not present.
|
||||
$defaults['_conditional'] = $defaults['headers'];
|
||||
unset($defaults['headers']);
|
||||
}
|
||||
|
||||
// Special handling for headers is required as they are added as
|
||||
// conditional headers and as headers passed to a request ctor.
|
||||
if (array_key_exists('headers', $options)) {
|
||||
// Allows default headers to be unset.
|
||||
if ($options['headers'] === null) {
|
||||
$defaults['_conditional'] = null;
|
||||
unset($options['headers']);
|
||||
} elseif (!is_array($options['headers'])) {
|
||||
throw new \InvalidArgumentException('headers must be an array');
|
||||
}
|
||||
}
|
||||
|
||||
// Shallow merge defaults underneath options.
|
||||
$result = $options + $defaults;
|
||||
|
||||
// Remove null values.
|
||||
foreach ($result as $k => $v) {
|
||||
if ($v === null) {
|
||||
unset($result[$k]);
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transfers the given request and applies request options.
|
||||
*
|
||||
* The URI of the request is not modified and the request options are used
|
||||
* as-is without merging in default options.
|
||||
*
|
||||
* @param RequestInterface $request
|
||||
* @param array $options
|
||||
*
|
||||
* @return Promise\PromiseInterface
|
||||
*/
|
||||
private function transfer(RequestInterface $request, array $options)
|
||||
{
|
||||
// save_to -> sink
|
||||
if (isset($options['save_to'])) {
|
||||
$options['sink'] = $options['save_to'];
|
||||
unset($options['save_to']);
|
||||
}
|
||||
|
||||
// exceptions -> http_error
|
||||
if (isset($options['exceptions'])) {
|
||||
$options['http_errors'] = $options['exceptions'];
|
||||
unset($options['exceptions']);
|
||||
}
|
||||
|
||||
$request = $this->applyOptions($request, $options);
|
||||
$handler = $options['handler'];
|
||||
|
||||
try {
|
||||
return Promise\promise_for($handler($request, $options));
|
||||
} catch (\Exception $e) {
|
||||
return Promise\rejection_for($e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies the array of request options to a request.
|
||||
*
|
||||
* @param RequestInterface $request
|
||||
* @param array $options
|
||||
*
|
||||
* @return RequestInterface
|
||||
*/
|
||||
private function applyOptions(RequestInterface $request, array &$options)
|
||||
{
|
||||
$modify = [];
|
||||
|
||||
if (isset($options['form_params'])) {
|
||||
if (isset($options['multipart'])) {
|
||||
throw new \InvalidArgumentException('You cannot use '
|
||||
. 'form_params and multipart at the same time. Use the '
|
||||
. 'form_params option if you want to send application/'
|
||||
. 'x-www-form-urlencoded requests, and the multipart '
|
||||
. 'option to send multipart/form-data requests.');
|
||||
}
|
||||
$options['body'] = http_build_query($options['form_params'], null, '&');
|
||||
unset($options['form_params']);
|
||||
$options['_conditional']['Content-Type'] = 'application/x-www-form-urlencoded';
|
||||
}
|
||||
|
||||
if (isset($options['multipart'])) {
|
||||
$elements = $options['multipart'];
|
||||
unset($options['multipart']);
|
||||
$options['body'] = new Psr7\MultipartStream($elements);
|
||||
}
|
||||
|
||||
if (!empty($options['decode_content'])
|
||||
&& $options['decode_content'] !== true
|
||||
) {
|
||||
$modify['set_headers']['Accept-Encoding'] = $options['decode_content'];
|
||||
}
|
||||
|
||||
if (isset($options['headers'])) {
|
||||
if (isset($modify['set_headers'])) {
|
||||
$modify['set_headers'] = $options['headers'] + $modify['set_headers'];
|
||||
} else {
|
||||
$modify['set_headers'] = $options['headers'];
|
||||
}
|
||||
unset($options['headers']);
|
||||
}
|
||||
|
||||
if (isset($options['body'])) {
|
||||
if (is_array($options['body'])) {
|
||||
$this->invalidBody();
|
||||
}
|
||||
$modify['body'] = Psr7\stream_for($options['body']);
|
||||
unset($options['body']);
|
||||
}
|
||||
|
||||
if (!empty($options['auth'])) {
|
||||
$value = $options['auth'];
|
||||
$type = is_array($value)
|
||||
? (isset($value[2]) ? strtolower($value[2]) : 'basic')
|
||||
: $value;
|
||||
$config['auth'] = $value;
|
||||
switch (strtolower($type)) {
|
||||
case 'basic':
|
||||
$modify['set_headers']['Authorization'] = 'Basic '
|
||||
. base64_encode("$value[0]:$value[1]");
|
||||
break;
|
||||
case 'digest':
|
||||
// @todo: Do not rely on curl
|
||||
$options['curl'][CURLOPT_HTTPAUTH] = CURLAUTH_DIGEST;
|
||||
$options['curl'][CURLOPT_USERPWD] = "$value[0]:$value[1]";
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($options['query'])) {
|
||||
$value = $options['query'];
|
||||
if (is_array($value)) {
|
||||
$value = http_build_query($value, null, '&', PHP_QUERY_RFC3986);
|
||||
}
|
||||
if (!is_string($value)) {
|
||||
throw new \InvalidArgumentException('query must be a string or array');
|
||||
}
|
||||
$modify['query'] = $value;
|
||||
unset($options['query']);
|
||||
}
|
||||
|
||||
if (isset($options['json'])) {
|
||||
$modify['body'] = Psr7\stream_for(json_encode($options['json']));
|
||||
$options['_conditional']['Content-Type'] = 'application/json';
|
||||
unset($options['json']);
|
||||
}
|
||||
|
||||
$request = Psr7\modify_request($request, $modify);
|
||||
if ($request->getBody() instanceof Psr7\MultipartStream) {
|
||||
// Use a multipart/form-data POST if a Content-Type is not set.
|
||||
$options['_conditional']['Content-Type'] = 'multipart/form-data; boundary='
|
||||
. $request->getBody()->getBoundary();
|
||||
}
|
||||
|
||||
// Merge in conditional headers if they are not present.
|
||||
if (isset($options['_conditional'])) {
|
||||
// Build up the changes so it's in a single clone of the message.
|
||||
$modify = [];
|
||||
foreach ($options['_conditional'] as $k => $v) {
|
||||
if (!$request->hasHeader($k)) {
|
||||
$modify['set_headers'][$k] = $v;
|
||||
}
|
||||
}
|
||||
$request = Psr7\modify_request($request, $modify);
|
||||
// Don't pass this internal value along to middleware/handlers.
|
||||
unset($options['_conditional']);
|
||||
}
|
||||
|
||||
return $request;
|
||||
}
|
||||
|
||||
private function invalidBody()
|
||||
{
|
||||
throw new \InvalidArgumentException('Passing in the "body" request '
|
||||
. 'option as an array to send a POST request has been deprecated. '
|
||||
. 'Please use the "form_params" request option to send a '
|
||||
. 'application/x-www-form-urlencoded request, or a the "multipart" '
|
||||
. 'request option to send a multipart/form-data request.');
|
||||
}
|
||||
}
|
84
server/vendor/guzzlehttp/guzzle/src/ClientInterface.php
vendored
Normal file
84
server/vendor/guzzlehttp/guzzle/src/ClientInterface.php
vendored
Normal file
|
@ -0,0 +1,84 @@
|
|||
<?php
|
||||
namespace GuzzleHttp;
|
||||
|
||||
use GuzzleHttp\Promise\PromiseInterface;
|
||||
use GuzzleHttp\Exception\GuzzleException;
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\UriInterface;
|
||||
|
||||
/**
|
||||
* Client interface for sending HTTP requests.
|
||||
*/
|
||||
interface ClientInterface
|
||||
{
|
||||
const VERSION = '6.1.1';
|
||||
|
||||
/**
|
||||
* Send an HTTP request.
|
||||
*
|
||||
* @param RequestInterface $request Request to send
|
||||
* @param array $options Request options to apply to the given
|
||||
* request and to the transfer.
|
||||
*
|
||||
* @return ResponseInterface
|
||||
* @throws GuzzleException
|
||||
*/
|
||||
public function send(RequestInterface $request, array $options = []);
|
||||
|
||||
/**
|
||||
* Asynchronously send an HTTP request.
|
||||
*
|
||||
* @param RequestInterface $request Request to send
|
||||
* @param array $options Request options to apply to the given
|
||||
* request and to the transfer.
|
||||
*
|
||||
* @return PromiseInterface
|
||||
*/
|
||||
public function sendAsync(RequestInterface $request, array $options = []);
|
||||
|
||||
/**
|
||||
* Create and send an HTTP request.
|
||||
*
|
||||
* Use an absolute path to override the base path of the client, or a
|
||||
* relative path to append to the base path of the client. The URL can
|
||||
* contain the query string as well.
|
||||
*
|
||||
* @param string $method HTTP method
|
||||
* @param string|UriInterface $uri URI object or string.
|
||||
* @param array $options Request options to apply.
|
||||
*
|
||||
* @return ResponseInterface
|
||||
* @throws GuzzleException
|
||||
*/
|
||||
public function request($method, $uri, array $options = []);
|
||||
|
||||
/**
|
||||
* Create and send an asynchronous HTTP request.
|
||||
*
|
||||
* Use an absolute path to override the base path of the client, or a
|
||||
* relative path to append to the base path of the client. The URL can
|
||||
* contain the query string as well. Use an array to provide a URL
|
||||
* template and additional variables to use in the URL template expansion.
|
||||
*
|
||||
* @param string $method HTTP method
|
||||
* @param string|UriInterface $uri URI object or string.
|
||||
* @param array $options Request options to apply.
|
||||
*
|
||||
* @return PromiseInterface
|
||||
*/
|
||||
public function requestAsync($method, $uri, array $options = []);
|
||||
|
||||
/**
|
||||
* Get a client configuration option.
|
||||
*
|
||||
* These options include default request options of the client, a "handler"
|
||||
* (if utilized by the concrete client), and a "base_uri" if utilized by
|
||||
* the concrete client.
|
||||
*
|
||||
* @param string|null $option The config option to retrieve.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getConfig($option = null);
|
||||
}
|
277
server/vendor/guzzlehttp/guzzle/src/Cookie/CookieJar.php
vendored
Normal file
277
server/vendor/guzzlehttp/guzzle/src/Cookie/CookieJar.php
vendored
Normal file
|
@ -0,0 +1,277 @@
|
|||
<?php
|
||||
namespace GuzzleHttp\Cookie;
|
||||
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
/**
|
||||
* Cookie jar that stores cookies an an array
|
||||
*/
|
||||
class CookieJar implements CookieJarInterface
|
||||
{
|
||||
/** @var SetCookie[] Loaded cookie data */
|
||||
private $cookies = [];
|
||||
|
||||
/** @var bool */
|
||||
private $strictMode;
|
||||
|
||||
/**
|
||||
* @param bool $strictMode Set to true to throw exceptions when invalid
|
||||
* cookies are added to the cookie jar.
|
||||
* @param array $cookieArray Array of SetCookie objects or a hash of
|
||||
* arrays that can be used with the SetCookie
|
||||
* constructor
|
||||
*/
|
||||
public function __construct($strictMode = false, $cookieArray = [])
|
||||
{
|
||||
$this->strictMode = $strictMode;
|
||||
|
||||
foreach ($cookieArray as $cookie) {
|
||||
if (!($cookie instanceof SetCookie)) {
|
||||
$cookie = new SetCookie($cookie);
|
||||
}
|
||||
$this->setCookie($cookie);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new Cookie jar from an associative array and domain.
|
||||
*
|
||||
* @param array $cookies Cookies to create the jar from
|
||||
* @param string $domain Domain to set the cookies to
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public static function fromArray(array $cookies, $domain)
|
||||
{
|
||||
$cookieJar = new self();
|
||||
foreach ($cookies as $name => $value) {
|
||||
$cookieJar->setCookie(new SetCookie([
|
||||
'Domain' => $domain,
|
||||
'Name' => $name,
|
||||
'Value' => $value,
|
||||
'Discard' => true
|
||||
]));
|
||||
}
|
||||
|
||||
return $cookieJar;
|
||||
}
|
||||
|
||||
/**
|
||||
* Quote the cookie value if it is not already quoted and it contains
|
||||
* problematic characters.
|
||||
*
|
||||
* @param string $value Value that may or may not need to be quoted
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public static function getCookieValue($value)
|
||||
{
|
||||
if (substr($value, 0, 1) !== '"' &&
|
||||
substr($value, -1, 1) !== '"' &&
|
||||
strpbrk($value, ';,=')
|
||||
) {
|
||||
$value = '"' . $value . '"';
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Evaluate if this cookie should be persisted to storage
|
||||
* that survives between requests.
|
||||
*
|
||||
* @param SetCookie $cookie Being evaluated.
|
||||
* @param bool $allowSessionCookies If we should persist session cookies
|
||||
* @return bool
|
||||
*/
|
||||
public static function shouldPersist(
|
||||
SetCookie $cookie,
|
||||
$allowSessionCookies = false
|
||||
) {
|
||||
if ($cookie->getExpires() || $allowSessionCookies) {
|
||||
if (!$cookie->getDiscard()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public function toArray()
|
||||
{
|
||||
return array_map(function (SetCookie $cookie) {
|
||||
return $cookie->toArray();
|
||||
}, $this->getIterator()->getArrayCopy());
|
||||
}
|
||||
|
||||
public function clear($domain = null, $path = null, $name = null)
|
||||
{
|
||||
if (!$domain) {
|
||||
$this->cookies = [];
|
||||
return;
|
||||
} elseif (!$path) {
|
||||
$this->cookies = array_filter(
|
||||
$this->cookies,
|
||||
function (SetCookie $cookie) use ($path, $domain) {
|
||||
return !$cookie->matchesDomain($domain);
|
||||
}
|
||||
);
|
||||
} elseif (!$name) {
|
||||
$this->cookies = array_filter(
|
||||
$this->cookies,
|
||||
function (SetCookie $cookie) use ($path, $domain) {
|
||||
return !($cookie->matchesPath($path) &&
|
||||
$cookie->matchesDomain($domain));
|
||||
}
|
||||
);
|
||||
} else {
|
||||
$this->cookies = array_filter(
|
||||
$this->cookies,
|
||||
function (SetCookie $cookie) use ($path, $domain, $name) {
|
||||
return !($cookie->getName() == $name &&
|
||||
$cookie->matchesPath($path) &&
|
||||
$cookie->matchesDomain($domain));
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public function clearSessionCookies()
|
||||
{
|
||||
$this->cookies = array_filter(
|
||||
$this->cookies,
|
||||
function (SetCookie $cookie) {
|
||||
return !$cookie->getDiscard() && $cookie->getExpires();
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
public function setCookie(SetCookie $cookie)
|
||||
{
|
||||
// If the name string is empty (but not 0), ignore the set-cookie
|
||||
// string entirely.
|
||||
$name = $cookie->getName();
|
||||
if (!$name && $name !== '0') {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only allow cookies with set and valid domain, name, value
|
||||
$result = $cookie->validate();
|
||||
if ($result !== true) {
|
||||
if ($this->strictMode) {
|
||||
throw new \RuntimeException('Invalid cookie: ' . $result);
|
||||
} else {
|
||||
$this->removeCookieIfEmpty($cookie);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// Resolve conflicts with previously set cookies
|
||||
foreach ($this->cookies as $i => $c) {
|
||||
|
||||
// Two cookies are identical, when their path, and domain are
|
||||
// identical.
|
||||
if ($c->getPath() != $cookie->getPath() ||
|
||||
$c->getDomain() != $cookie->getDomain() ||
|
||||
$c->getName() != $cookie->getName()
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// The previously set cookie is a discard cookie and this one is
|
||||
// not so allow the new cookie to be set
|
||||
if (!$cookie->getDiscard() && $c->getDiscard()) {
|
||||
unset($this->cookies[$i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the new cookie's expiration is further into the future, then
|
||||
// replace the old cookie
|
||||
if ($cookie->getExpires() > $c->getExpires()) {
|
||||
unset($this->cookies[$i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the value has changed, we better change it
|
||||
if ($cookie->getValue() !== $c->getValue()) {
|
||||
unset($this->cookies[$i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
// The cookie exists, so no need to continue
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->cookies[] = $cookie;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function count()
|
||||
{
|
||||
return count($this->cookies);
|
||||
}
|
||||
|
||||
public function getIterator()
|
||||
{
|
||||
return new \ArrayIterator(array_values($this->cookies));
|
||||
}
|
||||
|
||||
public function extractCookies(
|
||||
RequestInterface $request,
|
||||
ResponseInterface $response
|
||||
) {
|
||||
if ($cookieHeader = $response->getHeader('Set-Cookie')) {
|
||||
foreach ($cookieHeader as $cookie) {
|
||||
$sc = SetCookie::fromString($cookie);
|
||||
if (!$sc->getDomain()) {
|
||||
$sc->setDomain($request->getUri()->getHost());
|
||||
}
|
||||
$this->setCookie($sc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function withCookieHeader(RequestInterface $request)
|
||||
{
|
||||
$values = [];
|
||||
$uri = $request->getUri();
|
||||
$scheme = $uri->getScheme();
|
||||
$host = $uri->getHost();
|
||||
$path = $uri->getPath() ?: '/';
|
||||
|
||||
foreach ($this->cookies as $cookie) {
|
||||
if ($cookie->matchesPath($path) &&
|
||||
$cookie->matchesDomain($host) &&
|
||||
!$cookie->isExpired() &&
|
||||
(!$cookie->getSecure() || $scheme == 'https')
|
||||
) {
|
||||
$values[] = $cookie->getName() . '='
|
||||
. self::getCookieValue($cookie->getValue());
|
||||
}
|
||||
}
|
||||
|
||||
return $values
|
||||
? $request->withHeader('Cookie', implode('; ', $values))
|
||||
: $request;
|
||||
}
|
||||
|
||||
/**
|
||||
* If a cookie already exists and the server asks to set it again with a
|
||||
* null value, the cookie must be deleted.
|
||||
*
|
||||
* @param SetCookie $cookie
|
||||
*/
|
||||
private function removeCookieIfEmpty(SetCookie $cookie)
|
||||
{
|
||||
$cookieValue = $cookie->getValue();
|
||||
if ($cookieValue === null || $cookieValue === '') {
|
||||
$this->clear(
|
||||
$cookie->getDomain(),
|
||||
$cookie->getPath(),
|
||||
$cookie->getName()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
84
server/vendor/guzzlehttp/guzzle/src/Cookie/CookieJarInterface.php
vendored
Normal file
84
server/vendor/guzzlehttp/guzzle/src/Cookie/CookieJarInterface.php
vendored
Normal file
|
@ -0,0 +1,84 @@
|
|||
<?php
|
||||
namespace GuzzleHttp\Cookie;
|
||||
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
/**
|
||||
* Stores HTTP cookies.
|
||||
*
|
||||
* It extracts cookies from HTTP requests, and returns them in HTTP responses.
|
||||
* CookieJarInterface instances automatically expire contained cookies when
|
||||
* necessary. Subclasses are also responsible for storing and retrieving
|
||||
* cookies from a file, database, etc.
|
||||
*
|
||||
* @link http://docs.python.org/2/library/cookielib.html Inspiration
|
||||
*/
|
||||
interface CookieJarInterface extends \Countable, \IteratorAggregate
|
||||
{
|
||||
/**
|
||||
* Create a request with added cookie headers.
|
||||
*
|
||||
* If no matching cookies are found in the cookie jar, then no Cookie
|
||||
* header is added to the request and the same request is returned.
|
||||
*
|
||||
* @param RequestInterface $request Request object to modify.
|
||||
*
|
||||
* @return RequestInterface returns the modified request.
|
||||
*/
|
||||
public function withCookieHeader(RequestInterface $request);
|
||||
|
||||
/**
|
||||
* Extract cookies from an HTTP response and store them in the CookieJar.
|
||||
*
|
||||
* @param RequestInterface $request Request that was sent
|
||||
* @param ResponseInterface $response Response that was received
|
||||
*/
|
||||
public function extractCookies(
|
||||
RequestInterface $request,
|
||||
ResponseInterface $response
|
||||
);
|
||||
|
||||
/**
|
||||
* Sets a cookie in the cookie jar.
|
||||
*
|
||||
* @param SetCookie $cookie Cookie to set.
|
||||
*
|
||||
* @return bool Returns true on success or false on failure
|
||||
*/
|
||||
public function setCookie(SetCookie $cookie);
|
||||
|
||||
/**
|
||||
* Remove cookies currently held in the cookie jar.
|
||||
*
|
||||
* Invoking this method without arguments will empty the whole cookie jar.
|
||||
* If given a $domain argument only cookies belonging to that domain will
|
||||
* be removed. If given a $domain and $path argument, cookies belonging to
|
||||
* the specified path within that domain are removed. If given all three
|
||||
* arguments, then the cookie with the specified name, path and domain is
|
||||
* removed.
|
||||
*
|
||||
* @param string $domain Clears cookies matching a domain
|
||||
* @param string $path Clears cookies matching a domain and path
|
||||
* @param string $name Clears cookies matching a domain, path, and name
|
||||
*
|
||||
* @return CookieJarInterface
|
||||
*/
|
||||
public function clear($domain = null, $path = null, $name = null);
|
||||
|
||||
/**
|
||||
* Discard all sessions cookies.
|
||||
*
|
||||
* Removes cookies that don't have an expire field or a have a discard
|
||||
* field set to true. To be called when the user agent shuts down according
|
||||
* to RFC 2965.
|
||||
*/
|
||||
public function clearSessionCookies();
|
||||
|
||||
/**
|
||||
* Converts the cookie jar to an array.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function toArray();
|
||||
}
|
87
server/vendor/guzzlehttp/guzzle/src/Cookie/FileCookieJar.php
vendored
Normal file
87
server/vendor/guzzlehttp/guzzle/src/Cookie/FileCookieJar.php
vendored
Normal file
|
@ -0,0 +1,87 @@
|
|||
<?php
|
||||
namespace GuzzleHttp\Cookie;
|
||||
|
||||
/**
|
||||
* Persists non-session cookies using a JSON formatted file
|
||||
*/
|
||||
class FileCookieJar extends CookieJar
|
||||
{
|
||||
/** @var string filename */
|
||||
private $filename;
|
||||
|
||||
/** @var bool Control whether to persist session cookies or not. */
|
||||
private $storeSessionCookies;
|
||||
|
||||
/**
|
||||
* Create a new FileCookieJar object
|
||||
*
|
||||
* @param string $cookieFile File to store the cookie data
|
||||
* @param bool $storeSessionCookies Set to true to store session cookies
|
||||
* in the cookie jar.
|
||||
*
|
||||
* @throws \RuntimeException if the file cannot be found or created
|
||||
*/
|
||||
public function __construct($cookieFile, $storeSessionCookies = false)
|
||||
{
|
||||
$this->filename = $cookieFile;
|
||||
$this->storeSessionCookies = $storeSessionCookies;
|
||||
|
||||
if (file_exists($cookieFile)) {
|
||||
$this->load($cookieFile);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the file when shutting down
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
$this->save($this->filename);
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves the cookies to a file.
|
||||
*
|
||||
* @param string $filename File to save
|
||||
* @throws \RuntimeException if the file cannot be found or created
|
||||
*/
|
||||
public function save($filename)
|
||||
{
|
||||
$json = [];
|
||||
foreach ($this as $cookie) {
|
||||
/** @var SetCookie $cookie */
|
||||
if (CookieJar::shouldPersist($cookie, $this->storeSessionCookies)) {
|
||||
$json[] = $cookie->toArray();
|
||||
}
|
||||
}
|
||||
|
||||
if (false === file_put_contents($filename, json_encode($json))) {
|
||||
throw new \RuntimeException("Unable to save file {$filename}");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Load cookies from a JSON formatted file.
|
||||
*
|
||||
* Old cookies are kept unless overwritten by newly loaded ones.
|
||||
*
|
||||
* @param string $filename Cookie file to load.
|
||||
* @throws \RuntimeException if the file cannot be loaded.
|
||||
*/
|
||||
public function load($filename)
|
||||
{
|
||||
$json = file_get_contents($filename);
|
||||
if (false === $json) {
|
||||
throw new \RuntimeException("Unable to load file {$filename}");
|
||||
}
|
||||
|
||||
$data = json_decode($json, true);
|
||||
if (is_array($data)) {
|
||||
foreach (json_decode($json, true) as $cookie) {
|
||||
$this->setCookie(new SetCookie($cookie));
|
||||
}
|
||||
} elseif (strlen($data)) {
|
||||
throw new \RuntimeException("Invalid cookie file: {$filename}");
|
||||
}
|
||||
}
|
||||
}
|
72
server/vendor/guzzlehttp/guzzle/src/Cookie/SessionCookieJar.php
vendored
Normal file
72
server/vendor/guzzlehttp/guzzle/src/Cookie/SessionCookieJar.php
vendored
Normal file
|
@ -0,0 +1,72 @@
|
|||
<?php
|
||||
namespace GuzzleHttp\Cookie;
|
||||
|
||||
/**
|
||||
* Persists cookies in the client session
|
||||
*/
|
||||
class SessionCookieJar extends CookieJar
|
||||
{
|
||||
/** @var string session key */
|
||||
private $sessionKey;
|
||||
|
||||
/** @var bool Control whether to persist session cookies or not. */
|
||||
private $storeSessionCookies;
|
||||
|
||||
/**
|
||||
* Create a new SessionCookieJar object
|
||||
*
|
||||
* @param string $sessionKey Session key name to store the cookie
|
||||
* data in session
|
||||
* @param bool $storeSessionCookies Set to true to store session cookies
|
||||
* in the cookie jar.
|
||||
*/
|
||||
public function __construct($sessionKey, $storeSessionCookies = false)
|
||||
{
|
||||
$this->sessionKey = $sessionKey;
|
||||
$this->storeSessionCookies = $storeSessionCookies;
|
||||
$this->load();
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves cookies to session when shutting down
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
$this->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Save cookies to the client session
|
||||
*/
|
||||
public function save()
|
||||
{
|
||||
$json = [];
|
||||
foreach ($this as $cookie) {
|
||||
/** @var SetCookie $cookie */
|
||||
if (CookieJar::shouldPersist($cookie, $this->storeSessionCookies)) {
|
||||
$json[] = $cookie->toArray();
|
||||
}
|
||||
}
|
||||
|
||||
$_SESSION[$this->sessionKey] = json_encode($json);
|
||||
}
|
||||
|
||||
/**
|
||||
* Load the contents of the client session into the data array
|
||||
*/
|
||||
protected function load()
|
||||
{
|
||||
$cookieJar = isset($_SESSION[$this->sessionKey])
|
||||
? $_SESSION[$this->sessionKey]
|
||||
: null;
|
||||
|
||||
$data = json_decode($cookieJar, true);
|
||||
if (is_array($data)) {
|
||||
foreach ($data as $cookie) {
|
||||
$this->setCookie(new SetCookie($cookie));
|
||||
}
|
||||
} elseif (strlen($data)) {
|
||||
throw new \RuntimeException("Invalid cookie data");
|
||||
}
|
||||
}
|
||||
}
|
404
server/vendor/guzzlehttp/guzzle/src/Cookie/SetCookie.php
vendored
Normal file
404
server/vendor/guzzlehttp/guzzle/src/Cookie/SetCookie.php
vendored
Normal file
|
@ -0,0 +1,404 @@
|
|||
<?php
|
||||
namespace GuzzleHttp\Cookie;
|
||||
|
||||
/**
|
||||
* Set-Cookie object
|
||||
*/
|
||||
class SetCookie
|
||||
{
|
||||
/** @var array */
|
||||
private static $defaults = [
|
||||
'Name' => null,
|
||||
'Value' => null,
|
||||
'Domain' => null,
|
||||
'Path' => '/',
|
||||
'Max-Age' => null,
|
||||
'Expires' => null,
|
||||
'Secure' => false,
|
||||
'Discard' => false,
|
||||
'HttpOnly' => false
|
||||
];
|
||||
|
||||
/** @var array Cookie data */
|
||||
private $data;
|
||||
|
||||
/**
|
||||
* Create a new SetCookie object from a string
|
||||
*
|
||||
* @param string $cookie Set-Cookie header string
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public static function fromString($cookie)
|
||||
{
|
||||
// Create the default return array
|
||||
$data = self::$defaults;
|
||||
// Explode the cookie string using a series of semicolons
|
||||
$pieces = array_filter(array_map('trim', explode(';', $cookie)));
|
||||
// The name of the cookie (first kvp) must include an equal sign.
|
||||
if (empty($pieces) || !strpos($pieces[0], '=')) {
|
||||
return new self($data);
|
||||
}
|
||||
|
||||
// Add the cookie pieces into the parsed data array
|
||||
foreach ($pieces as $part) {
|
||||
|
||||
$cookieParts = explode('=', $part, 2);
|
||||
$key = trim($cookieParts[0]);
|
||||
$value = isset($cookieParts[1])
|
||||
? trim($cookieParts[1], " \n\r\t\0\x0B")
|
||||
: true;
|
||||
|
||||
// Only check for non-cookies when cookies have been found
|
||||
if (empty($data['Name'])) {
|
||||
$data['Name'] = $key;
|
||||
$data['Value'] = $value;
|
||||
} else {
|
||||
foreach (array_keys(self::$defaults) as $search) {
|
||||
if (!strcasecmp($search, $key)) {
|
||||
$data[$search] = $value;
|
||||
continue 2;
|
||||
}
|
||||
}
|
||||
$data[$key] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
return new self($data);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array $data Array of cookie data provided by a Cookie parser
|
||||
*/
|
||||
public function __construct(array $data = [])
|
||||
{
|
||||
$this->data = array_replace(self::$defaults, $data);
|
||||
// Extract the Expires value and turn it into a UNIX timestamp if needed
|
||||
if (!$this->getExpires() && $this->getMaxAge()) {
|
||||
// Calculate the Expires date
|
||||
$this->setExpires(time() + $this->getMaxAge());
|
||||
} elseif ($this->getExpires() && !is_numeric($this->getExpires())) {
|
||||
$this->setExpires($this->getExpires());
|
||||
}
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
$str = $this->data['Name'] . '=' . $this->data['Value'] . '; ';
|
||||
foreach ($this->data as $k => $v) {
|
||||
if ($k != 'Name' && $k != 'Value' && $v !== null && $v !== false) {
|
||||
if ($k == 'Expires') {
|
||||
$str .= 'Expires=' . gmdate('D, d M Y H:i:s \G\M\T', $v) . '; ';
|
||||
} else {
|
||||
$str .= ($v === true ? $k : "{$k}={$v}") . '; ';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rtrim($str, '; ');
|
||||
}
|
||||
|
||||
public function toArray()
|
||||
{
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the cookie name
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getName()
|
||||
{
|
||||
return $this->data['Name'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the cookie name
|
||||
*
|
||||
* @param string $name Cookie name
|
||||
*/
|
||||
public function setName($name)
|
||||
{
|
||||
$this->data['Name'] = $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the cookie value
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getValue()
|
||||
{
|
||||
return $this->data['Value'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the cookie value
|
||||
*
|
||||
* @param string $value Cookie value
|
||||
*/
|
||||
public function setValue($value)
|
||||
{
|
||||
$this->data['Value'] = $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the domain
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public function getDomain()
|
||||
{
|
||||
return $this->data['Domain'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the domain of the cookie
|
||||
*
|
||||
* @param string $domain
|
||||
*/
|
||||
public function setDomain($domain)
|
||||
{
|
||||
$this->data['Domain'] = $domain;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the path
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getPath()
|
||||
{
|
||||
return $this->data['Path'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the path of the cookie
|
||||
*
|
||||
* @param string $path Path of the cookie
|
||||
*/
|
||||
public function setPath($path)
|
||||
{
|
||||
$this->data['Path'] = $path;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maximum lifetime of the cookie in seconds
|
||||
*
|
||||
* @return int|null
|
||||
*/
|
||||
public function getMaxAge()
|
||||
{
|
||||
return $this->data['Max-Age'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the max-age of the cookie
|
||||
*
|
||||
* @param int $maxAge Max age of the cookie in seconds
|
||||
*/
|
||||
public function setMaxAge($maxAge)
|
||||
{
|
||||
$this->data['Max-Age'] = $maxAge;
|
||||
}
|
||||
|
||||
/**
|
||||
* The UNIX timestamp when the cookie Expires
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getExpires()
|
||||
{
|
||||
return $this->data['Expires'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the unix timestamp for which the cookie will expire
|
||||
*
|
||||
* @param int $timestamp Unix timestamp
|
||||
*/
|
||||
public function setExpires($timestamp)
|
||||
{
|
||||
$this->data['Expires'] = is_numeric($timestamp)
|
||||
? (int) $timestamp
|
||||
: strtotime($timestamp);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get whether or not this is a secure cookie
|
||||
*
|
||||
* @return null|bool
|
||||
*/
|
||||
public function getSecure()
|
||||
{
|
||||
return $this->data['Secure'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether or not the cookie is secure
|
||||
*
|
||||
* @param bool $secure Set to true or false if secure
|
||||
*/
|
||||
public function setSecure($secure)
|
||||
{
|
||||
$this->data['Secure'] = $secure;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get whether or not this is a session cookie
|
||||
*
|
||||
* @return null|bool
|
||||
*/
|
||||
public function getDiscard()
|
||||
{
|
||||
return $this->data['Discard'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether or not this is a session cookie
|
||||
*
|
||||
* @param bool $discard Set to true or false if this is a session cookie
|
||||
*/
|
||||
public function setDiscard($discard)
|
||||
{
|
||||
$this->data['Discard'] = $discard;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get whether or not this is an HTTP only cookie
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function getHttpOnly()
|
||||
{
|
||||
return $this->data['HttpOnly'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Set whether or not this is an HTTP only cookie
|
||||
*
|
||||
* @param bool $httpOnly Set to true or false if this is HTTP only
|
||||
*/
|
||||
public function setHttpOnly($httpOnly)
|
||||
{
|
||||
$this->data['HttpOnly'] = $httpOnly;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the cookie matches a path value.
|
||||
*
|
||||
* A request-path path-matches a given cookie-path if at least one of
|
||||
* the following conditions holds:
|
||||
*
|
||||
* - The cookie-path and the request-path are identical.
|
||||
* - The cookie-path is a prefix of the request-path, and the last
|
||||
* character of the cookie-path is %x2F ("/").
|
||||
* - The cookie-path is a prefix of the request-path, and the first
|
||||
* character of the request-path that is not included in the cookie-
|
||||
* path is a %x2F ("/") character.
|
||||
*
|
||||
* @param string $requestPath Path to check against
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function matchesPath($requestPath)
|
||||
{
|
||||
$cookiePath = $this->getPath();
|
||||
|
||||
// Match on exact matches or when path is the default empty "/"
|
||||
if ($cookiePath == '/' || $cookiePath == $requestPath) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Ensure that the cookie-path is a prefix of the request path.
|
||||
if (0 !== strpos($requestPath, $cookiePath)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Match if the last character of the cookie-path is "/"
|
||||
if (substr($cookiePath, -1, 1) == '/') {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Match if the first character not included in cookie path is "/"
|
||||
return substr($requestPath, strlen($cookiePath), 1) == '/';
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the cookie matches a domain value
|
||||
*
|
||||
* @param string $domain Domain to check against
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function matchesDomain($domain)
|
||||
{
|
||||
// Remove the leading '.' as per spec in RFC 6265.
|
||||
// http://tools.ietf.org/html/rfc6265#section-5.2.3
|
||||
$cookieDomain = ltrim($this->getDomain(), '.');
|
||||
|
||||
// Domain not set or exact match.
|
||||
if (!$cookieDomain || !strcasecmp($domain, $cookieDomain)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Matching the subdomain according to RFC 6265.
|
||||
// http://tools.ietf.org/html/rfc6265#section-5.1.3
|
||||
if (filter_var($domain, FILTER_VALIDATE_IP)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return (bool) preg_match('/\.' . preg_quote($cookieDomain) . '$/', $domain);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the cookie is expired
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isExpired()
|
||||
{
|
||||
return $this->getExpires() && time() > $this->getExpires();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the cookie is valid according to RFC 6265
|
||||
*
|
||||
* @return bool|string Returns true if valid or an error message if invalid
|
||||
*/
|
||||
public function validate()
|
||||
{
|
||||
// Names must not be empty, but can be 0
|
||||
$name = $this->getName();
|
||||
if (empty($name) && !is_numeric($name)) {
|
||||
return 'The cookie name must not be empty';
|
||||
}
|
||||
|
||||
// Check if any of the invalid characters are present in the cookie name
|
||||
if (preg_match(
|
||||
'/[\x00-\x20\x22\x28-\x29\x2c\x2f\x3a-\x40\x5c\x7b\x7d\x7f]/',
|
||||
$name)
|
||||
) {
|
||||
return 'Cookie name must not contain invalid characters: ASCII '
|
||||
. 'Control characters (0-31;127), space, tab and the '
|
||||
. 'following characters: ()<>@,;:\"/?={}';
|
||||
}
|
||||
|
||||
// Value must not be empty, but can be 0
|
||||
$value = $this->getValue();
|
||||
if (empty($value) && !is_numeric($value)) {
|
||||
return 'The cookie value must not be empty';
|
||||
}
|
||||
|
||||
// Domains must not be empty, but can be 0
|
||||
// A "0" is not a valid internet domain, but may be used as server name
|
||||
// in a private network.
|
||||
$domain = $this->getDomain();
|
||||
if (empty($domain) && !is_numeric($domain)) {
|
||||
return 'The cookie domain must not be empty';
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
7
server/vendor/guzzlehttp/guzzle/src/Exception/BadResponseException.php
vendored
Normal file
7
server/vendor/guzzlehttp/guzzle/src/Exception/BadResponseException.php
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
<?php
|
||||
namespace GuzzleHttp\Exception;
|
||||
|
||||
/**
|
||||
* Exception when an HTTP error occurs (4xx or 5xx error)
|
||||
*/
|
||||
class BadResponseException extends RequestException {}
|
7
server/vendor/guzzlehttp/guzzle/src/Exception/ClientException.php
vendored
Normal file
7
server/vendor/guzzlehttp/guzzle/src/Exception/ClientException.php
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
<?php
|
||||
namespace GuzzleHttp\Exception;
|
||||
|
||||
/**
|
||||
* Exception when a client error is encountered (4xx codes)
|
||||
*/
|
||||
class ClientException extends BadResponseException {}
|
37
server/vendor/guzzlehttp/guzzle/src/Exception/ConnectException.php
vendored
Normal file
37
server/vendor/guzzlehttp/guzzle/src/Exception/ConnectException.php
vendored
Normal file
|
@ -0,0 +1,37 @@
|
|||
<?php
|
||||
namespace GuzzleHttp\Exception;
|
||||
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
|
||||
/**
|
||||
* Exception thrown when a connection cannot be established.
|
||||
*
|
||||
* Note that no response is present for a ConnectException
|
||||
*/
|
||||
class ConnectException extends RequestException
|
||||
{
|
||||
public function __construct(
|
||||
$message,
|
||||
RequestInterface $request,
|
||||
\Exception $previous = null,
|
||||
array $handlerContext = []
|
||||
) {
|
||||
parent::__construct($message, $request, null, $previous, $handlerContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return null
|
||||
*/
|
||||
public function getResponse()
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
public function hasResponse()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
4
server/vendor/guzzlehttp/guzzle/src/Exception/GuzzleException.php
vendored
Normal file
4
server/vendor/guzzlehttp/guzzle/src/Exception/GuzzleException.php
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
<?php
|
||||
namespace GuzzleHttp\Exception;
|
||||
|
||||
interface GuzzleException {}
|
188
server/vendor/guzzlehttp/guzzle/src/Exception/RequestException.php
vendored
Normal file
188
server/vendor/guzzlehttp/guzzle/src/Exception/RequestException.php
vendored
Normal file
|
@ -0,0 +1,188 @@
|
|||
<?php
|
||||
namespace GuzzleHttp\Exception;
|
||||
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use GuzzleHttp\Promise\PromiseInterface;
|
||||
|
||||
/**
|
||||
* HTTP Request exception
|
||||
*/
|
||||
class RequestException extends TransferException
|
||||
{
|
||||
/** @var RequestInterface */
|
||||
private $request;
|
||||
|
||||
/** @var ResponseInterface */
|
||||
private $response;
|
||||
|
||||
/** @var array */
|
||||
private $handlerContext;
|
||||
|
||||
public function __construct(
|
||||
$message,
|
||||
RequestInterface $request,
|
||||
ResponseInterface $response = null,
|
||||
\Exception $previous = null,
|
||||
array $handlerContext = []
|
||||
) {
|
||||
// Set the code of the exception if the response is set and not future.
|
||||
$code = $response && !($response instanceof PromiseInterface)
|
||||
? $response->getStatusCode()
|
||||
: 0;
|
||||
parent::__construct($message, $code, $previous);
|
||||
$this->request = $request;
|
||||
$this->response = $response;
|
||||
$this->handlerContext = $handlerContext;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrap non-RequestExceptions with a RequestException
|
||||
*
|
||||
* @param RequestInterface $request
|
||||
* @param \Exception $e
|
||||
*
|
||||
* @return RequestException
|
||||
*/
|
||||
public static function wrapException(RequestInterface $request, \Exception $e)
|
||||
{
|
||||
return $e instanceof RequestException
|
||||
? $e
|
||||
: new RequestException($e->getMessage(), $request, null, $e);
|
||||
}
|
||||
|
||||
/**
|
||||
* Factory method to create a new exception with a normalized error message
|
||||
*
|
||||
* @param RequestInterface $request Request
|
||||
* @param ResponseInterface $response Response received
|
||||
* @param \Exception $previous Previous exception
|
||||
* @param array $ctx Optional handler context.
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public static function create(
|
||||
RequestInterface $request,
|
||||
ResponseInterface $response = null,
|
||||
\Exception $previous = null,
|
||||
array $ctx = []
|
||||
) {
|
||||
if (!$response) {
|
||||
return new self(
|
||||
'Error completing request',
|
||||
$request,
|
||||
null,
|
||||
$previous,
|
||||
$ctx
|
||||
);
|
||||
}
|
||||
|
||||
$level = floor($response->getStatusCode() / 100);
|
||||
if ($level == '4') {
|
||||
$label = 'Client error';
|
||||
$className = __NAMESPACE__ . '\\ClientException';
|
||||
} elseif ($level == '5') {
|
||||
$label = 'Server error';
|
||||
$className = __NAMESPACE__ . '\\ServerException';
|
||||
} else {
|
||||
$label = 'Unsuccessful request';
|
||||
$className = __CLASS__;
|
||||
}
|
||||
|
||||
// Server Error: `GET /` resulted in a `404 Not Found` response:
|
||||
// <html> ... (truncated)
|
||||
$message = sprintf(
|
||||
'%s: `%s` resulted in a `%s` response',
|
||||
$label,
|
||||
$request->getMethod() . ' ' . $request->getUri(),
|
||||
$response->getStatusCode() . ' ' . $response->getReasonPhrase()
|
||||
);
|
||||
|
||||
$summary = static::getResponseBodySummary($response);
|
||||
|
||||
if ($summary !== null) {
|
||||
$message .= ":\n{$summary}\n";
|
||||
}
|
||||
|
||||
return new $className($message, $request, $response, $previous, $ctx);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a short summary of the response
|
||||
*
|
||||
* Will return `null` if the response is not printable.
|
||||
*
|
||||
* @param ResponseInterface $response
|
||||
*
|
||||
* @return string|null
|
||||
*/
|
||||
public static function getResponseBodySummary(ResponseInterface $response)
|
||||
{
|
||||
$body = $response->getBody();
|
||||
|
||||
if (!$body->isSeekable()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$size = $body->getSize();
|
||||
$summary = $body->read(120);
|
||||
$body->rewind();
|
||||
|
||||
if ($size > 120) {
|
||||
$summary .= ' (truncated...)';
|
||||
}
|
||||
|
||||
// Matches any printable character, including unicode characters:
|
||||
// letters, marks, numbers, punctuation, spacing, and separators.
|
||||
if (preg_match('/[^\pL\pM\pN\pP\pS\pZ\n\r\t]/', $summary)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $summary;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the request that caused the exception
|
||||
*
|
||||
* @return RequestInterface
|
||||
*/
|
||||
public function getRequest()
|
||||
{
|
||||
return $this->request;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the associated response
|
||||
*
|
||||
* @return ResponseInterface|null
|
||||
*/
|
||||
public function getResponse()
|
||||
{
|
||||
return $this->response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a response was received
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasResponse()
|
||||
{
|
||||
return $this->response !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get contextual information about the error from the underlying handler.
|
||||
*
|
||||
* The contents of this array will vary depending on which handler you are
|
||||
* using. It may also be just an empty array. Relying on this data will
|
||||
* couple you to a specific handler, but can give more debug information
|
||||
* when needed.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getHandlerContext()
|
||||
{
|
||||
return $this->handlerContext;
|
||||
}
|
||||
}
|
27
server/vendor/guzzlehttp/guzzle/src/Exception/SeekException.php
vendored
Normal file
27
server/vendor/guzzlehttp/guzzle/src/Exception/SeekException.php
vendored
Normal file
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
namespace GuzzleHttp\Exception;
|
||||
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
|
||||
/**
|
||||
* Exception thrown when a seek fails on a stream.
|
||||
*/
|
||||
class SeekException extends \RuntimeException implements GuzzleException
|
||||
{
|
||||
private $stream;
|
||||
|
||||
public function __construct(StreamInterface $stream, $pos = 0, $msg = '')
|
||||
{
|
||||
$this->stream = $stream;
|
||||
$msg = $msg ?: 'Could not seek the stream to position ' . $pos;
|
||||
parent::__construct($msg);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return StreamInterface
|
||||
*/
|
||||
public function getStream()
|
||||
{
|
||||
return $this->stream;
|
||||
}
|
||||
}
|
7
server/vendor/guzzlehttp/guzzle/src/Exception/ServerException.php
vendored
Normal file
7
server/vendor/guzzlehttp/guzzle/src/Exception/ServerException.php
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
<?php
|
||||
namespace GuzzleHttp\Exception;
|
||||
|
||||
/**
|
||||
* Exception when a server error is encountered (5xx codes)
|
||||
*/
|
||||
class ServerException extends BadResponseException {}
|
4
server/vendor/guzzlehttp/guzzle/src/Exception/TooManyRedirectsException.php
vendored
Normal file
4
server/vendor/guzzlehttp/guzzle/src/Exception/TooManyRedirectsException.php
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
<?php
|
||||
namespace GuzzleHttp\Exception;
|
||||
|
||||
class TooManyRedirectsException extends RequestException {}
|
4
server/vendor/guzzlehttp/guzzle/src/Exception/TransferException.php
vendored
Normal file
4
server/vendor/guzzlehttp/guzzle/src/Exception/TransferException.php
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
<?php
|
||||
namespace GuzzleHttp\Exception;
|
||||
|
||||
class TransferException extends \RuntimeException implements GuzzleException {}
|
531
server/vendor/guzzlehttp/guzzle/src/Handler/CurlFactory.php
vendored
Normal file
531
server/vendor/guzzlehttp/guzzle/src/Handler/CurlFactory.php
vendored
Normal file
|
@ -0,0 +1,531 @@
|
|||
<?php
|
||||
namespace GuzzleHttp\Handler;
|
||||
|
||||
use GuzzleHttp\Exception\RequestException;
|
||||
use GuzzleHttp\Exception\ConnectException;
|
||||
use GuzzleHttp\Promise\FulfilledPromise;
|
||||
use GuzzleHttp\Promise\RejectedPromise;
|
||||
use GuzzleHttp\Psr7;
|
||||
use GuzzleHttp\Psr7\LazyOpenStream;
|
||||
use GuzzleHttp\TransferStats;
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
|
||||
/**
|
||||
* Creates curl resources from a request
|
||||
*/
|
||||
class CurlFactory implements CurlFactoryInterface
|
||||
{
|
||||
/** @var array */
|
||||
private $handles;
|
||||
|
||||
/** @var int Total number of idle handles to keep in cache */
|
||||
private $maxHandles;
|
||||
|
||||
/**
|
||||
* @param int $maxHandles Maximum number of idle handles.
|
||||
*/
|
||||
public function __construct($maxHandles)
|
||||
{
|
||||
$this->maxHandles = $maxHandles;
|
||||
}
|
||||
|
||||
public function create(RequestInterface $request, array $options)
|
||||
{
|
||||
if (isset($options['curl']['body_as_string'])) {
|
||||
$options['_body_as_string'] = $options['curl']['body_as_string'];
|
||||
unset($options['curl']['body_as_string']);
|
||||
}
|
||||
|
||||
$easy = new EasyHandle;
|
||||
$easy->request = $request;
|
||||
$easy->options = $options;
|
||||
$conf = $this->getDefaultConf($easy);
|
||||
$this->applyMethod($easy, $conf);
|
||||
$this->applyHandlerOptions($easy, $conf);
|
||||
$this->applyHeaders($easy, $conf);
|
||||
unset($conf['_headers']);
|
||||
|
||||
// Add handler options from the request configuration options
|
||||
if (isset($options['curl'])) {
|
||||
$conf = array_replace($conf, $options['curl']);
|
||||
}
|
||||
|
||||
$conf[CURLOPT_HEADERFUNCTION] = $this->createHeaderFn($easy);
|
||||
$easy->handle = $this->handles
|
||||
? array_pop($this->handles)
|
||||
: curl_init();
|
||||
curl_setopt_array($easy->handle, $conf);
|
||||
|
||||
return $easy;
|
||||
}
|
||||
|
||||
public function release(EasyHandle $easy)
|
||||
{
|
||||
$resource = $easy->handle;
|
||||
unset($easy->handle);
|
||||
|
||||
if (count($this->handles) >= $this->maxHandles) {
|
||||
curl_close($resource);
|
||||
} else {
|
||||
// Remove all callback functions as they can hold onto references
|
||||
// and are not cleaned up by curl_reset. Using curl_setopt_array
|
||||
// does not work for some reason, so removing each one
|
||||
// individually.
|
||||
curl_setopt($resource, CURLOPT_HEADERFUNCTION, null);
|
||||
curl_setopt($resource, CURLOPT_READFUNCTION, null);
|
||||
curl_setopt($resource, CURLOPT_WRITEFUNCTION, null);
|
||||
curl_setopt($resource, CURLOPT_PROGRESSFUNCTION, null);
|
||||
curl_reset($resource);
|
||||
$this->handles[] = $resource;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Completes a cURL transaction, either returning a response promise or a
|
||||
* rejected promise.
|
||||
*
|
||||
* @param callable $handler
|
||||
* @param EasyHandle $easy
|
||||
* @param CurlFactoryInterface $factory Dictates how the handle is released
|
||||
*
|
||||
* @return \GuzzleHttp\Promise\PromiseInterface
|
||||
*/
|
||||
public static function finish(
|
||||
callable $handler,
|
||||
EasyHandle $easy,
|
||||
CurlFactoryInterface $factory
|
||||
) {
|
||||
if (isset($easy->options['on_stats'])) {
|
||||
self::invokeStats($easy);
|
||||
}
|
||||
|
||||
if (!$easy->response || $easy->errno) {
|
||||
return self::finishError($handler, $easy, $factory);
|
||||
}
|
||||
|
||||
// Return the response if it is present and there is no error.
|
||||
$factory->release($easy);
|
||||
|
||||
// Rewind the body of the response if possible.
|
||||
$body = $easy->response->getBody();
|
||||
if ($body->isSeekable()) {
|
||||
$body->rewind();
|
||||
}
|
||||
|
||||
return new FulfilledPromise($easy->response);
|
||||
}
|
||||
|
||||
private static function invokeStats(EasyHandle $easy)
|
||||
{
|
||||
$curlStats = curl_getinfo($easy->handle);
|
||||
$stats = new TransferStats(
|
||||
$easy->request,
|
||||
$easy->response,
|
||||
$curlStats['total_time'],
|
||||
$easy->errno,
|
||||
$curlStats
|
||||
);
|
||||
call_user_func($easy->options['on_stats'], $stats);
|
||||
}
|
||||
|
||||
private static function finishError(
|
||||
callable $handler,
|
||||
EasyHandle $easy,
|
||||
CurlFactoryInterface $factory
|
||||
) {
|
||||
// Get error information and release the handle to the factory.
|
||||
$ctx = [
|
||||
'errno' => $easy->errno,
|
||||
'error' => curl_error($easy->handle),
|
||||
] + curl_getinfo($easy->handle);
|
||||
$factory->release($easy);
|
||||
|
||||
// Retry when nothing is present or when curl failed to rewind.
|
||||
if (empty($easy->options['_err_message'])
|
||||
&& (!$easy->errno || $easy->errno == 65)
|
||||
) {
|
||||
return self::retryFailedRewind($handler, $easy, $ctx);
|
||||
}
|
||||
|
||||
return self::createRejection($easy, $ctx);
|
||||
}
|
||||
|
||||
private static function createRejection(EasyHandle $easy, array $ctx)
|
||||
{
|
||||
static $connectionErrors = [
|
||||
CURLE_OPERATION_TIMEOUTED => true,
|
||||
CURLE_COULDNT_RESOLVE_HOST => true,
|
||||
CURLE_COULDNT_CONNECT => true,
|
||||
CURLE_SSL_CONNECT_ERROR => true,
|
||||
CURLE_GOT_NOTHING => true,
|
||||
];
|
||||
|
||||
// If an exception was encountered during the onHeaders event, then
|
||||
// return a rejected promise that wraps that exception.
|
||||
if ($easy->onHeadersException) {
|
||||
return new RejectedPromise(
|
||||
new RequestException(
|
||||
'An error was encountered during the on_headers event',
|
||||
$easy->request,
|
||||
$easy->response,
|
||||
$easy->onHeadersException,
|
||||
$ctx
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$message = sprintf(
|
||||
'cURL error %s: %s (%s)',
|
||||
$ctx['errno'],
|
||||
$ctx['error'],
|
||||
'see http://curl.haxx.se/libcurl/c/libcurl-errors.html'
|
||||
);
|
||||
|
||||
// Create a connection exception if it was a specific error code.
|
||||
$error = isset($connectionErrors[$easy->errno])
|
||||
? new ConnectException($message, $easy->request, null, $ctx)
|
||||
: new RequestException($message, $easy->request, $easy->response, null, $ctx);
|
||||
|
||||
return new RejectedPromise($error);
|
||||
}
|
||||
|
||||
private function getDefaultConf(EasyHandle $easy)
|
||||
{
|
||||
$conf = [
|
||||
'_headers' => $easy->request->getHeaders(),
|
||||
CURLOPT_CUSTOMREQUEST => $easy->request->getMethod(),
|
||||
CURLOPT_URL => (string) $easy->request->getUri(),
|
||||
CURLOPT_RETURNTRANSFER => false,
|
||||
CURLOPT_HEADER => false,
|
||||
CURLOPT_CONNECTTIMEOUT => 150,
|
||||
];
|
||||
|
||||
if (defined('CURLOPT_PROTOCOLS')) {
|
||||
$conf[CURLOPT_PROTOCOLS] = CURLPROTO_HTTP | CURLPROTO_HTTPS;
|
||||
}
|
||||
|
||||
$version = $easy->request->getProtocolVersion();
|
||||
if ($version == 1.1) {
|
||||
$conf[CURLOPT_HTTP_VERSION] = CURL_HTTP_VERSION_1_1;
|
||||
} elseif ($version == 2.0) {
|
||||
$conf[CURLOPT_HTTP_VERSION] = CURL_HTTP_VERSION_2_0;
|
||||
} else {
|
||||
$conf[CURLOPT_HTTP_VERSION] = CURL_HTTP_VERSION_1_0;
|
||||
}
|
||||
|
||||
return $conf;
|
||||
}
|
||||
|
||||
private function applyMethod(EasyHandle $easy, array &$conf)
|
||||
{
|
||||
$body = $easy->request->getBody();
|
||||
$size = $body->getSize();
|
||||
|
||||
if ($size === null || $size > 0) {
|
||||
$this->applyBody($easy->request, $easy->options, $conf);
|
||||
return;
|
||||
}
|
||||
|
||||
$method = $easy->request->getMethod();
|
||||
if ($method === 'PUT' || $method === 'POST') {
|
||||
// See http://tools.ietf.org/html/rfc7230#section-3.3.2
|
||||
if (!$easy->request->hasHeader('Content-Length')) {
|
||||
$conf[CURLOPT_HTTPHEADER][] = 'Content-Length: 0';
|
||||
}
|
||||
} elseif ($method === 'HEAD') {
|
||||
$conf[CURLOPT_NOBODY] = true;
|
||||
unset(
|
||||
$conf[CURLOPT_WRITEFUNCTION],
|
||||
$conf[CURLOPT_READFUNCTION],
|
||||
$conf[CURLOPT_FILE],
|
||||
$conf[CURLOPT_INFILE]
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private function applyBody(RequestInterface $request, array $options, array &$conf)
|
||||
{
|
||||
$size = $request->hasHeader('Content-Length')
|
||||
? (int) $request->getHeaderLine('Content-Length')
|
||||
: null;
|
||||
|
||||
// Send the body as a string if the size is less than 1MB OR if the
|
||||
// [curl][body_as_string] request value is set.
|
||||
if (($size !== null && $size < 1000000) ||
|
||||
!empty($options['_body_as_string'])
|
||||
) {
|
||||
$conf[CURLOPT_POSTFIELDS] = (string) $request->getBody();
|
||||
// Don't duplicate the Content-Length header
|
||||
$this->removeHeader('Content-Length', $conf);
|
||||
$this->removeHeader('Transfer-Encoding', $conf);
|
||||
} else {
|
||||
$conf[CURLOPT_UPLOAD] = true;
|
||||
if ($size !== null) {
|
||||
$conf[CURLOPT_INFILESIZE] = $size;
|
||||
$this->removeHeader('Content-Length', $conf);
|
||||
}
|
||||
$body = $request->getBody();
|
||||
$conf[CURLOPT_READFUNCTION] = function ($ch, $fd, $length) use ($body) {
|
||||
return $body->read($length);
|
||||
};
|
||||
}
|
||||
|
||||
// If the Expect header is not present, prevent curl from adding it
|
||||
if (!$request->hasHeader('Expect')) {
|
||||
$conf[CURLOPT_HTTPHEADER][] = 'Expect:';
|
||||
}
|
||||
|
||||
// cURL sometimes adds a content-type by default. Prevent this.
|
||||
if (!$request->hasHeader('Content-Type')) {
|
||||
$conf[CURLOPT_HTTPHEADER][] = 'Content-Type:';
|
||||
}
|
||||
}
|
||||
|
||||
private function applyHeaders(EasyHandle $easy, array &$conf)
|
||||
{
|
||||
foreach ($conf['_headers'] as $name => $values) {
|
||||
foreach ($values as $value) {
|
||||
$conf[CURLOPT_HTTPHEADER][] = "$name: $value";
|
||||
}
|
||||
}
|
||||
|
||||
// Remove the Accept header if one was not set
|
||||
if (!$easy->request->hasHeader('Accept')) {
|
||||
$conf[CURLOPT_HTTPHEADER][] = 'Accept:';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a header from the options array.
|
||||
*
|
||||
* @param string $name Case-insensitive header to remove
|
||||
* @param array $options Array of options to modify
|
||||
*/
|
||||
private function removeHeader($name, array &$options)
|
||||
{
|
||||
foreach (array_keys($options['_headers']) as $key) {
|
||||
if (!strcasecmp($key, $name)) {
|
||||
unset($options['_headers'][$key]);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function applyHandlerOptions(EasyHandle $easy, array &$conf)
|
||||
{
|
||||
$options = $easy->options;
|
||||
if (isset($options['verify'])) {
|
||||
if ($options['verify'] === false) {
|
||||
unset($conf[CURLOPT_CAINFO]);
|
||||
$conf[CURLOPT_SSL_VERIFYHOST] = 0;
|
||||
$conf[CURLOPT_SSL_VERIFYPEER] = false;
|
||||
} else {
|
||||
$conf[CURLOPT_SSL_VERIFYHOST] = 2;
|
||||
$conf[CURLOPT_SSL_VERIFYPEER] = true;
|
||||
if (is_string($options['verify'])) {
|
||||
$conf[CURLOPT_CAINFO] = $options['verify'];
|
||||
if (!file_exists($options['verify'])) {
|
||||
throw new \InvalidArgumentException(
|
||||
"SSL CA bundle not found: {$options['verify']}"
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($options['decode_content'])) {
|
||||
$accept = $easy->request->getHeaderLine('Accept-Encoding');
|
||||
if ($accept) {
|
||||
$conf[CURLOPT_ENCODING] = $accept;
|
||||
} else {
|
||||
$conf[CURLOPT_ENCODING] = '';
|
||||
// Don't let curl send the header over the wire
|
||||
$conf[CURLOPT_HTTPHEADER][] = 'Accept-Encoding:';
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($options['sink'])) {
|
||||
$sink = $options['sink'];
|
||||
if (!is_string($sink)) {
|
||||
$sink = \GuzzleHttp\Psr7\stream_for($sink);
|
||||
} elseif (!is_dir(dirname($sink))) {
|
||||
// Ensure that the directory exists before failing in curl.
|
||||
throw new \RuntimeException(sprintf(
|
||||
'Directory %s does not exist for sink value of %s',
|
||||
dirname($sink),
|
||||
$sink
|
||||
));
|
||||
} else {
|
||||
$sink = new LazyOpenStream($sink, 'w+');
|
||||
}
|
||||
$easy->sink = $sink;
|
||||
$conf[CURLOPT_WRITEFUNCTION] = function ($ch, $write) use ($sink) {
|
||||
return $sink->write($write);
|
||||
};
|
||||
} else {
|
||||
// Use a default temp stream if no sink was set.
|
||||
$conf[CURLOPT_FILE] = fopen('php://temp', 'w+');
|
||||
$easy->sink = Psr7\stream_for($conf[CURLOPT_FILE]);
|
||||
}
|
||||
|
||||
if (isset($options['timeout'])) {
|
||||
$conf[CURLOPT_TIMEOUT_MS] = $options['timeout'] * 1000;
|
||||
}
|
||||
|
||||
if (isset($options['connect_timeout'])) {
|
||||
$conf[CURLOPT_CONNECTTIMEOUT_MS] = $options['connect_timeout'] * 1000;
|
||||
}
|
||||
|
||||
if (isset($options['proxy'])) {
|
||||
if (!is_array($options['proxy'])) {
|
||||
$conf[CURLOPT_PROXY] = $options['proxy'];
|
||||
} else {
|
||||
$scheme = $easy->request->getUri()->getScheme();
|
||||
if (isset($options['proxy'][$scheme])) {
|
||||
$host = $easy->request->getUri()->getHost();
|
||||
if (!isset($options['proxy']['no']) ||
|
||||
!\GuzzleHttp\is_host_in_noproxy($host, $options['proxy']['no'])
|
||||
) {
|
||||
$conf[CURLOPT_PROXY] = $options['proxy'][$scheme];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($options['cert'])) {
|
||||
$cert = $options['cert'];
|
||||
if (is_array($cert)) {
|
||||
$conf[CURLOPT_SSLCERTPASSWD] = $cert[1];
|
||||
$cert = $cert[0];
|
||||
}
|
||||
if (!file_exists($cert)) {
|
||||
throw new \InvalidArgumentException(
|
||||
"SSL certificate not found: {$cert}"
|
||||
);
|
||||
}
|
||||
$conf[CURLOPT_SSLCERT] = $cert;
|
||||
}
|
||||
|
||||
if (isset($options['ssl_key'])) {
|
||||
$sslKey = $options['ssl_key'];
|
||||
if (is_array($sslKey)) {
|
||||
$conf[CURLOPT_SSLKEYPASSWD] = $sslKey[1];
|
||||
$sslKey = $sslKey[0];
|
||||
}
|
||||
if (!file_exists($sslKey)) {
|
||||
throw new \InvalidArgumentException(
|
||||
"SSL private key not found: {$sslKey}"
|
||||
);
|
||||
}
|
||||
$conf[CURLOPT_SSLKEY] = $sslKey;
|
||||
}
|
||||
|
||||
if (isset($options['progress'])) {
|
||||
$progress = $options['progress'];
|
||||
if (!is_callable($progress)) {
|
||||
throw new \InvalidArgumentException(
|
||||
'progress client option must be callable'
|
||||
);
|
||||
}
|
||||
$conf[CURLOPT_NOPROGRESS] = false;
|
||||
$conf[CURLOPT_PROGRESSFUNCTION] = function () use ($progress) {
|
||||
$args = func_get_args();
|
||||
// PHP 5.5 pushed the handle onto the start of the args
|
||||
if (is_resource($args[0])) {
|
||||
array_shift($args);
|
||||
}
|
||||
call_user_func_array($progress, $args);
|
||||
};
|
||||
}
|
||||
|
||||
if (!empty($options['debug'])) {
|
||||
$conf[CURLOPT_STDERR] = \GuzzleHttp\debug_resource($options['debug']);
|
||||
$conf[CURLOPT_VERBOSE] = true;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This function ensures that a response was set on a transaction. If one
|
||||
* was not set, then the request is retried if possible. This error
|
||||
* typically means you are sending a payload, curl encountered a
|
||||
* "Connection died, retrying a fresh connect" error, tried to rewind the
|
||||
* stream, and then encountered a "necessary data rewind wasn't possible"
|
||||
* error, causing the request to be sent through curl_multi_info_read()
|
||||
* without an error status.
|
||||
*/
|
||||
private static function retryFailedRewind(
|
||||
callable $handler,
|
||||
EasyHandle $easy,
|
||||
array $ctx
|
||||
) {
|
||||
try {
|
||||
// Only rewind if the body has been read from.
|
||||
$body = $easy->request->getBody();
|
||||
if ($body->tell() > 0) {
|
||||
$body->rewind();
|
||||
}
|
||||
} catch (\RuntimeException $e) {
|
||||
$ctx['error'] = 'The connection unexpectedly failed without '
|
||||
. 'providing an error. The request would have been retried, '
|
||||
. 'but attempting to rewind the request body failed. '
|
||||
. 'Exception: ' . $e;
|
||||
return self::createRejection($easy, $ctx);
|
||||
}
|
||||
|
||||
// Retry no more than 3 times before giving up.
|
||||
if (!isset($easy->options['_curl_retries'])) {
|
||||
$easy->options['_curl_retries'] = 1;
|
||||
} elseif ($easy->options['_curl_retries'] == 2) {
|
||||
$ctx['error'] = 'The cURL request was retried 3 times '
|
||||
. 'and did not succeed. The most likely reason for the failure '
|
||||
. 'is that cURL was unable to rewind the body of the request '
|
||||
. 'and subsequent retries resulted in the same error. Turn on '
|
||||
. 'the debug option to see what went wrong. See '
|
||||
. 'https://bugs.php.net/bug.php?id=47204 for more information.';
|
||||
return self::createRejection($easy, $ctx);
|
||||
} else {
|
||||
$easy->options['_curl_retries']++;
|
||||
}
|
||||
|
||||
return $handler($easy->request, $easy->options);
|
||||
}
|
||||
|
||||
private function createHeaderFn(EasyHandle $easy)
|
||||
{
|
||||
if (!isset($easy->options['on_headers'])) {
|
||||
$onHeaders = null;
|
||||
} elseif (!is_callable($easy->options['on_headers'])) {
|
||||
throw new \InvalidArgumentException('on_headers must be callable');
|
||||
} else {
|
||||
$onHeaders = $easy->options['on_headers'];
|
||||
}
|
||||
|
||||
return function ($ch, $h) use (
|
||||
$onHeaders,
|
||||
$easy,
|
||||
&$startingResponse
|
||||
) {
|
||||
$value = trim($h);
|
||||
if ($value === '') {
|
||||
$startingResponse = true;
|
||||
$easy->createResponse();
|
||||
if ($onHeaders) {
|
||||
try {
|
||||
$onHeaders($easy->response);
|
||||
} catch (\Exception $e) {
|
||||
// Associate the exception with the handle and trigger
|
||||
// a curl header write error by returning 0.
|
||||
$easy->onHeadersException = $e;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
} elseif ($startingResponse) {
|
||||
$startingResponse = false;
|
||||
$easy->headers = [$value];
|
||||
} else {
|
||||
$easy->headers[] = $value;
|
||||
}
|
||||
return strlen($h);
|
||||
};
|
||||
}
|
||||
}
|
27
server/vendor/guzzlehttp/guzzle/src/Handler/CurlFactoryInterface.php
vendored
Normal file
27
server/vendor/guzzlehttp/guzzle/src/Handler/CurlFactoryInterface.php
vendored
Normal file
|
@ -0,0 +1,27 @@
|
|||
<?php
|
||||
namespace GuzzleHttp\Handler;
|
||||
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
|
||||
interface CurlFactoryInterface
|
||||
{
|
||||
/**
|
||||
* Creates a cURL handle resource.
|
||||
*
|
||||
* @param RequestInterface $request Request
|
||||
* @param array $options Transfer options
|
||||
*
|
||||
* @return EasyHandle
|
||||
* @throws \RuntimeException when an option cannot be applied
|
||||
*/
|
||||
public function create(RequestInterface $request, array $options);
|
||||
|
||||
/**
|
||||
* Release an easy handle, allowing it to be reused or closed.
|
||||
*
|
||||
* This function must call unset on the easy handle's "handle" property.
|
||||
*
|
||||
* @param EasyHandle $easy
|
||||
*/
|
||||
public function release(EasyHandle $easy);
|
||||
}
|
45
server/vendor/guzzlehttp/guzzle/src/Handler/CurlHandler.php
vendored
Normal file
45
server/vendor/guzzlehttp/guzzle/src/Handler/CurlHandler.php
vendored
Normal file
|
@ -0,0 +1,45 @@
|
|||
<?php
|
||||
namespace GuzzleHttp\Handler;
|
||||
|
||||
use GuzzleHttp\Psr7;
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
|
||||
/**
|
||||
* HTTP handler that uses cURL easy handles as a transport layer.
|
||||
*
|
||||
* When using the CurlHandler, custom curl options can be specified as an
|
||||
* associative array of curl option constants mapping to values in the
|
||||
* **curl** key of the "client" key of the request.
|
||||
*/
|
||||
class CurlHandler
|
||||
{
|
||||
/** @var CurlFactoryInterface */
|
||||
private $factory;
|
||||
|
||||
/**
|
||||
* Accepts an associative array of options:
|
||||
*
|
||||
* - factory: Optional curl factory used to create cURL handles.
|
||||
*
|
||||
* @param array $options Array of options to use with the handler
|
||||
*/
|
||||
public function __construct(array $options = [])
|
||||
{
|
||||
$this->factory = isset($options['handle_factory'])
|
||||
? $options['handle_factory']
|
||||
: new CurlFactory(3);
|
||||
}
|
||||
|
||||
public function __invoke(RequestInterface $request, array $options)
|
||||
{
|
||||
if (isset($options['delay'])) {
|
||||
usleep($options['delay'] * 1000);
|
||||
}
|
||||
|
||||
$easy = $this->factory->create($request, $options);
|
||||
curl_exec($easy->handle);
|
||||
$easy->errno = curl_errno($easy->handle);
|
||||
|
||||
return CurlFactory::finish($this, $easy, $this->factory);
|
||||
}
|
||||
}
|
197
server/vendor/guzzlehttp/guzzle/src/Handler/CurlMultiHandler.php
vendored
Normal file
197
server/vendor/guzzlehttp/guzzle/src/Handler/CurlMultiHandler.php
vendored
Normal file
|
@ -0,0 +1,197 @@
|
|||
<?php
|
||||
namespace GuzzleHttp\Handler;
|
||||
|
||||
use GuzzleHttp\Promise as P;
|
||||
use GuzzleHttp\Promise\Promise;
|
||||
use GuzzleHttp\Psr7;
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
|
||||
/**
|
||||
* Returns an asynchronous response using curl_multi_* functions.
|
||||
*
|
||||
* When using the CurlMultiHandler, custom curl options can be specified as an
|
||||
* associative array of curl option constants mapping to values in the
|
||||
* **curl** key of the provided request options.
|
||||
*
|
||||
* @property resource $_mh Internal use only. Lazy loaded multi-handle.
|
||||
*/
|
||||
class CurlMultiHandler
|
||||
{
|
||||
/** @var CurlFactoryInterface */
|
||||
private $factory;
|
||||
private $selectTimeout;
|
||||
private $active;
|
||||
private $handles = [];
|
||||
private $delays = [];
|
||||
|
||||
/**
|
||||
* This handler accepts the following options:
|
||||
*
|
||||
* - handle_factory: An optional factory used to create curl handles
|
||||
* - select_timeout: Optional timeout (in seconds) to block before timing
|
||||
* out while selecting curl handles. Defaults to 1 second.
|
||||
*
|
||||
* @param array $options
|
||||
*/
|
||||
public function __construct(array $options = [])
|
||||
{
|
||||
$this->factory = isset($options['handle_factory'])
|
||||
? $options['handle_factory'] : new CurlFactory(50);
|
||||
$this->selectTimeout = isset($options['select_timeout'])
|
||||
? $options['select_timeout'] : 1;
|
||||
}
|
||||
|
||||
public function __get($name)
|
||||
{
|
||||
if ($name === '_mh') {
|
||||
return $this->_mh = curl_multi_init();
|
||||
}
|
||||
|
||||
throw new \BadMethodCallException();
|
||||
}
|
||||
|
||||
public function __destruct()
|
||||
{
|
||||
if (isset($this->_mh)) {
|
||||
curl_multi_close($this->_mh);
|
||||
unset($this->_mh);
|
||||
}
|
||||
}
|
||||
|
||||
public function __invoke(RequestInterface $request, array $options)
|
||||
{
|
||||
$easy = $this->factory->create($request, $options);
|
||||
$id = (int) $easy->handle;
|
||||
|
||||
$promise = new Promise(
|
||||
[$this, 'execute'],
|
||||
function () use ($id) { return $this->cancel($id); }
|
||||
);
|
||||
|
||||
$this->addRequest(['easy' => $easy, 'deferred' => $promise]);
|
||||
|
||||
return $promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Ticks the curl event loop.
|
||||
*/
|
||||
public function tick()
|
||||
{
|
||||
// Add any delayed handles if needed.
|
||||
if ($this->delays) {
|
||||
$currentTime = microtime(true);
|
||||
foreach ($this->delays as $id => $delay) {
|
||||
if ($currentTime >= $delay) {
|
||||
unset($this->delays[$id]);
|
||||
curl_multi_add_handle(
|
||||
$this->_mh,
|
||||
$this->handles[$id]['easy']->handle
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Step through the task queue which may add additional requests.
|
||||
P\queue()->run();
|
||||
|
||||
if ($this->active &&
|
||||
curl_multi_select($this->_mh, $this->selectTimeout) === -1
|
||||
) {
|
||||
// Perform a usleep if a select returns -1.
|
||||
// See: https://bugs.php.net/bug.php?id=61141
|
||||
usleep(250);
|
||||
}
|
||||
|
||||
while (curl_multi_exec($this->_mh, $this->active) === CURLM_CALL_MULTI_PERFORM);
|
||||
|
||||
$this->processMessages();
|
||||
}
|
||||
|
||||
/**
|
||||
* Runs until all outstanding connections have completed.
|
||||
*/
|
||||
public function execute()
|
||||
{
|
||||
$queue = P\queue();
|
||||
|
||||
while ($this->handles || !$queue->isEmpty()) {
|
||||
// If there are no transfers, then sleep for the next delay
|
||||
if (!$this->active && $this->delays) {
|
||||
usleep($this->timeToNext());
|
||||
}
|
||||
$this->tick();
|
||||
}
|
||||
}
|
||||
|
||||
private function addRequest(array $entry)
|
||||
{
|
||||
$easy = $entry['easy'];
|
||||
$id = (int) $easy->handle;
|
||||
$this->handles[$id] = $entry;
|
||||
if (empty($easy->options['delay'])) {
|
||||
curl_multi_add_handle($this->_mh, $easy->handle);
|
||||
} else {
|
||||
$this->delays[$id] = microtime(true) + ($easy->options['delay'] / 1000);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Cancels a handle from sending and removes references to it.
|
||||
*
|
||||
* @param int $id Handle ID to cancel and remove.
|
||||
*
|
||||
* @return bool True on success, false on failure.
|
||||
*/
|
||||
private function cancel($id)
|
||||
{
|
||||
// Cannot cancel if it has been processed.
|
||||
if (!isset($this->handles[$id])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$handle = $this->handles[$id]['easy']->handle;
|
||||
unset($this->delays[$id], $this->handles[$id]);
|
||||
curl_multi_remove_handle($this->_mh, $handle);
|
||||
curl_close($handle);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function processMessages()
|
||||
{
|
||||
while ($done = curl_multi_info_read($this->_mh)) {
|
||||
$id = (int) $done['handle'];
|
||||
curl_multi_remove_handle($this->_mh, $done['handle']);
|
||||
|
||||
if (!isset($this->handles[$id])) {
|
||||
// Probably was cancelled.
|
||||
continue;
|
||||
}
|
||||
|
||||
$entry = $this->handles[$id];
|
||||
unset($this->handles[$id], $this->delays[$id]);
|
||||
$entry['easy']->errno = $done['result'];
|
||||
$entry['deferred']->resolve(
|
||||
CurlFactory::finish(
|
||||
$this,
|
||||
$entry['easy'],
|
||||
$this->factory
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private function timeToNext()
|
||||
{
|
||||
$currentTime = microtime(true);
|
||||
$nextTime = PHP_INT_MAX;
|
||||
foreach ($this->delays as $time) {
|
||||
if ($time < $nextTime) {
|
||||
$nextTime = $time;
|
||||
}
|
||||
}
|
||||
|
||||
return max(0, $currentTime - $nextTime);
|
||||
}
|
||||
}
|
87
server/vendor/guzzlehttp/guzzle/src/Handler/EasyHandle.php
vendored
Normal file
87
server/vendor/guzzlehttp/guzzle/src/Handler/EasyHandle.php
vendored
Normal file
|
@ -0,0 +1,87 @@
|
|||
<?php
|
||||
namespace GuzzleHttp\Handler;
|
||||
|
||||
use GuzzleHttp\Psr7\Response;
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
|
||||
/**
|
||||
* Represents a cURL easy handle and the data it populates.
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
final class EasyHandle
|
||||
{
|
||||
/** @var resource cURL resource */
|
||||
public $handle;
|
||||
|
||||
/** @var StreamInterface Where data is being written */
|
||||
public $sink;
|
||||
|
||||
/** @var array Received HTTP headers so far */
|
||||
public $headers = [];
|
||||
|
||||
/** @var ResponseInterface Received response (if any) */
|
||||
public $response;
|
||||
|
||||
/** @var RequestInterface Request being sent */
|
||||
public $request;
|
||||
|
||||
/** @var array Request options */
|
||||
public $options = [];
|
||||
|
||||
/** @var int cURL error number (if any) */
|
||||
public $errno = 0;
|
||||
|
||||
/** @var \Exception Exception during on_headers (if any) */
|
||||
public $onHeadersException;
|
||||
|
||||
/**
|
||||
* Attach a response to the easy handle based on the received headers.
|
||||
*
|
||||
* @throws \RuntimeException if no headers have been received.
|
||||
*/
|
||||
public function createResponse()
|
||||
{
|
||||
if (empty($this->headers)) {
|
||||
throw new \RuntimeException('No headers have been received');
|
||||
}
|
||||
|
||||
// HTTP-version SP status-code SP reason-phrase
|
||||
$startLine = explode(' ', array_shift($this->headers), 3);
|
||||
$headers = \GuzzleHttp\headers_from_lines($this->headers);
|
||||
$normalizedKeys = \GuzzleHttp\normalize_header_keys($headers);
|
||||
|
||||
if (!empty($this->options['decode_content'])
|
||||
&& isset($normalizedKeys['content-encoding'])
|
||||
) {
|
||||
unset($headers[$normalizedKeys['content-encoding']]);
|
||||
if (isset($normalizedKeys['content-length'])) {
|
||||
$bodyLength = (int) $this->sink->getSize();
|
||||
if ($bodyLength) {
|
||||
$headers[$normalizedKeys['content-length']] = $bodyLength;
|
||||
} else {
|
||||
unset($headers[$normalizedKeys['content-length']]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Attach a response to the easy handle with the parsed headers.
|
||||
$this->response = new Response(
|
||||
$startLine[1],
|
||||
$headers,
|
||||
$this->sink,
|
||||
substr($startLine[0], 5),
|
||||
isset($startLine[2]) ? (string) $startLine[2] : null
|
||||
);
|
||||
}
|
||||
|
||||
public function __get($name)
|
||||
{
|
||||
$msg = $name === 'handle'
|
||||
? 'The EasyHandle has been released'
|
||||
: 'Invalid property: ' . $name;
|
||||
throw new \BadMethodCallException($msg);
|
||||
}
|
||||
}
|
176
server/vendor/guzzlehttp/guzzle/src/Handler/MockHandler.php
vendored
Normal file
176
server/vendor/guzzlehttp/guzzle/src/Handler/MockHandler.php
vendored
Normal file
|
@ -0,0 +1,176 @@
|
|||
<?php
|
||||
namespace GuzzleHttp\Handler;
|
||||
|
||||
use GuzzleHttp\HandlerStack;
|
||||
use GuzzleHttp\Promise\PromiseInterface;
|
||||
use GuzzleHttp\Promise\RejectedPromise;
|
||||
use GuzzleHttp\TransferStats;
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
/**
|
||||
* Handler that returns responses or throw exceptions from a queue.
|
||||
*/
|
||||
class MockHandler implements \Countable
|
||||
{
|
||||
private $queue;
|
||||
private $lastRequest;
|
||||
private $lastOptions;
|
||||
private $onFulfilled;
|
||||
private $onRejected;
|
||||
|
||||
/**
|
||||
* Creates a new MockHandler that uses the default handler stack list of
|
||||
* middlewares.
|
||||
*
|
||||
* @param array $queue Array of responses, callables, or exceptions.
|
||||
* @param callable $onFulfilled Callback to invoke when the return value is fulfilled.
|
||||
* @param callable $onRejected Callback to invoke when the return value is rejected.
|
||||
*
|
||||
* @return MockHandler
|
||||
*/
|
||||
public static function createWithMiddleware(
|
||||
array $queue = null,
|
||||
callable $onFulfilled = null,
|
||||
callable $onRejected = null
|
||||
) {
|
||||
return HandlerStack::create(new self($queue, $onFulfilled, $onRejected));
|
||||
}
|
||||
|
||||
/**
|
||||
* The passed in value must be an array of
|
||||
* {@see Psr7\Http\Message\ResponseInterface} objects, Exceptions,
|
||||
* callables, or Promises.
|
||||
*
|
||||
* @param array $queue
|
||||
* @param callable $onFulfilled Callback to invoke when the return value is fulfilled.
|
||||
* @param callable $onRejected Callback to invoke when the return value is rejected.
|
||||
*/
|
||||
public function __construct(
|
||||
array $queue = null,
|
||||
callable $onFulfilled = null,
|
||||
callable $onRejected = null
|
||||
) {
|
||||
$this->onFulfilled = $onFulfilled;
|
||||
$this->onRejected = $onRejected;
|
||||
|
||||
if ($queue) {
|
||||
call_user_func_array([$this, 'append'], $queue);
|
||||
}
|
||||
}
|
||||
|
||||
public function __invoke(RequestInterface $request, array $options)
|
||||
{
|
||||
if (!$this->queue) {
|
||||
throw new \OutOfBoundsException('Mock queue is empty');
|
||||
}
|
||||
|
||||
if (isset($options['delay'])) {
|
||||
usleep($options['delay'] * 1000);
|
||||
}
|
||||
|
||||
$this->lastRequest = $request;
|
||||
$this->lastOptions = $options;
|
||||
$response = array_shift($this->queue);
|
||||
|
||||
if (is_callable($response)) {
|
||||
$response = $response($request, $options);
|
||||
}
|
||||
|
||||
$response = $response instanceof \Exception
|
||||
? new RejectedPromise($response)
|
||||
: \GuzzleHttp\Promise\promise_for($response);
|
||||
|
||||
return $response->then(
|
||||
function ($value) use ($request, $options) {
|
||||
$this->invokeStats($request, $options, $value);
|
||||
if ($this->onFulfilled) {
|
||||
call_user_func($this->onFulfilled, $value);
|
||||
}
|
||||
if (isset($options['sink'])) {
|
||||
$contents = (string) $value->getBody();
|
||||
$sink = $options['sink'];
|
||||
|
||||
if (is_resource($sink)) {
|
||||
fwrite($sink, $contents);
|
||||
} elseif (is_string($sink)) {
|
||||
file_put_contents($sink, $contents);
|
||||
} elseif ($sink instanceof \Psr\Http\Message\StreamInterface) {
|
||||
$sink->write($contents);
|
||||
}
|
||||
}
|
||||
|
||||
return $value;
|
||||
},
|
||||
function ($reason) use ($request, $options) {
|
||||
$this->invokeStats($request, $options, null, $reason);
|
||||
if ($this->onRejected) {
|
||||
call_user_func($this->onRejected, $reason);
|
||||
}
|
||||
return new RejectedPromise($reason);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds one or more variadic requests, exceptions, callables, or promises
|
||||
* to the queue.
|
||||
*/
|
||||
public function append()
|
||||
{
|
||||
foreach (func_get_args() as $value) {
|
||||
if ($value instanceof ResponseInterface
|
||||
|| $value instanceof \Exception
|
||||
|| $value instanceof PromiseInterface
|
||||
|| is_callable($value)
|
||||
) {
|
||||
$this->queue[] = $value;
|
||||
} else {
|
||||
throw new \InvalidArgumentException('Expected a response or '
|
||||
. 'exception. Found ' . \GuzzleHttp\describe_type($value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the last received request.
|
||||
*
|
||||
* @return RequestInterface
|
||||
*/
|
||||
public function getLastRequest()
|
||||
{
|
||||
return $this->lastRequest;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the last received request options.
|
||||
*
|
||||
* @return RequestInterface
|
||||
*/
|
||||
public function getLastOptions()
|
||||
{
|
||||
return $this->lastOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of remaining items in the queue.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function count()
|
||||
{
|
||||
return count($this->queue);
|
||||
}
|
||||
|
||||
private function invokeStats(
|
||||
RequestInterface $request,
|
||||
array $options,
|
||||
ResponseInterface $response = null,
|
||||
$reason = null
|
||||
) {
|
||||
if (isset($options['on_stats'])) {
|
||||
$stats = new TransferStats($request, $response, 0, $reason);
|
||||
call_user_func($options['on_stats'], $stats);
|
||||
}
|
||||
}
|
||||
}
|
55
server/vendor/guzzlehttp/guzzle/src/Handler/Proxy.php
vendored
Normal file
55
server/vendor/guzzlehttp/guzzle/src/Handler/Proxy.php
vendored
Normal file
|
@ -0,0 +1,55 @@
|
|||
<?php
|
||||
namespace GuzzleHttp\Handler;
|
||||
|
||||
use GuzzleHttp\RequestOptions;
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
|
||||
/**
|
||||
* Provides basic proxies for handlers.
|
||||
*/
|
||||
class Proxy
|
||||
{
|
||||
/**
|
||||
* Sends synchronous requests to a specific handler while sending all other
|
||||
* requests to another handler.
|
||||
*
|
||||
* @param callable $default Handler used for normal responses
|
||||
* @param callable $sync Handler used for synchronous responses.
|
||||
*
|
||||
* @return callable Returns the composed handler.
|
||||
*/
|
||||
public static function wrapSync(
|
||||
callable $default,
|
||||
callable $sync
|
||||
) {
|
||||
return function (RequestInterface $request, array $options) use ($default, $sync) {
|
||||
return empty($options[RequestOptions::SYNCHRONOUS])
|
||||
? $default($request, $options)
|
||||
: $sync($request, $options);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends streaming requests to a streaming compatible handler while sending
|
||||
* all other requests to a default handler.
|
||||
*
|
||||
* This, for example, could be useful for taking advantage of the
|
||||
* performance benefits of curl while still supporting true streaming
|
||||
* through the StreamHandler.
|
||||
*
|
||||
* @param callable $default Handler used for non-streaming responses
|
||||
* @param callable $streaming Handler used for streaming responses
|
||||
*
|
||||
* @return callable Returns the composed handler.
|
||||
*/
|
||||
public static function wrapStreaming(
|
||||
callable $default,
|
||||
callable $streaming
|
||||
) {
|
||||
return function (RequestInterface $request, array $options) use ($default, $streaming) {
|
||||
return empty($options['stream'])
|
||||
? $default($request, $options)
|
||||
: $streaming($request, $options);
|
||||
};
|
||||
}
|
||||
}
|
458
server/vendor/guzzlehttp/guzzle/src/Handler/StreamHandler.php
vendored
Normal file
458
server/vendor/guzzlehttp/guzzle/src/Handler/StreamHandler.php
vendored
Normal file
|
@ -0,0 +1,458 @@
|
|||
<?php
|
||||
namespace GuzzleHttp\Handler;
|
||||
|
||||
use GuzzleHttp\Exception\RequestException;
|
||||
use GuzzleHttp\Exception\ConnectException;
|
||||
use GuzzleHttp\Promise\FulfilledPromise;
|
||||
use GuzzleHttp\Promise\RejectedPromise;
|
||||
use GuzzleHttp\Promise\PromiseInterface;
|
||||
use GuzzleHttp\Psr7;
|
||||
use GuzzleHttp\TransferStats;
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
|
||||
/**
|
||||
* HTTP handler that uses PHP's HTTP stream wrapper.
|
||||
*/
|
||||
class StreamHandler
|
||||
{
|
||||
private $lastHeaders = [];
|
||||
|
||||
/**
|
||||
* Sends an HTTP request.
|
||||
*
|
||||
* @param RequestInterface $request Request to send.
|
||||
* @param array $options Request transfer options.
|
||||
*
|
||||
* @return PromiseInterface
|
||||
*/
|
||||
public function __invoke(RequestInterface $request, array $options)
|
||||
{
|
||||
// Sleep if there is a delay specified.
|
||||
if (isset($options['delay'])) {
|
||||
usleep($options['delay'] * 1000);
|
||||
}
|
||||
|
||||
$startTime = isset($options['on_stats']) ? microtime(true) : null;
|
||||
|
||||
try {
|
||||
// Does not support the expect header.
|
||||
$request = $request->withoutHeader('Expect');
|
||||
|
||||
// Append a content-length header if body size is zero to match
|
||||
// cURL's behavior.
|
||||
if (0 === $request->getBody()->getSize()) {
|
||||
$request = $request->withHeader('Content-Length', 0);
|
||||
}
|
||||
|
||||
return $this->createResponse(
|
||||
$request,
|
||||
$options,
|
||||
$this->createStream($request, $options),
|
||||
$startTime
|
||||
);
|
||||
} catch (\InvalidArgumentException $e) {
|
||||
throw $e;
|
||||
} catch (\Exception $e) {
|
||||
// Determine if the error was a networking error.
|
||||
$message = $e->getMessage();
|
||||
// This list can probably get more comprehensive.
|
||||
if (strpos($message, 'getaddrinfo') // DNS lookup failed
|
||||
|| strpos($message, 'Connection refused')
|
||||
|| strpos($message, "couldn't connect to host") // error on HHVM
|
||||
) {
|
||||
$e = new ConnectException($e->getMessage(), $request, $e);
|
||||
}
|
||||
$e = RequestException::wrapException($request, $e);
|
||||
$this->invokeStats($options, $request, $startTime, null, $e);
|
||||
|
||||
return new RejectedPromise($e);
|
||||
}
|
||||
}
|
||||
|
||||
private function invokeStats(
|
||||
array $options,
|
||||
RequestInterface $request,
|
||||
$startTime,
|
||||
ResponseInterface $response = null,
|
||||
$error = null
|
||||
) {
|
||||
if (isset($options['on_stats'])) {
|
||||
$stats = new TransferStats(
|
||||
$request,
|
||||
$response,
|
||||
microtime(true) - $startTime,
|
||||
$error,
|
||||
[]
|
||||
);
|
||||
call_user_func($options['on_stats'], $stats);
|
||||
}
|
||||
}
|
||||
|
||||
private function createResponse(
|
||||
RequestInterface $request,
|
||||
array $options,
|
||||
$stream,
|
||||
$startTime
|
||||
) {
|
||||
$hdrs = $this->lastHeaders;
|
||||
$this->lastHeaders = [];
|
||||
$parts = explode(' ', array_shift($hdrs), 3);
|
||||
$ver = explode('/', $parts[0])[1];
|
||||
$status = $parts[1];
|
||||
$reason = isset($parts[2]) ? $parts[2] : null;
|
||||
$headers = \GuzzleHttp\headers_from_lines($hdrs);
|
||||
list ($stream, $headers) = $this->checkDecode($options, $headers, $stream);
|
||||
$stream = Psr7\stream_for($stream);
|
||||
$sink = $this->createSink($stream, $options);
|
||||
$response = new Psr7\Response($status, $headers, $sink, $ver, $reason);
|
||||
|
||||
if (isset($options['on_headers'])) {
|
||||
try {
|
||||
$options['on_headers']($response);
|
||||
} catch (\Exception $e) {
|
||||
$msg = 'An error was encountered during the on_headers event';
|
||||
$ex = new RequestException($msg, $request, $response, $e);
|
||||
return new RejectedPromise($ex);
|
||||
}
|
||||
}
|
||||
|
||||
if ($sink !== $stream) {
|
||||
$this->drain($stream, $sink);
|
||||
}
|
||||
|
||||
$this->invokeStats($options, $request, $startTime, $response, null);
|
||||
|
||||
return new FulfilledPromise($response);
|
||||
}
|
||||
|
||||
private function createSink(StreamInterface $stream, array $options)
|
||||
{
|
||||
if (!empty($options['stream'])) {
|
||||
return $stream;
|
||||
}
|
||||
|
||||
$sink = isset($options['sink'])
|
||||
? $options['sink']
|
||||
: fopen('php://temp', 'r+');
|
||||
|
||||
return is_string($sink)
|
||||
? new Psr7\Stream(Psr7\try_fopen($sink, 'r+'))
|
||||
: Psr7\stream_for($sink);
|
||||
}
|
||||
|
||||
private function checkDecode(array $options, array $headers, $stream)
|
||||
{
|
||||
// Automatically decode responses when instructed.
|
||||
if (!empty($options['decode_content'])) {
|
||||
$normalizedKeys = \GuzzleHttp\normalize_header_keys($headers);
|
||||
if (isset($normalizedKeys['content-encoding'])) {
|
||||
$encoding = $headers[$normalizedKeys['content-encoding']];
|
||||
if ($encoding[0] == 'gzip' || $encoding[0] == 'deflate') {
|
||||
$stream = new Psr7\InflateStream(
|
||||
Psr7\stream_for($stream)
|
||||
);
|
||||
// Remove content-encoding header
|
||||
unset($headers[$normalizedKeys['content-encoding']]);
|
||||
// Fix content-length header
|
||||
if (isset($normalizedKeys['content-length'])) {
|
||||
$length = (int) $stream->getSize();
|
||||
if ($length == 0) {
|
||||
unset($headers[$normalizedKeys['content-length']]);
|
||||
} else {
|
||||
$headers[$normalizedKeys['content-length']] = [$length];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return [$stream, $headers];
|
||||
}
|
||||
|
||||
/**
|
||||
* Drains the source stream into the "sink" client option.
|
||||
*
|
||||
* @param StreamInterface $source
|
||||
* @param StreamInterface $sink
|
||||
*
|
||||
* @return StreamInterface
|
||||
* @throws \RuntimeException when the sink option is invalid.
|
||||
*/
|
||||
private function drain(StreamInterface $source, StreamInterface $sink)
|
||||
{
|
||||
Psr7\copy_to_stream($source, $sink);
|
||||
$sink->seek(0);
|
||||
$source->close();
|
||||
|
||||
return $sink;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a resource and check to ensure it was created successfully
|
||||
*
|
||||
* @param callable $callback Callable that returns stream resource
|
||||
*
|
||||
* @return resource
|
||||
* @throws \RuntimeException on error
|
||||
*/
|
||||
private function createResource(callable $callback)
|
||||
{
|
||||
$errors = null;
|
||||
set_error_handler(function ($_, $msg, $file, $line) use (&$errors) {
|
||||
$errors[] = [
|
||||
'message' => $msg,
|
||||
'file' => $file,
|
||||
'line' => $line
|
||||
];
|
||||
return true;
|
||||
});
|
||||
|
||||
$resource = $callback();
|
||||
restore_error_handler();
|
||||
|
||||
if (!$resource) {
|
||||
$message = 'Error creating resource: ';
|
||||
foreach ($errors as $err) {
|
||||
foreach ($err as $key => $value) {
|
||||
$message .= "[$key] $value" . PHP_EOL;
|
||||
}
|
||||
}
|
||||
throw new \RuntimeException(trim($message));
|
||||
}
|
||||
|
||||
return $resource;
|
||||
}
|
||||
|
||||
private function createStream(RequestInterface $request, array $options)
|
||||
{
|
||||
static $methods;
|
||||
if (!$methods) {
|
||||
$methods = array_flip(get_class_methods(__CLASS__));
|
||||
}
|
||||
|
||||
// HTTP/1.1 streams using the PHP stream wrapper require a
|
||||
// Connection: close header
|
||||
if ($request->getProtocolVersion() == '1.1'
|
||||
&& !$request->hasHeader('Connection')
|
||||
) {
|
||||
$request = $request->withHeader('Connection', 'close');
|
||||
}
|
||||
|
||||
// Ensure SSL is verified by default
|
||||
if (!isset($options['verify'])) {
|
||||
$options['verify'] = true;
|
||||
}
|
||||
|
||||
$params = [];
|
||||
$context = $this->getDefaultContext($request, $options);
|
||||
|
||||
if (isset($options['on_headers']) && !is_callable($options['on_headers'])) {
|
||||
throw new \InvalidArgumentException('on_headers must be callable');
|
||||
}
|
||||
|
||||
if (!empty($options)) {
|
||||
foreach ($options as $key => $value) {
|
||||
$method = "add_{$key}";
|
||||
if (isset($methods[$method])) {
|
||||
$this->{$method}($request, $context, $value, $params);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($options['stream_context'])) {
|
||||
if (!is_array($options['stream_context'])) {
|
||||
throw new \InvalidArgumentException('stream_context must be an array');
|
||||
}
|
||||
$context = array_replace_recursive(
|
||||
$context,
|
||||
$options['stream_context']
|
||||
);
|
||||
}
|
||||
|
||||
$context = $this->createResource(
|
||||
function () use ($context, $params) {
|
||||
return stream_context_create($context, $params);
|
||||
}
|
||||
);
|
||||
|
||||
return $this->createResource(
|
||||
function () use ($request, &$http_response_header, $context) {
|
||||
$resource = fopen($request->getUri(), 'r', null, $context);
|
||||
$this->lastHeaders = $http_response_header;
|
||||
return $resource;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private function getDefaultContext(RequestInterface $request)
|
||||
{
|
||||
$headers = '';
|
||||
foreach ($request->getHeaders() as $name => $value) {
|
||||
foreach ($value as $val) {
|
||||
$headers .= "$name: $val\r\n";
|
||||
}
|
||||
}
|
||||
|
||||
$context = [
|
||||
'http' => [
|
||||
'method' => $request->getMethod(),
|
||||
'header' => $headers,
|
||||
'protocol_version' => $request->getProtocolVersion(),
|
||||
'ignore_errors' => true,
|
||||
'follow_location' => 0,
|
||||
],
|
||||
];
|
||||
|
||||
$body = (string) $request->getBody();
|
||||
|
||||
if (!empty($body)) {
|
||||
$context['http']['content'] = $body;
|
||||
// Prevent the HTTP handler from adding a Content-Type header.
|
||||
if (!$request->hasHeader('Content-Type')) {
|
||||
$context['http']['header'] .= "Content-Type:\r\n";
|
||||
}
|
||||
}
|
||||
|
||||
$context['http']['header'] = rtrim($context['http']['header']);
|
||||
|
||||
return $context;
|
||||
}
|
||||
|
||||
private function add_proxy(RequestInterface $request, &$options, $value, &$params)
|
||||
{
|
||||
if (!is_array($value)) {
|
||||
$options['http']['proxy'] = $value;
|
||||
} else {
|
||||
$scheme = $request->getUri()->getScheme();
|
||||
if (isset($value[$scheme])) {
|
||||
if (!isset($value['no'])
|
||||
|| !\GuzzleHttp\is_host_in_noproxy(
|
||||
$request->getUri()->getHost(),
|
||||
$value['no']
|
||||
)
|
||||
) {
|
||||
$options['http']['proxy'] = $value[$scheme];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function add_timeout(RequestInterface $request, &$options, $value, &$params)
|
||||
{
|
||||
$options['http']['timeout'] = $value;
|
||||
}
|
||||
|
||||
private function add_verify(RequestInterface $request, &$options, $value, &$params)
|
||||
{
|
||||
if ($value === true) {
|
||||
// PHP 5.6 or greater will find the system cert by default. When
|
||||
// < 5.6, use the Guzzle bundled cacert.
|
||||
if (PHP_VERSION_ID < 50600) {
|
||||
$options['ssl']['cafile'] = \GuzzleHttp\default_ca_bundle();
|
||||
}
|
||||
} elseif (is_string($value)) {
|
||||
$options['ssl']['cafile'] = $value;
|
||||
if (!file_exists($value)) {
|
||||
throw new \RuntimeException("SSL CA bundle not found: $value");
|
||||
}
|
||||
} elseif ($value === false) {
|
||||
$options['ssl']['verify_peer'] = false;
|
||||
$options['ssl']['verify_peer_name'] = false;
|
||||
return;
|
||||
} else {
|
||||
throw new \InvalidArgumentException('Invalid verify request option');
|
||||
}
|
||||
|
||||
$options['ssl']['verify_peer'] = true;
|
||||
$options['ssl']['verify_peer_name'] = true;
|
||||
$options['ssl']['allow_self_signed'] = false;
|
||||
}
|
||||
|
||||
private function add_cert(RequestInterface $request, &$options, $value, &$params)
|
||||
{
|
||||
if (is_array($value)) {
|
||||
$options['ssl']['passphrase'] = $value[1];
|
||||
$value = $value[0];
|
||||
}
|
||||
|
||||
if (!file_exists($value)) {
|
||||
throw new \RuntimeException("SSL certificate not found: {$value}");
|
||||
}
|
||||
|
||||
$options['ssl']['local_cert'] = $value;
|
||||
}
|
||||
|
||||
private function add_progress(RequestInterface $request, &$options, $value, &$params)
|
||||
{
|
||||
$this->addNotification(
|
||||
$params,
|
||||
function ($code, $a, $b, $c, $transferred, $total) use ($value) {
|
||||
if ($code == STREAM_NOTIFY_PROGRESS) {
|
||||
$value($total, $transferred, null, null);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private function add_debug(RequestInterface $request, &$options, $value, &$params)
|
||||
{
|
||||
if ($value === false) {
|
||||
return;
|
||||
}
|
||||
|
||||
static $map = [
|
||||
STREAM_NOTIFY_CONNECT => 'CONNECT',
|
||||
STREAM_NOTIFY_AUTH_REQUIRED => 'AUTH_REQUIRED',
|
||||
STREAM_NOTIFY_AUTH_RESULT => 'AUTH_RESULT',
|
||||
STREAM_NOTIFY_MIME_TYPE_IS => 'MIME_TYPE_IS',
|
||||
STREAM_NOTIFY_FILE_SIZE_IS => 'FILE_SIZE_IS',
|
||||
STREAM_NOTIFY_REDIRECTED => 'REDIRECTED',
|
||||
STREAM_NOTIFY_PROGRESS => 'PROGRESS',
|
||||
STREAM_NOTIFY_FAILURE => 'FAILURE',
|
||||
STREAM_NOTIFY_COMPLETED => 'COMPLETED',
|
||||
STREAM_NOTIFY_RESOLVE => 'RESOLVE',
|
||||
];
|
||||
static $args = ['severity', 'message', 'message_code',
|
||||
'bytes_transferred', 'bytes_max'];
|
||||
|
||||
$value = \GuzzleHttp\debug_resource($value);
|
||||
$ident = $request->getMethod() . ' ' . $request->getUri();
|
||||
$this->addNotification(
|
||||
$params,
|
||||
function () use ($ident, $value, $map, $args) {
|
||||
$passed = func_get_args();
|
||||
$code = array_shift($passed);
|
||||
fprintf($value, '<%s> [%s] ', $ident, $map[$code]);
|
||||
foreach (array_filter($passed) as $i => $v) {
|
||||
fwrite($value, $args[$i] . ': "' . $v . '" ');
|
||||
}
|
||||
fwrite($value, "\n");
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private function addNotification(array &$params, callable $notify)
|
||||
{
|
||||
// Wrap the existing function if needed.
|
||||
if (!isset($params['notification'])) {
|
||||
$params['notification'] = $notify;
|
||||
} else {
|
||||
$params['notification'] = $this->callArray([
|
||||
$params['notification'],
|
||||
$notify
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
private function callArray(array $functions)
|
||||
{
|
||||
return function () use ($functions) {
|
||||
$args = func_get_args();
|
||||
foreach ($functions as $fn) {
|
||||
call_user_func_array($fn, $args);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
273
server/vendor/guzzlehttp/guzzle/src/HandlerStack.php
vendored
Normal file
273
server/vendor/guzzlehttp/guzzle/src/HandlerStack.php
vendored
Normal file
|
@ -0,0 +1,273 @@
|
|||
<?php
|
||||
namespace GuzzleHttp;
|
||||
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
|
||||
/**
|
||||
* Creates a composed Guzzle handler function by stacking middlewares on top of
|
||||
* an HTTP handler function.
|
||||
*/
|
||||
class HandlerStack
|
||||
{
|
||||
/** @var callable */
|
||||
private $handler;
|
||||
|
||||
/** @var array */
|
||||
private $stack = [];
|
||||
|
||||
/** @var callable|null */
|
||||
private $cached;
|
||||
|
||||
/**
|
||||
* Creates a default handler stack that can be used by clients.
|
||||
*
|
||||
* The returned handler will wrap the provided handler or use the most
|
||||
* appropriate default handler for you system. The returned HandlerStack has
|
||||
* support for cookies, redirects, HTTP error exceptions, and preparing a body
|
||||
* before sending.
|
||||
*
|
||||
* The returned handler stack can be passed to a client in the "handler"
|
||||
* option.
|
||||
*
|
||||
* @param callable $handler HTTP handler function to use with the stack. If no
|
||||
* handler is provided, the best handler for your
|
||||
* system will be utilized.
|
||||
*
|
||||
* @return HandlerStack
|
||||
*/
|
||||
public static function create(callable $handler = null)
|
||||
{
|
||||
$stack = new self($handler ?: choose_handler());
|
||||
$stack->push(Middleware::httpErrors(), 'http_errors');
|
||||
$stack->push(Middleware::redirect(), 'allow_redirects');
|
||||
$stack->push(Middleware::cookies(), 'cookies');
|
||||
$stack->push(Middleware::prepareBody(), 'prepare_body');
|
||||
|
||||
return $stack;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param callable $handler Underlying HTTP handler.
|
||||
*/
|
||||
public function __construct(callable $handler = null)
|
||||
{
|
||||
$this->handler = $handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Invokes the handler stack as a composed handler
|
||||
*
|
||||
* @param RequestInterface $request
|
||||
* @param array $options
|
||||
*/
|
||||
public function __invoke(RequestInterface $request, array $options)
|
||||
{
|
||||
$handler = $this->resolve();
|
||||
|
||||
return $handler($request, $options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dumps a string representation of the stack.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function __toString()
|
||||
{
|
||||
$depth = 0;
|
||||
$stack = [];
|
||||
if ($this->handler) {
|
||||
$stack[] = "0) Handler: " . $this->debugCallable($this->handler);
|
||||
}
|
||||
|
||||
$result = '';
|
||||
foreach (array_reverse($this->stack) as $tuple) {
|
||||
$depth++;
|
||||
$str = "{$depth}) Name: '{$tuple[1]}', ";
|
||||
$str .= "Function: " . $this->debugCallable($tuple[0]);
|
||||
$result = "> {$str}\n{$result}";
|
||||
$stack[] = $str;
|
||||
}
|
||||
|
||||
foreach (array_keys($stack) as $k) {
|
||||
$result .= "< {$stack[$k]}\n";
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the HTTP handler that actually returns a promise.
|
||||
*
|
||||
* @param callable $handler Accepts a request and array of options and
|
||||
* returns a Promise.
|
||||
*/
|
||||
public function setHandler(callable $handler)
|
||||
{
|
||||
$this->handler = $handler;
|
||||
$this->cached = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the builder has a handler.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasHandler()
|
||||
{
|
||||
return (bool) $this->handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Unshift a middleware to the bottom of the stack.
|
||||
*
|
||||
* @param callable $middleware Middleware function
|
||||
* @param string $name Name to register for this middleware.
|
||||
*/
|
||||
public function unshift(callable $middleware, $name = null)
|
||||
{
|
||||
array_unshift($this->stack, [$middleware, $name]);
|
||||
$this->cached = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Push a middleware to the top of the stack.
|
||||
*
|
||||
* @param callable $middleware Middleware function
|
||||
* @param string $name Name to register for this middleware.
|
||||
*/
|
||||
public function push(callable $middleware, $name = '')
|
||||
{
|
||||
$this->stack[] = [$middleware, $name];
|
||||
$this->cached = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a middleware before another middleware by name.
|
||||
*
|
||||
* @param string $findName Middleware to find
|
||||
* @param callable $middleware Middleware function
|
||||
* @param string $withName Name to register for this middleware.
|
||||
*/
|
||||
public function before($findName, callable $middleware, $withName = '')
|
||||
{
|
||||
$this->splice($findName, $withName, $middleware, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a middleware after another middleware by name.
|
||||
*
|
||||
* @param string $findName Middleware to find
|
||||
* @param callable $middleware Middleware function
|
||||
* @param string $withName Name to register for this middleware.
|
||||
*/
|
||||
public function after($findName, callable $middleware, $withName = '')
|
||||
{
|
||||
$this->splice($findName, $withName, $middleware, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a middleware by instance or name from the stack.
|
||||
*
|
||||
* @param callable|string $remove Middleware to remove by instance or name.
|
||||
*/
|
||||
public function remove($remove)
|
||||
{
|
||||
$this->cached = null;
|
||||
$idx = is_callable($remove) ? 0 : 1;
|
||||
$this->stack = array_values(array_filter(
|
||||
$this->stack,
|
||||
function ($tuple) use ($idx, $remove) {
|
||||
return $tuple[$idx] !== $remove;
|
||||
}
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Compose the middleware and handler into a single callable function.
|
||||
*
|
||||
* @return callable
|
||||
*/
|
||||
public function resolve()
|
||||
{
|
||||
if (!$this->cached) {
|
||||
if (!($prev = $this->handler)) {
|
||||
throw new \LogicException('No handler has been specified');
|
||||
}
|
||||
|
||||
foreach (array_reverse($this->stack) as $fn) {
|
||||
$prev = $fn[0]($prev);
|
||||
}
|
||||
|
||||
$this->cached = $prev;
|
||||
}
|
||||
|
||||
return $this->cached;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param $name
|
||||
* @return int
|
||||
*/
|
||||
private function findByName($name)
|
||||
{
|
||||
foreach ($this->stack as $k => $v) {
|
||||
if ($v[1] === $name) {
|
||||
return $k;
|
||||
}
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException("Middleware not found: $name");
|
||||
}
|
||||
|
||||
/**
|
||||
* Splices a function into the middleware list at a specific position.
|
||||
*
|
||||
* @param $findName
|
||||
* @param $withName
|
||||
* @param callable $middleware
|
||||
* @param $before
|
||||
*/
|
||||
private function splice($findName, $withName, callable $middleware, $before)
|
||||
{
|
||||
$this->cached = null;
|
||||
$idx = $this->findByName($findName);
|
||||
$tuple = [$middleware, $withName];
|
||||
|
||||
if ($before) {
|
||||
if ($idx === 0) {
|
||||
array_unshift($this->stack, $tuple);
|
||||
} else {
|
||||
$replacement = [$tuple, $this->stack[$idx]];
|
||||
array_splice($this->stack, $idx, 1, $replacement);
|
||||
}
|
||||
} elseif ($idx === count($this->stack) - 1) {
|
||||
$this->stack[] = $tuple;
|
||||
} else {
|
||||
$replacement = [$this->stack[$idx], $tuple];
|
||||
array_splice($this->stack, $idx, 1, $replacement);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides a debug string for a given callable.
|
||||
*
|
||||
* @param array|callable $fn Function to write as a string.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function debugCallable($fn)
|
||||
{
|
||||
if (is_string($fn)) {
|
||||
return "callable({$fn})";
|
||||
}
|
||||
|
||||
if (is_array($fn)) {
|
||||
return is_string($fn[0])
|
||||
? "callable({$fn[0]}::{$fn[1]})"
|
||||
: "callable(['" . get_class($fn[0]) . "', '{$fn[1]}'])";
|
||||
}
|
||||
|
||||
return 'callable(' . spl_object_hash($fn) . ')';
|
||||
}
|
||||
}
|
182
server/vendor/guzzlehttp/guzzle/src/MessageFormatter.php
vendored
Normal file
182
server/vendor/guzzlehttp/guzzle/src/MessageFormatter.php
vendored
Normal file
|
@ -0,0 +1,182 @@
|
|||
<?php
|
||||
namespace GuzzleHttp;
|
||||
|
||||
use Psr\Http\Message\MessageInterface;
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
/**
|
||||
* Formats log messages using variable substitutions for requests, responses,
|
||||
* and other transactional data.
|
||||
*
|
||||
* The following variable substitutions are supported:
|
||||
*
|
||||
* - {request}: Full HTTP request message
|
||||
* - {response}: Full HTTP response message
|
||||
* - {ts}: ISO 8601 date in GMT
|
||||
* - {date_iso_8601} ISO 8601 date in GMT
|
||||
* - {date_common_log} Apache common log date using the configured timezone.
|
||||
* - {host}: Host of the request
|
||||
* - {method}: Method of the request
|
||||
* - {uri}: URI of the request
|
||||
* - {host}: Host of the request
|
||||
* - {version}: Protocol version
|
||||
* - {target}: Request target of the request (path + query + fragment)
|
||||
* - {hostname}: Hostname of the machine that sent the request
|
||||
* - {code}: Status code of the response (if available)
|
||||
* - {phrase}: Reason phrase of the response (if available)
|
||||
* - {error}: Any error messages (if available)
|
||||
* - {req_header_*}: Replace `*` with the lowercased name of a request header to add to the message
|
||||
* - {res_header_*}: Replace `*` with the lowercased name of a response header to add to the message
|
||||
* - {req_headers}: Request headers
|
||||
* - {res_headers}: Response headers
|
||||
* - {req_body}: Request body
|
||||
* - {res_body}: Response body
|
||||
*/
|
||||
class MessageFormatter
|
||||
{
|
||||
/**
|
||||
* Apache Common Log Format.
|
||||
* @link http://httpd.apache.org/docs/2.4/logs.html#common
|
||||
* @var string
|
||||
*/
|
||||
const CLF = "{hostname} {req_header_User-Agent} - [{date_common_log}] \"{method} {target} HTTP/{version}\" {code} {res_header_Content-Length}";
|
||||
const DEBUG = ">>>>>>>>\n{request}\n<<<<<<<<\n{response}\n--------\n{error}";
|
||||
const SHORT = '[{ts}] "{method} {target} HTTP/{version}" {code}';
|
||||
|
||||
/** @var string Template used to format log messages */
|
||||
private $template;
|
||||
|
||||
/**
|
||||
* @param string $template Log message template
|
||||
*/
|
||||
public function __construct($template = self::CLF)
|
||||
{
|
||||
$this->template = $template ?: self::CLF;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a formatted message string.
|
||||
*
|
||||
* @param RequestInterface $request Request that was sent
|
||||
* @param ResponseInterface $response Response that was received
|
||||
* @param \Exception $error Exception that was received
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function format(
|
||||
RequestInterface $request,
|
||||
ResponseInterface $response = null,
|
||||
\Exception $error = null
|
||||
) {
|
||||
$cache = [];
|
||||
|
||||
return preg_replace_callback(
|
||||
'/{\s*([A-Za-z_\-\.0-9]+)\s*}/',
|
||||
function (array $matches) use ($request, $response, $error, &$cache) {
|
||||
|
||||
if (isset($cache[$matches[1]])) {
|
||||
return $cache[$matches[1]];
|
||||
}
|
||||
|
||||
$result = '';
|
||||
switch ($matches[1]) {
|
||||
case 'request':
|
||||
$result = Psr7\str($request);
|
||||
break;
|
||||
case 'response':
|
||||
$result = $response ? Psr7\str($response) : '';
|
||||
break;
|
||||
case 'req_headers':
|
||||
$result = trim($request->getMethod()
|
||||
. ' ' . $request->getRequestTarget())
|
||||
. ' HTTP/' . $request->getProtocolVersion() . "\r\n"
|
||||
. $this->headers($request);
|
||||
break;
|
||||
case 'res_headers':
|
||||
$result = $response ?
|
||||
sprintf(
|
||||
'HTTP/%s %d %s',
|
||||
$response->getProtocolVersion(),
|
||||
$response->getStatusCode(),
|
||||
$response->getReasonPhrase()
|
||||
) . "\r\n" . $this->headers($response)
|
||||
: 'NULL';
|
||||
break;
|
||||
case 'req_body':
|
||||
$result = $request->getBody();
|
||||
break;
|
||||
case 'res_body':
|
||||
$result = $response ? $response->getBody() : 'NULL';
|
||||
break;
|
||||
case 'ts':
|
||||
case 'date_iso_8601':
|
||||
$result = gmdate('c');
|
||||
break;
|
||||
case 'date_common_log':
|
||||
$result = date('d/M/Y:H:i:s O');
|
||||
break;
|
||||
case 'method':
|
||||
$result = $request->getMethod();
|
||||
break;
|
||||
case 'version':
|
||||
$result = $request->getProtocolVersion();
|
||||
break;
|
||||
case 'uri':
|
||||
case 'url':
|
||||
$result = $request->getUri();
|
||||
break;
|
||||
case 'target':
|
||||
$result = $request->getRequestTarget();
|
||||
break;
|
||||
case 'req_version':
|
||||
$result = $request->getProtocolVersion();
|
||||
break;
|
||||
case 'res_version':
|
||||
$result = $response
|
||||
? $response->getProtocolVersion()
|
||||
: 'NULL';
|
||||
break;
|
||||
case 'host':
|
||||
$result = $request->getHeaderLine('Host');
|
||||
break;
|
||||
case 'hostname':
|
||||
$result = gethostname();
|
||||
break;
|
||||
case 'code':
|
||||
$result = $response ? $response->getStatusCode() : 'NULL';
|
||||
break;
|
||||
case 'phrase':
|
||||
$result = $response ? $response->getReasonPhrase() : 'NULL';
|
||||
break;
|
||||
case 'error':
|
||||
$result = $error ? $error->getMessage() : 'NULL';
|
||||
break;
|
||||
default:
|
||||
// handle prefixed dynamic headers
|
||||
if (strpos($matches[1], 'req_header_') === 0) {
|
||||
$result = $request->getHeaderLine(substr($matches[1], 11));
|
||||
} elseif (strpos($matches[1], 'res_header_') === 0) {
|
||||
$result = $response
|
||||
? $response->getHeaderLine(substr($matches[1], 11))
|
||||
: 'NULL';
|
||||
}
|
||||
}
|
||||
|
||||
$cache[$matches[1]] = $result;
|
||||
return $result;
|
||||
},
|
||||
$this->template
|
||||
);
|
||||
}
|
||||
|
||||
private function headers(MessageInterface $message)
|
||||
{
|
||||
$result = '';
|
||||
foreach ($message->getHeaders() as $name => $values) {
|
||||
$result .= $name . ': ' . implode(', ', $values) . "\r\n";
|
||||
}
|
||||
|
||||
return trim($result);
|
||||
}
|
||||
}
|
249
server/vendor/guzzlehttp/guzzle/src/Middleware.php
vendored
Normal file
249
server/vendor/guzzlehttp/guzzle/src/Middleware.php
vendored
Normal file
|
@ -0,0 +1,249 @@
|
|||
<?php
|
||||
namespace GuzzleHttp;
|
||||
|
||||
use GuzzleHttp\Cookie\CookieJarInterface;
|
||||
use GuzzleHttp\Exception\RequestException;
|
||||
use GuzzleHttp\Promise\RejectedPromise;
|
||||
use GuzzleHttp\Psr7;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Log\LoggerInterface;
|
||||
use Psr\Log\LogLevel;
|
||||
|
||||
/**
|
||||
* Functions used to create and wrap handlers with handler middleware.
|
||||
*/
|
||||
final class Middleware
|
||||
{
|
||||
/**
|
||||
* Middleware that adds cookies to requests.
|
||||
*
|
||||
* The options array must be set to a CookieJarInterface in order to use
|
||||
* cookies. This is typically handled for you by a client.
|
||||
*
|
||||
* @return callable Returns a function that accepts the next handler.
|
||||
*/
|
||||
public static function cookies()
|
||||
{
|
||||
return function (callable $handler) {
|
||||
return function ($request, array $options) use ($handler) {
|
||||
if (empty($options['cookies'])) {
|
||||
return $handler($request, $options);
|
||||
} elseif (!($options['cookies'] instanceof CookieJarInterface)) {
|
||||
throw new \InvalidArgumentException('cookies must be an instance of GuzzleHttp\Cookie\CookieJarInterface');
|
||||
}
|
||||
$cookieJar = $options['cookies'];
|
||||
$request = $cookieJar->withCookieHeader($request);
|
||||
return $handler($request, $options)
|
||||
->then(function ($response) use ($cookieJar, $request) {
|
||||
$cookieJar->extractCookies($request, $response);
|
||||
return $response;
|
||||
}
|
||||
);
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Middleware that throws exceptions for 4xx or 5xx responses when the
|
||||
* "http_error" request option is set to true.
|
||||
*
|
||||
* @return callable Returns a function that accepts the next handler.
|
||||
*/
|
||||
public static function httpErrors()
|
||||
{
|
||||
return function (callable $handler) {
|
||||
return function ($request, array $options) use ($handler) {
|
||||
if (empty($options['http_errors'])) {
|
||||
return $handler($request, $options);
|
||||
}
|
||||
return $handler($request, $options)->then(
|
||||
function (ResponseInterface $response) use ($request, $handler) {
|
||||
$code = $response->getStatusCode();
|
||||
if ($code < 400) {
|
||||
return $response;
|
||||
}
|
||||
throw RequestException::create($request, $response);
|
||||
}
|
||||
);
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Middleware that pushes history data to an ArrayAccess container.
|
||||
*
|
||||
* @param array $container Container to hold the history (by reference).
|
||||
*
|
||||
* @return callable Returns a function that accepts the next handler.
|
||||
*/
|
||||
public static function history(array &$container)
|
||||
{
|
||||
return function (callable $handler) use (&$container) {
|
||||
return function ($request, array $options) use ($handler, &$container) {
|
||||
return $handler($request, $options)->then(
|
||||
function ($value) use ($request, &$container, $options) {
|
||||
$container[] = [
|
||||
'request' => $request,
|
||||
'response' => $value,
|
||||
'error' => null,
|
||||
'options' => $options
|
||||
];
|
||||
return $value;
|
||||
},
|
||||
function ($reason) use ($request, &$container, $options) {
|
||||
$container[] = [
|
||||
'request' => $request,
|
||||
'response' => null,
|
||||
'error' => $reason,
|
||||
'options' => $options
|
||||
];
|
||||
return new RejectedPromise($reason);
|
||||
}
|
||||
);
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Middleware that invokes a callback before and after sending a request.
|
||||
*
|
||||
* The provided listener cannot modify or alter the response. It simply
|
||||
* "taps" into the chain to be notified before returning the promise. The
|
||||
* before listener accepts a request and options array, and the after
|
||||
* listener accepts a request, options array, and response promise.
|
||||
*
|
||||
* @param callable $before Function to invoke before forwarding the request.
|
||||
* @param callable $after Function invoked after forwarding.
|
||||
*
|
||||
* @return callable Returns a function that accepts the next handler.
|
||||
*/
|
||||
public static function tap(callable $before = null, callable $after = null)
|
||||
{
|
||||
return function (callable $handler) use ($before, $after) {
|
||||
return function ($request, array $options) use ($handler, $before, $after) {
|
||||
if ($before) {
|
||||
$before($request, $options);
|
||||
}
|
||||
$response = $handler($request, $options);
|
||||
if ($after) {
|
||||
$after($request, $options, $response);
|
||||
}
|
||||
return $response;
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Middleware that handles request redirects.
|
||||
*
|
||||
* @return callable Returns a function that accepts the next handler.
|
||||
*/
|
||||
public static function redirect()
|
||||
{
|
||||
return function (callable $handler) {
|
||||
return new RedirectMiddleware($handler);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Middleware that retries requests based on the boolean result of
|
||||
* invoking the provided "decider" function.
|
||||
*
|
||||
* If no delay function is provided, a simple implementation of exponential
|
||||
* backoff will be utilized.
|
||||
*
|
||||
* @param callable $decider Function that accepts the number of retries,
|
||||
* a request, [response], and [exception] and
|
||||
* returns true if the request is to be retried.
|
||||
* @param callable $delay Function that accepts the number of retries and
|
||||
* returns the number of milliseconds to delay.
|
||||
*
|
||||
* @return callable Returns a function that accepts the next handler.
|
||||
*/
|
||||
public static function retry(callable $decider, callable $delay = null)
|
||||
{
|
||||
return function (callable $handler) use ($decider, $delay) {
|
||||
return new RetryMiddleware($decider, $handler, $delay);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Middleware that logs requests, responses, and errors using a message
|
||||
* formatter.
|
||||
*
|
||||
* @param LoggerInterface $logger Logs messages.
|
||||
* @param MessageFormatter $formatter Formatter used to create message strings.
|
||||
* @param string $logLevel Level at which to log requests.
|
||||
*
|
||||
* @return callable Returns a function that accepts the next handler.
|
||||
*/
|
||||
public static function log(LoggerInterface $logger, MessageFormatter $formatter, $logLevel = LogLevel::INFO)
|
||||
{
|
||||
return function (callable $handler) use ($logger, $formatter, $logLevel) {
|
||||
return function ($request, array $options) use ($handler, $logger, $formatter, $logLevel) {
|
||||
return $handler($request, $options)->then(
|
||||
function ($response) use ($logger, $request, $formatter, $logLevel) {
|
||||
$message = $formatter->format($request, $response);
|
||||
$logger->log($logLevel, $message);
|
||||
return $response;
|
||||
},
|
||||
function ($reason) use ($logger, $request, $formatter) {
|
||||
$response = $reason instanceof RequestException
|
||||
? $reason->getResponse()
|
||||
: null;
|
||||
$message = $formatter->format($request, $response, $reason);
|
||||
$logger->notice($message);
|
||||
return \GuzzleHttp\Promise\rejection_for($reason);
|
||||
}
|
||||
);
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* This middleware adds a default content-type if possible, a default
|
||||
* content-length or transfer-encoding header, and the expect header.
|
||||
*
|
||||
* @return callable
|
||||
*/
|
||||
public static function prepareBody()
|
||||
{
|
||||
return function (callable $handler) {
|
||||
return new PrepareBodyMiddleware($handler);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Middleware that applies a map function to the request before passing to
|
||||
* the next handler.
|
||||
*
|
||||
* @param callable $fn Function that accepts a RequestInterface and returns
|
||||
* a RequestInterface.
|
||||
* @return callable
|
||||
*/
|
||||
public static function mapRequest(callable $fn)
|
||||
{
|
||||
return function (callable $handler) use ($fn) {
|
||||
return function ($request, array $options) use ($handler, $fn) {
|
||||
return $handler($fn($request), $options);
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Middleware that applies a map function to the resolved promise's
|
||||
* response.
|
||||
*
|
||||
* @param callable $fn Function that accepts a ResponseInterface and
|
||||
* returns a ResponseInterface.
|
||||
* @return callable
|
||||
*/
|
||||
public static function mapResponse(callable $fn)
|
||||
{
|
||||
return function (callable $handler) use ($fn) {
|
||||
return function ($request, array $options) use ($handler, $fn) {
|
||||
return $handler($request, $options)->then($fn);
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
123
server/vendor/guzzlehttp/guzzle/src/Pool.php
vendored
Normal file
123
server/vendor/guzzlehttp/guzzle/src/Pool.php
vendored
Normal file
|
@ -0,0 +1,123 @@
|
|||
<?php
|
||||
namespace GuzzleHttp;
|
||||
|
||||
use GuzzleHttp\Promise\PromisorInterface;
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
use GuzzleHttp\Promise\EachPromise;
|
||||
|
||||
/**
|
||||
* Sends and iterator of requests concurrently using a capped pool size.
|
||||
*
|
||||
* The pool will read from an iterator until it is cancelled or until the
|
||||
* iterator is consumed. When a request is yielded, the request is sent after
|
||||
* applying the "request_options" request options (if provided in the ctor).
|
||||
*
|
||||
* When a function is yielded by the iterator, the function is provided the
|
||||
* "request_options" array that should be merged on top of any existing
|
||||
* options, and the function MUST then return a wait-able promise.
|
||||
*/
|
||||
class Pool implements PromisorInterface
|
||||
{
|
||||
/** @var EachPromise */
|
||||
private $each;
|
||||
|
||||
/**
|
||||
* @param ClientInterface $client Client used to send the requests.
|
||||
* @param array|\Iterator $requests Requests or functions that return
|
||||
* requests to send concurrently.
|
||||
* @param array $config Associative array of options
|
||||
* - concurrency: (int) Maximum number of requests to send concurrently
|
||||
* - options: Array of request options to apply to each request.
|
||||
* - fulfilled: (callable) Function to invoke when a request completes.
|
||||
* - rejected: (callable) Function to invoke when a request is rejected.
|
||||
*/
|
||||
public function __construct(
|
||||
ClientInterface $client,
|
||||
$requests,
|
||||
array $config = []
|
||||
) {
|
||||
// Backwards compatibility.
|
||||
if (isset($config['pool_size'])) {
|
||||
$config['concurrency'] = $config['pool_size'];
|
||||
} elseif (!isset($config['concurrency'])) {
|
||||
$config['concurrency'] = 25;
|
||||
}
|
||||
|
||||
if (isset($config['options'])) {
|
||||
$opts = $config['options'];
|
||||
unset($config['options']);
|
||||
} else {
|
||||
$opts = [];
|
||||
}
|
||||
|
||||
$iterable = \GuzzleHttp\Promise\iter_for($requests);
|
||||
$requests = function () use ($iterable, $client, $opts) {
|
||||
foreach ($iterable as $key => $rfn) {
|
||||
if ($rfn instanceof RequestInterface) {
|
||||
yield $key => $client->sendAsync($rfn, $opts);
|
||||
} elseif (is_callable($rfn)) {
|
||||
yield $key => $rfn($opts);
|
||||
} else {
|
||||
throw new \InvalidArgumentException('Each value yielded by '
|
||||
. 'the iterator must be a Psr7\Http\Message\RequestInterface '
|
||||
. 'or a callable that returns a promise that fulfills '
|
||||
. 'with a Psr7\Message\Http\ResponseInterface object.');
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
$this->each = new EachPromise($requests(), $config);
|
||||
}
|
||||
|
||||
public function promise()
|
||||
{
|
||||
return $this->each->promise();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends multiple requests concurrently and returns an array of responses
|
||||
* and exceptions that uses the same ordering as the provided requests.
|
||||
*
|
||||
* IMPORTANT: This method keeps every request and response in memory, and
|
||||
* as such, is NOT recommended when sending a large number or an
|
||||
* indeterminate number of requests concurrently.
|
||||
*
|
||||
* @param ClientInterface $client Client used to send the requests
|
||||
* @param array|\Iterator $requests Requests to send concurrently.
|
||||
* @param array $options Passes through the options available in
|
||||
* {@see GuzzleHttp\Pool::__construct}
|
||||
*
|
||||
* @return array Returns an array containing the response or an exception
|
||||
* in the same order that the requests were sent.
|
||||
* @throws \InvalidArgumentException if the event format is incorrect.
|
||||
*/
|
||||
public static function batch(
|
||||
ClientInterface $client,
|
||||
$requests,
|
||||
array $options = []
|
||||
) {
|
||||
$res = [];
|
||||
self::cmpCallback($options, 'fulfilled', $res);
|
||||
self::cmpCallback($options, 'rejected', $res);
|
||||
$pool = new static($client, $requests, $options);
|
||||
$pool->promise()->wait();
|
||||
ksort($res);
|
||||
|
||||
return $res;
|
||||
}
|
||||
|
||||
private static function cmpCallback(array &$options, $name, array &$results)
|
||||
{
|
||||
if (!isset($options[$name])) {
|
||||
$options[$name] = function ($v, $k) use (&$results) {
|
||||
$results[$k] = $v;
|
||||
};
|
||||
} else {
|
||||
$currentFn = $options[$name];
|
||||
$options[$name] = function ($v, $k) use (&$results, $currentFn) {
|
||||
$currentFn($v, $k);
|
||||
$results[$k] = $v;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
112
server/vendor/guzzlehttp/guzzle/src/PrepareBodyMiddleware.php
vendored
Normal file
112
server/vendor/guzzlehttp/guzzle/src/PrepareBodyMiddleware.php
vendored
Normal file
|
@ -0,0 +1,112 @@
|
|||
<?php
|
||||
namespace GuzzleHttp;
|
||||
|
||||
use GuzzleHttp\Promise\PromiseInterface;
|
||||
use GuzzleHttp\Psr7;
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
|
||||
/**
|
||||
* Prepares requests that contain a body, adding the Content-Length,
|
||||
* Content-Type, and Expect headers.
|
||||
*/
|
||||
class PrepareBodyMiddleware
|
||||
{
|
||||
/** @var callable */
|
||||
private $nextHandler;
|
||||
|
||||
/** @var array */
|
||||
private static $skipMethods = ['GET' => true, 'HEAD' => true];
|
||||
|
||||
/**
|
||||
* @param callable $nextHandler Next handler to invoke.
|
||||
*/
|
||||
public function __construct(callable $nextHandler)
|
||||
{
|
||||
$this->nextHandler = $nextHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param RequestInterface $request
|
||||
* @param array $options
|
||||
*
|
||||
* @return PromiseInterface
|
||||
*/
|
||||
public function __invoke(RequestInterface $request, array $options)
|
||||
{
|
||||
$fn = $this->nextHandler;
|
||||
|
||||
// Don't do anything if the request has no body.
|
||||
if (isset(self::$skipMethods[$request->getMethod()])
|
||||
|| $request->getBody()->getSize() === 0
|
||||
) {
|
||||
return $fn($request, $options);
|
||||
}
|
||||
|
||||
$modify = [];
|
||||
|
||||
// Add a default content-type if possible.
|
||||
if (!$request->hasHeader('Content-Type')) {
|
||||
if ($uri = $request->getBody()->getMetadata('uri')) {
|
||||
if ($type = Psr7\mimetype_from_filename($uri)) {
|
||||
$modify['set_headers']['Content-Type'] = $type;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add a default content-length or transfer-encoding header.
|
||||
if (!isset(self::$skipMethods[$request->getMethod()])
|
||||
&& !$request->hasHeader('Content-Length')
|
||||
&& !$request->hasHeader('Transfer-Encoding')
|
||||
) {
|
||||
$size = $request->getBody()->getSize();
|
||||
if ($size !== null) {
|
||||
$modify['set_headers']['Content-Length'] = $size;
|
||||
} else {
|
||||
$modify['set_headers']['Transfer-Encoding'] = 'chunked';
|
||||
}
|
||||
}
|
||||
|
||||
// Add the expect header if needed.
|
||||
$this->addExpectHeader($request, $options, $modify);
|
||||
|
||||
return $fn(Psr7\modify_request($request, $modify), $options);
|
||||
}
|
||||
|
||||
private function addExpectHeader(
|
||||
RequestInterface $request,
|
||||
array $options,
|
||||
array &$modify
|
||||
) {
|
||||
// Determine if the Expect header should be used
|
||||
if ($request->hasHeader('Expect')) {
|
||||
return;
|
||||
}
|
||||
|
||||
$expect = isset($options['expect']) ? $options['expect'] : null;
|
||||
|
||||
// Return if disabled or if you're not using HTTP/1.1 or HTTP/2.0
|
||||
if ($expect === false || $request->getProtocolVersion() < 1.1) {
|
||||
return;
|
||||
}
|
||||
|
||||
// The expect header is unconditionally enabled
|
||||
if ($expect === true) {
|
||||
$modify['set_headers']['Expect'] = '100-Continue';
|
||||
return;
|
||||
}
|
||||
|
||||
// By default, send the expect header when the payload is > 1mb
|
||||
if ($expect === null) {
|
||||
$expect = 1048576;
|
||||
}
|
||||
|
||||
// Always add if the body cannot be rewound, the size cannot be
|
||||
// determined, or the size is greater than the cutoff threshold
|
||||
$body = $request->getBody();
|
||||
$size = $body->getSize();
|
||||
|
||||
if ($size === null || $size >= (int) $expect || !$body->isSeekable()) {
|
||||
$modify['set_headers']['Expect'] = '100-Continue';
|
||||
}
|
||||
}
|
||||
}
|
231
server/vendor/guzzlehttp/guzzle/src/RedirectMiddleware.php
vendored
Normal file
231
server/vendor/guzzlehttp/guzzle/src/RedirectMiddleware.php
vendored
Normal file
|
@ -0,0 +1,231 @@
|
|||
<?php
|
||||
namespace GuzzleHttp;
|
||||
|
||||
use GuzzleHttp\Exception\BadResponseException;
|
||||
use GuzzleHttp\Exception\TooManyRedirectsException;
|
||||
use GuzzleHttp\Promise\PromiseInterface;
|
||||
use GuzzleHttp\Psr7;
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\UriInterface;
|
||||
|
||||
/**
|
||||
* Request redirect middleware.
|
||||
*
|
||||
* Apply this middleware like other middleware using
|
||||
* {@see GuzzleHttp\Middleware::redirect()}.
|
||||
*/
|
||||
class RedirectMiddleware
|
||||
{
|
||||
const HISTORY_HEADER = 'X-Guzzle-Redirect-History';
|
||||
|
||||
public static $defaultSettings = [
|
||||
'max' => 5,
|
||||
'protocols' => ['http', 'https'],
|
||||
'strict' => false,
|
||||
'referer' => false,
|
||||
'track_redirects' => false,
|
||||
];
|
||||
|
||||
/** @var callable */
|
||||
private $nextHandler;
|
||||
|
||||
/**
|
||||
* @param callable $nextHandler Next handler to invoke.
|
||||
*/
|
||||
public function __construct(callable $nextHandler)
|
||||
{
|
||||
$this->nextHandler = $nextHandler;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param RequestInterface $request
|
||||
* @param array $options
|
||||
*
|
||||
* @return PromiseInterface
|
||||
*/
|
||||
public function __invoke(RequestInterface $request, array $options)
|
||||
{
|
||||
$fn = $this->nextHandler;
|
||||
|
||||
if (empty($options['allow_redirects'])) {
|
||||
return $fn($request, $options);
|
||||
}
|
||||
|
||||
if ($options['allow_redirects'] === true) {
|
||||
$options['allow_redirects'] = self::$defaultSettings;
|
||||
} elseif (!is_array($options['allow_redirects'])) {
|
||||
throw new \InvalidArgumentException('allow_redirects must be true, false, or array');
|
||||
} else {
|
||||
// Merge the default settings with the provided settings
|
||||
$options['allow_redirects'] += self::$defaultSettings;
|
||||
}
|
||||
|
||||
if (empty($options['allow_redirects']['max'])) {
|
||||
return $fn($request, $options);
|
||||
}
|
||||
|
||||
return $fn($request, $options)
|
||||
->then(function (ResponseInterface $response) use ($request, $options) {
|
||||
return $this->checkRedirect($request, $options, $response);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* @param RequestInterface $request
|
||||
* @param array $options
|
||||
* @param ResponseInterface|PromiseInterface $response
|
||||
*
|
||||
* @return ResponseInterface|PromiseInterface
|
||||
*/
|
||||
public function checkRedirect(
|
||||
RequestInterface $request,
|
||||
array $options,
|
||||
ResponseInterface $response
|
||||
) {
|
||||
if (substr($response->getStatusCode(), 0, 1) != '3'
|
||||
|| !$response->hasHeader('Location')
|
||||
) {
|
||||
return $response;
|
||||
}
|
||||
|
||||
$this->guardMax($request, $options);
|
||||
$nextRequest = $this->modifyRequest($request, $options, $response);
|
||||
|
||||
if (isset($options['allow_redirects']['on_redirect'])) {
|
||||
call_user_func(
|
||||
$options['allow_redirects']['on_redirect'],
|
||||
$request,
|
||||
$response,
|
||||
$nextRequest->getUri()
|
||||
);
|
||||
}
|
||||
|
||||
/** @var PromiseInterface|ResponseInterface $promise */
|
||||
$promise = $this($nextRequest, $options);
|
||||
|
||||
// Add headers to be able to track history of redirects.
|
||||
if (!empty($options['allow_redirects']['track_redirects'])) {
|
||||
return $this->withTracking(
|
||||
$promise,
|
||||
(string) $nextRequest->getUri()
|
||||
);
|
||||
}
|
||||
|
||||
return $promise;
|
||||
}
|
||||
|
||||
private function withTracking(PromiseInterface $promise, $uri)
|
||||
{
|
||||
return $promise->then(
|
||||
function (ResponseInterface $response) use ($uri) {
|
||||
// Note that we are pushing to the front of the list as this
|
||||
// would be an earlier response than what is currently present
|
||||
// in the history header.
|
||||
$header = $response->getHeader(self::HISTORY_HEADER);
|
||||
array_unshift($header, $uri);
|
||||
return $response->withHeader(self::HISTORY_HEADER, $header);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private function guardMax(RequestInterface $request, array &$options)
|
||||
{
|
||||
$current = isset($options['__redirect_count'])
|
||||
? $options['__redirect_count']
|
||||
: 0;
|
||||
$options['__redirect_count'] = $current + 1;
|
||||
$max = $options['allow_redirects']['max'];
|
||||
|
||||
if ($options['__redirect_count'] > $max) {
|
||||
throw new TooManyRedirectsException(
|
||||
"Will not follow more than {$max} redirects",
|
||||
$request
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param RequestInterface $request
|
||||
* @param array $options
|
||||
* @param ResponseInterface $response
|
||||
*
|
||||
* @return RequestInterface
|
||||
*/
|
||||
public function modifyRequest(
|
||||
RequestInterface $request,
|
||||
array $options,
|
||||
ResponseInterface $response
|
||||
) {
|
||||
// Request modifications to apply.
|
||||
$modify = [];
|
||||
$protocols = $options['allow_redirects']['protocols'];
|
||||
|
||||
// Use a GET request if this is an entity enclosing request and we are
|
||||
// not forcing RFC compliance, but rather emulating what all browsers
|
||||
// would do.
|
||||
$statusCode = $response->getStatusCode();
|
||||
if ($statusCode == 303 ||
|
||||
($statusCode <= 302 && $request->getBody() && !$options['allow_redirects']['strict'])
|
||||
) {
|
||||
$modify['method'] = 'GET';
|
||||
$modify['body'] = '';
|
||||
}
|
||||
|
||||
$modify['uri'] = $this->redirectUri($request, $response, $protocols);
|
||||
Psr7\rewind_body($request);
|
||||
|
||||
// Add the Referer header if it is told to do so and only
|
||||
// add the header if we are not redirecting from https to http.
|
||||
if ($options['allow_redirects']['referer']
|
||||
&& $modify['uri']->getScheme() === $request->getUri()->getScheme()
|
||||
) {
|
||||
$uri = $request->getUri()->withUserInfo('', '');
|
||||
$modify['set_headers']['Referer'] = (string) $uri;
|
||||
} else {
|
||||
$modify['remove_headers'][] = 'Referer';
|
||||
}
|
||||
|
||||
// Remove Authorization header if host is different.
|
||||
if ($request->getUri()->getHost() !== $modify['uri']->getHost()) {
|
||||
$modify['remove_headers'][] = 'Authorization';
|
||||
}
|
||||
|
||||
return Psr7\modify_request($request, $modify);
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the appropriate URL on the request based on the location header
|
||||
*
|
||||
* @param RequestInterface $request
|
||||
* @param ResponseInterface $response
|
||||
* @param array $protocols
|
||||
*
|
||||
* @return UriInterface
|
||||
*/
|
||||
private function redirectUri(
|
||||
RequestInterface $request,
|
||||
ResponseInterface $response,
|
||||
array $protocols
|
||||
) {
|
||||
$location = Psr7\Uri::resolve(
|
||||
$request->getUri(),
|
||||
$response->getHeaderLine('Location')
|
||||
);
|
||||
|
||||
// Ensure that the redirect URI is allowed based on the protocols.
|
||||
if (!in_array($location->getScheme(), $protocols)) {
|
||||
throw new BadResponseException(
|
||||
sprintf(
|
||||
'Redirect URI, %s, does not use one of the allowed redirect protocols: %s',
|
||||
$location,
|
||||
implode(', ', $protocols)
|
||||
),
|
||||
$request,
|
||||
$response
|
||||
);
|
||||
}
|
||||
|
||||
return $location;
|
||||
}
|
||||
}
|
244
server/vendor/guzzlehttp/guzzle/src/RequestOptions.php
vendored
Normal file
244
server/vendor/guzzlehttp/guzzle/src/RequestOptions.php
vendored
Normal file
|
@ -0,0 +1,244 @@
|
|||
<?php
|
||||
namespace GuzzleHttp;
|
||||
|
||||
/**
|
||||
* This class contains a list of built-in Guzzle request options.
|
||||
*
|
||||
* More documentation for each option can be found at http://guzzlephp.org/.
|
||||
*
|
||||
* @link http://docs.guzzlephp.org/en/v6/request-options.html
|
||||
*/
|
||||
final class RequestOptions
|
||||
{
|
||||
/**
|
||||
* allow_redirects: (bool|array) Controls redirect behavior. Pass false
|
||||
* to disable redirects, pass true to enable redirects, pass an
|
||||
* associative to provide custom redirect settings. Defaults to "false".
|
||||
* This option only works if your handler has the RedirectMiddleware. When
|
||||
* passing an associative array, you can provide the following key value
|
||||
* pairs:
|
||||
*
|
||||
* - max: (int, default=5) maximum number of allowed redirects.
|
||||
* - strict: (bool, default=false) Set to true to use strict redirects
|
||||
* meaning redirect POST requests with POST requests vs. doing what most
|
||||
* browsers do which is redirect POST requests with GET requests
|
||||
* - referer: (bool, default=true) Set to false to disable the Referer
|
||||
* header.
|
||||
* - protocols: (array, default=['http', 'https']) Allowed redirect
|
||||
* protocols.
|
||||
* - on_redirect: (callable) PHP callable that is invoked when a redirect
|
||||
* is encountered. The callable is invoked with the request, the redirect
|
||||
* response that was received, and the effective URI. Any return value
|
||||
* from the on_redirect function is ignored.
|
||||
*/
|
||||
const ALLOW_REDIRECTS = 'allow_redirects';
|
||||
|
||||
/**
|
||||
* auth: (array) Pass an array of HTTP authentication parameters to use
|
||||
* with the request. The array must contain the username in index [0],
|
||||
* the password in index [1], and you can optionally provide a built-in
|
||||
* authentication type in index [2]. Pass null to disable authentication
|
||||
* for a request.
|
||||
*/
|
||||
const AUTH = 'auth';
|
||||
|
||||
/**
|
||||
* body: (string|null|callable|iterator|object) Body to send in the
|
||||
* request.
|
||||
*/
|
||||
const BODY = 'body';
|
||||
|
||||
/**
|
||||
* cert: (string|array) Set to a string to specify the path to a file
|
||||
* containing a PEM formatted SSL client side certificate. If a password
|
||||
* is required, then set cert to an array containing the path to the PEM
|
||||
* file in the first array element followed by the certificate password
|
||||
* in the second array element.
|
||||
*/
|
||||
const CERT = 'cert';
|
||||
|
||||
/**
|
||||
* cookies: (bool|GuzzleHttp\Cookie\CookieJarInterface, default=false)
|
||||
* Specifies whether or not cookies are used in a request or what cookie
|
||||
* jar to use or what cookies to send. This option only works if your
|
||||
* handler has the `cookie` middleware. Valid values are `false` and
|
||||
* an instance of {@see GuzzleHttp\Cookie\CookieJarInterface}.
|
||||
*/
|
||||
const COOKIES = 'cookies';
|
||||
|
||||
/**
|
||||
* connect_timeout: (float, default=0) Float describing the number of
|
||||
* seconds to wait while trying to connect to a server. Use 0 to wait
|
||||
* indefinitely (the default behavior).
|
||||
*/
|
||||
const CONNECT_TIMEOUT = 'connect_timeout';
|
||||
|
||||
/**
|
||||
* debug: (bool|resource) Set to true or set to a PHP stream returned by
|
||||
* fopen() enable debug output with the HTTP handler used to send a
|
||||
* request.
|
||||
*/
|
||||
const DEBUG = 'debug';
|
||||
|
||||
/**
|
||||
* decode_content: (bool, default=true) Specify whether or not
|
||||
* Content-Encoding responses (gzip, deflate, etc.) are automatically
|
||||
* decoded.
|
||||
*/
|
||||
const DECODE_CONTENT = 'decode_content';
|
||||
|
||||
/**
|
||||
* delay: (int) The amount of time to delay before sending in milliseconds.
|
||||
*/
|
||||
const DELAY = 'delay';
|
||||
|
||||
/**
|
||||
* expect: (bool|integer) Controls the behavior of the
|
||||
* "Expect: 100-Continue" header.
|
||||
*
|
||||
* Set to `true` to enable the "Expect: 100-Continue" header for all
|
||||
* requests that sends a body. Set to `false` to disable the
|
||||
* "Expect: 100-Continue" header for all requests. Set to a number so that
|
||||
* the size of the payload must be greater than the number in order to send
|
||||
* the Expect header. Setting to a number will send the Expect header for
|
||||
* all requests in which the size of the payload cannot be determined or
|
||||
* where the body is not rewindable.
|
||||
*
|
||||
* By default, Guzzle will add the "Expect: 100-Continue" header when the
|
||||
* size of the body of a request is greater than 1 MB and a request is
|
||||
* using HTTP/1.1.
|
||||
*/
|
||||
const EXPECT = 'expect';
|
||||
|
||||
/**
|
||||
* form_params: (array) Associative array of form field names to values
|
||||
* where each value is a string or array of strings. Sets the Content-Type
|
||||
* header to application/x-www-form-urlencoded when no Content-Type header
|
||||
* is already present.
|
||||
*/
|
||||
const FORM_PARAMS = 'form_params';
|
||||
|
||||
/**
|
||||
* headers: (array) Associative array of HTTP headers. Each value MUST be
|
||||
* a string or array of strings.
|
||||
*/
|
||||
const HEADERS = 'headers';
|
||||
|
||||
/**
|
||||
* http_errors: (bool, default=true) Set to false to disable exceptions
|
||||
* when a non- successful HTTP response is received. By default,
|
||||
* exceptions will be thrown for 4xx and 5xx responses. This option only
|
||||
* works if your handler has the `httpErrors` middleware.
|
||||
*/
|
||||
const HTTP_ERRORS = 'http_errors';
|
||||
|
||||
/**
|
||||
* json: (mixed) Adds JSON data to a request. The provided value is JSON
|
||||
* encoded and a Content-Type header of application/json will be added to
|
||||
* the request if no Content-Type header is already present.
|
||||
*/
|
||||
const JSON = 'json';
|
||||
|
||||
/**
|
||||
* multipart: (array) Array of associative arrays, each containing a
|
||||
* required "name" key mapping to the form field, name, a required
|
||||
* "contents" key mapping to a StreamInterface|resource|string, an
|
||||
* optional "headers" associative array of custom headers, and an
|
||||
* optional "filename" key mapping to a string to send as the filename in
|
||||
* the part. If no "filename" key is present, then no "filename" attribute
|
||||
* will be added to the part.
|
||||
*/
|
||||
const MULTIPART = 'multipart';
|
||||
|
||||
/**
|
||||
* on_headers: (callable) A callable that is invoked when the HTTP headers
|
||||
* of the response have been received but the body has not yet begun to
|
||||
* download.
|
||||
*/
|
||||
const ON_HEADERS = 'on_headers';
|
||||
|
||||
/**
|
||||
* on_stats: (callable) allows you to get access to transfer statistics of
|
||||
* a request and access the lower level transfer details of the handler
|
||||
* associated with your client. ``on_stats`` is a callable that is invoked
|
||||
* when a handler has finished sending a request. The callback is invoked
|
||||
* with transfer statistics about the request, the response received, or
|
||||
* the error encountered. Included in the data is the total amount of time
|
||||
* taken to send the request.
|
||||
*/
|
||||
const ON_STATS = 'on_stats';
|
||||
|
||||
/**
|
||||
* progress: (callable) Defines a function to invoke when transfer
|
||||
* progress is made. The function accepts the following positional
|
||||
* arguments: the total number of bytes expected to be downloaded, the
|
||||
* number of bytes downloaded so far, the number of bytes expected to be
|
||||
* uploaded, the number of bytes uploaded so far.
|
||||
*/
|
||||
const PROGRESS = 'progress';
|
||||
|
||||
/**
|
||||
* proxy: (string|array) Pass a string to specify an HTTP proxy, or an
|
||||
* array to specify different proxies for different protocols (where the
|
||||
* key is the protocol and the value is a proxy string).
|
||||
*/
|
||||
const PROXY = 'proxy';
|
||||
|
||||
/**
|
||||
* query: (array|string) Associative array of query string values to add
|
||||
* to the request. This option uses PHP's http_build_query() to create
|
||||
* the string representation. Pass a string value if you need more
|
||||
* control than what this method provides
|
||||
*/
|
||||
const QUERY = 'query';
|
||||
|
||||
/**
|
||||
* sink: (resource|string|StreamInterface) Where the data of the
|
||||
* response is written to. Defaults to a PHP temp stream. Providing a
|
||||
* string will write data to a file by the given name.
|
||||
*/
|
||||
const SINK = 'sink';
|
||||
|
||||
/**
|
||||
* synchronous: (bool) Set to true to inform HTTP handlers that you intend
|
||||
* on waiting on the response. This can be useful for optimizations. Note
|
||||
* that a promise is still returned if you are using one of the async
|
||||
* client methods.
|
||||
*/
|
||||
const SYNCHRONOUS = 'synchronous';
|
||||
|
||||
/**
|
||||
* ssl_key: (array|string) Specify the path to a file containing a private
|
||||
* SSL key in PEM format. If a password is required, then set to an array
|
||||
* containing the path to the SSL key in the first array element followed
|
||||
* by the password required for the certificate in the second element.
|
||||
*/
|
||||
const SSL_KEY = 'ssl_key';
|
||||
|
||||
/**
|
||||
* stream: Set to true to attempt to stream a response rather than
|
||||
* download it all up-front.
|
||||
*/
|
||||
const STREAM = 'stream';
|
||||
|
||||
/**
|
||||
* verify: (bool|string, default=true) Describes the SSL certificate
|
||||
* verification behavior of a request. Set to true to enable SSL
|
||||
* certificate verification using the system CA bundle when available
|
||||
* (the default). Set to false to disable certificate verification (this
|
||||
* is insecure!). Set to a string to provide the path to a CA bundle on
|
||||
* disk to enable verification using a custom certificate.
|
||||
*/
|
||||
const VERIFY = 'verify';
|
||||
|
||||
/**
|
||||
* timeout: (float, default=0) Float describing the timeout of the
|
||||
* request in seconds. Use 0 to wait indefinitely (the default behavior).
|
||||
*/
|
||||
const TIMEOUT = 'timeout';
|
||||
|
||||
/**
|
||||
* version: (float) Specifies the HTTP protocol version to attempt to use.
|
||||
*/
|
||||
const VERSION = 'version';
|
||||
}
|
111
server/vendor/guzzlehttp/guzzle/src/RetryMiddleware.php
vendored
Normal file
111
server/vendor/guzzlehttp/guzzle/src/RetryMiddleware.php
vendored
Normal file
|
@ -0,0 +1,111 @@
|
|||
<?php
|
||||
namespace GuzzleHttp;
|
||||
|
||||
use GuzzleHttp\Promise\PromiseInterface;
|
||||
use GuzzleHttp\Promise\RejectedPromise;
|
||||
use GuzzleHttp\Psr7;
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
|
||||
/**
|
||||
* Middleware that retries requests based on the boolean result of
|
||||
* invoking the provided "decider" function.
|
||||
*/
|
||||
class RetryMiddleware
|
||||
{
|
||||
/** @var callable */
|
||||
private $nextHandler;
|
||||
|
||||
/** @var callable */
|
||||
private $decider;
|
||||
|
||||
/**
|
||||
* @param callable $decider Function that accepts the number of retries,
|
||||
* a request, [response], and [exception] and
|
||||
* returns true if the request is to be
|
||||
* retried.
|
||||
* @param callable $nextHandler Next handler to invoke.
|
||||
* @param callable $delay Function that accepts the number of retries
|
||||
* and returns the number of milliseconds to
|
||||
* delay.
|
||||
*/
|
||||
public function __construct(
|
||||
callable $decider,
|
||||
callable $nextHandler,
|
||||
callable $delay = null
|
||||
) {
|
||||
$this->decider = $decider;
|
||||
$this->nextHandler = $nextHandler;
|
||||
$this->delay = $delay ?: __CLASS__ . '::exponentialDelay';
|
||||
}
|
||||
|
||||
/**
|
||||
* Default exponential backoff delay function.
|
||||
*
|
||||
* @param $retries
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public static function exponentialDelay($retries)
|
||||
{
|
||||
return (int) pow(2, $retries - 1);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param RequestInterface $request
|
||||
* @param array $options
|
||||
*
|
||||
* @return PromiseInterface
|
||||
*/
|
||||
public function __invoke(RequestInterface $request, array $options)
|
||||
{
|
||||
if (!isset($options['retries'])) {
|
||||
$options['retries'] = 0;
|
||||
}
|
||||
|
||||
$fn = $this->nextHandler;
|
||||
return $fn($request, $options)
|
||||
->then(
|
||||
$this->onFulfilled($request, $options),
|
||||
$this->onRejected($request, $options)
|
||||
);
|
||||
}
|
||||
|
||||
private function onFulfilled(RequestInterface $req, array $options)
|
||||
{
|
||||
return function ($value) use ($req, $options) {
|
||||
if (!call_user_func(
|
||||
$this->decider,
|
||||
$options['retries'],
|
||||
$req,
|
||||
$value,
|
||||
null
|
||||
)) {
|
||||
return $value;
|
||||
}
|
||||
return $this->doRetry($req, $options);
|
||||
};
|
||||
}
|
||||
|
||||
private function onRejected(RequestInterface $req, array $options)
|
||||
{
|
||||
return function ($reason) use ($req, $options) {
|
||||
if (!call_user_func(
|
||||
$this->decider,
|
||||
$options['retries'],
|
||||
$req,
|
||||
null,
|
||||
$reason
|
||||
)) {
|
||||
return new RejectedPromise($reason);
|
||||
}
|
||||
return $this->doRetry($req, $options);
|
||||
};
|
||||
}
|
||||
|
||||
private function doRetry(RequestInterface $request, array $options)
|
||||
{
|
||||
$options['delay'] = call_user_func($this->delay, ++$options['retries']);
|
||||
|
||||
return $this($request, $options);
|
||||
}
|
||||
}
|
126
server/vendor/guzzlehttp/guzzle/src/TransferStats.php
vendored
Normal file
126
server/vendor/guzzlehttp/guzzle/src/TransferStats.php
vendored
Normal file
|
@ -0,0 +1,126 @@
|
|||
<?php
|
||||
namespace GuzzleHttp;
|
||||
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\UriInterface;
|
||||
|
||||
/**
|
||||
* Represents data at the point after it was transferred either successfully
|
||||
* or after a network error.
|
||||
*/
|
||||
final class TransferStats
|
||||
{
|
||||
private $request;
|
||||
private $response;
|
||||
private $transferTime;
|
||||
private $handlerStats;
|
||||
private $handlerErrorData;
|
||||
|
||||
/**
|
||||
* @param RequestInterface $request Request that was sent.
|
||||
* @param ResponseInterface $response Response received (if any)
|
||||
* @param null $transferTime Total handler transfer time.
|
||||
* @param mixed $handlerErrorData Handler error data.
|
||||
* @param array $handlerStats Handler specific stats.
|
||||
*/
|
||||
public function __construct(
|
||||
RequestInterface $request,
|
||||
ResponseInterface $response = null,
|
||||
$transferTime = null,
|
||||
$handlerErrorData = null,
|
||||
$handlerStats = []
|
||||
) {
|
||||
$this->request = $request;
|
||||
$this->response = $response;
|
||||
$this->transferTime = $transferTime;
|
||||
$this->handlerErrorData = $handlerErrorData;
|
||||
$this->handlerStats = $handlerStats;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return RequestInterface
|
||||
*/
|
||||
public function getRequest()
|
||||
{
|
||||
return $this->request;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the response that was received (if any).
|
||||
*
|
||||
* @return ResponseInterface|null
|
||||
*/
|
||||
public function getResponse()
|
||||
{
|
||||
return $this->response;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if a response was received.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function hasResponse()
|
||||
{
|
||||
return $this->response !== null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets handler specific error data.
|
||||
*
|
||||
* This might be an exception, a integer representing an error code, or
|
||||
* anything else. Relying on this value assumes that you know what handler
|
||||
* you are using.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getHandlerErrorData()
|
||||
{
|
||||
return $this->handlerErrorData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the effective URI the request was sent to.
|
||||
*
|
||||
* @return UriInterface
|
||||
*/
|
||||
public function getEffectiveUri()
|
||||
{
|
||||
return $this->request->getUri();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the estimated time the request was being transferred by the handler.
|
||||
*
|
||||
* @return float Time in seconds.
|
||||
*/
|
||||
public function getTransferTime()
|
||||
{
|
||||
return $this->transferTime;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an array of all of the handler specific transfer data.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function getHandlerStats()
|
||||
{
|
||||
return $this->handlerStats;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a specific handler statistic from the handler by name.
|
||||
*
|
||||
* @param string $stat Handler specific transfer stat to retrieve.
|
||||
*
|
||||
* @return mixed|null
|
||||
*/
|
||||
public function getHandlerStat($stat)
|
||||
{
|
||||
return isset($this->handlerStats[$stat])
|
||||
? $this->handlerStats[$stat]
|
||||
: null;
|
||||
}
|
||||
}
|
241
server/vendor/guzzlehttp/guzzle/src/UriTemplate.php
vendored
Normal file
241
server/vendor/guzzlehttp/guzzle/src/UriTemplate.php
vendored
Normal file
|
@ -0,0 +1,241 @@
|
|||
<?php
|
||||
namespace GuzzleHttp;
|
||||
|
||||
/**
|
||||
* Expands URI templates. Userland implementation of PECL uri_template.
|
||||
*
|
||||
* @link http://tools.ietf.org/html/rfc6570
|
||||
*/
|
||||
class UriTemplate
|
||||
{
|
||||
/** @var string URI template */
|
||||
private $template;
|
||||
|
||||
/** @var array Variables to use in the template expansion */
|
||||
private $variables;
|
||||
|
||||
/** @var array Hash for quick operator lookups */
|
||||
private static $operatorHash = array(
|
||||
'' => array('prefix' => '', 'joiner' => ',', 'query' => false),
|
||||
'+' => array('prefix' => '', 'joiner' => ',', 'query' => false),
|
||||
'#' => array('prefix' => '#', 'joiner' => ',', 'query' => false),
|
||||
'.' => array('prefix' => '.', 'joiner' => '.', 'query' => false),
|
||||
'/' => array('prefix' => '/', 'joiner' => '/', 'query' => false),
|
||||
';' => array('prefix' => ';', 'joiner' => ';', 'query' => true),
|
||||
'?' => array('prefix' => '?', 'joiner' => '&', 'query' => true),
|
||||
'&' => array('prefix' => '&', 'joiner' => '&', 'query' => true)
|
||||
);
|
||||
|
||||
/** @var array Delimiters */
|
||||
private static $delims = array(':', '/', '?', '#', '[', ']', '@', '!', '$',
|
||||
'&', '\'', '(', ')', '*', '+', ',', ';', '=');
|
||||
|
||||
/** @var array Percent encoded delimiters */
|
||||
private static $delimsPct = array('%3A', '%2F', '%3F', '%23', '%5B', '%5D',
|
||||
'%40', '%21', '%24', '%26', '%27', '%28', '%29', '%2A', '%2B', '%2C',
|
||||
'%3B', '%3D');
|
||||
|
||||
public function expand($template, array $variables)
|
||||
{
|
||||
if (false === strpos($template, '{')) {
|
||||
return $template;
|
||||
}
|
||||
|
||||
$this->template = $template;
|
||||
$this->variables = $variables;
|
||||
|
||||
return preg_replace_callback(
|
||||
'/\{([^\}]+)\}/',
|
||||
[$this, 'expandMatch'],
|
||||
$this->template
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse an expression into parts
|
||||
*
|
||||
* @param string $expression Expression to parse
|
||||
*
|
||||
* @return array Returns an associative array of parts
|
||||
*/
|
||||
private function parseExpression($expression)
|
||||
{
|
||||
$result = array();
|
||||
|
||||
if (isset(self::$operatorHash[$expression[0]])) {
|
||||
$result['operator'] = $expression[0];
|
||||
$expression = substr($expression, 1);
|
||||
} else {
|
||||
$result['operator'] = '';
|
||||
}
|
||||
|
||||
foreach (explode(',', $expression) as $value) {
|
||||
$value = trim($value);
|
||||
$varspec = array();
|
||||
if ($colonPos = strpos($value, ':')) {
|
||||
$varspec['value'] = substr($value, 0, $colonPos);
|
||||
$varspec['modifier'] = ':';
|
||||
$varspec['position'] = (int) substr($value, $colonPos + 1);
|
||||
} elseif (substr($value, -1) == '*') {
|
||||
$varspec['modifier'] = '*';
|
||||
$varspec['value'] = substr($value, 0, -1);
|
||||
} else {
|
||||
$varspec['value'] = (string) $value;
|
||||
$varspec['modifier'] = '';
|
||||
}
|
||||
$result['values'][] = $varspec;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Process an expansion
|
||||
*
|
||||
* @param array $matches Matches met in the preg_replace_callback
|
||||
*
|
||||
* @return string Returns the replacement string
|
||||
*/
|
||||
private function expandMatch(array $matches)
|
||||
{
|
||||
static $rfc1738to3986 = array('+' => '%20', '%7e' => '~');
|
||||
|
||||
$replacements = array();
|
||||
$parsed = self::parseExpression($matches[1]);
|
||||
$prefix = self::$operatorHash[$parsed['operator']]['prefix'];
|
||||
$joiner = self::$operatorHash[$parsed['operator']]['joiner'];
|
||||
$useQuery = self::$operatorHash[$parsed['operator']]['query'];
|
||||
|
||||
foreach ($parsed['values'] as $value) {
|
||||
|
||||
if (!isset($this->variables[$value['value']])) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$variable = $this->variables[$value['value']];
|
||||
$actuallyUseQuery = $useQuery;
|
||||
$expanded = '';
|
||||
|
||||
if (is_array($variable)) {
|
||||
|
||||
$isAssoc = $this->isAssoc($variable);
|
||||
$kvp = array();
|
||||
foreach ($variable as $key => $var) {
|
||||
|
||||
if ($isAssoc) {
|
||||
$key = rawurlencode($key);
|
||||
$isNestedArray = is_array($var);
|
||||
} else {
|
||||
$isNestedArray = false;
|
||||
}
|
||||
|
||||
if (!$isNestedArray) {
|
||||
$var = rawurlencode($var);
|
||||
if ($parsed['operator'] == '+' ||
|
||||
$parsed['operator'] == '#'
|
||||
) {
|
||||
$var = $this->decodeReserved($var);
|
||||
}
|
||||
}
|
||||
|
||||
if ($value['modifier'] == '*') {
|
||||
if ($isAssoc) {
|
||||
if ($isNestedArray) {
|
||||
// Nested arrays must allow for deeply nested
|
||||
// structures.
|
||||
$var = strtr(
|
||||
http_build_query([$key => $var]),
|
||||
$rfc1738to3986
|
||||
);
|
||||
} else {
|
||||
$var = $key . '=' . $var;
|
||||
}
|
||||
} elseif ($key > 0 && $actuallyUseQuery) {
|
||||
$var = $value['value'] . '=' . $var;
|
||||
}
|
||||
}
|
||||
|
||||
$kvp[$key] = $var;
|
||||
}
|
||||
|
||||
if (empty($variable)) {
|
||||
$actuallyUseQuery = false;
|
||||
} elseif ($value['modifier'] == '*') {
|
||||
$expanded = implode($joiner, $kvp);
|
||||
if ($isAssoc) {
|
||||
// Don't prepend the value name when using the explode
|
||||
// modifier with an associative array.
|
||||
$actuallyUseQuery = false;
|
||||
}
|
||||
} else {
|
||||
if ($isAssoc) {
|
||||
// When an associative array is encountered and the
|
||||
// explode modifier is not set, then the result must be
|
||||
// a comma separated list of keys followed by their
|
||||
// respective values.
|
||||
foreach ($kvp as $k => &$v) {
|
||||
$v = $k . ',' . $v;
|
||||
}
|
||||
}
|
||||
$expanded = implode(',', $kvp);
|
||||
}
|
||||
|
||||
} else {
|
||||
if ($value['modifier'] == ':') {
|
||||
$variable = substr($variable, 0, $value['position']);
|
||||
}
|
||||
$expanded = rawurlencode($variable);
|
||||
if ($parsed['operator'] == '+' || $parsed['operator'] == '#') {
|
||||
$expanded = $this->decodeReserved($expanded);
|
||||
}
|
||||
}
|
||||
|
||||
if ($actuallyUseQuery) {
|
||||
if (!$expanded && $joiner != '&') {
|
||||
$expanded = $value['value'];
|
||||
} else {
|
||||
$expanded = $value['value'] . '=' . $expanded;
|
||||
}
|
||||
}
|
||||
|
||||
$replacements[] = $expanded;
|
||||
}
|
||||
|
||||
$ret = implode($joiner, $replacements);
|
||||
if ($ret && $prefix) {
|
||||
return $prefix . $ret;
|
||||
}
|
||||
|
||||
return $ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines if an array is associative.
|
||||
*
|
||||
* This makes the assumption that input arrays are sequences or hashes.
|
||||
* This assumption is a tradeoff for accuracy in favor of speed, but it
|
||||
* should work in almost every case where input is supplied for a URI
|
||||
* template.
|
||||
*
|
||||
* @param array $array Array to check
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
private function isAssoc(array $array)
|
||||
{
|
||||
return $array && array_keys($array)[0] !== 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes percent encoding on reserved characters (used with + and #
|
||||
* modifiers).
|
||||
*
|
||||
* @param string $string String to fix
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function decodeReserved($string)
|
||||
{
|
||||
return str_replace(self::$delimsPct, self::$delims, $string);
|
||||
}
|
||||
}
|
284
server/vendor/guzzlehttp/guzzle/src/functions.php
vendored
Normal file
284
server/vendor/guzzlehttp/guzzle/src/functions.php
vendored
Normal file
|
@ -0,0 +1,284 @@
|
|||
<?php
|
||||
namespace GuzzleHttp;
|
||||
|
||||
use GuzzleHttp\Handler\CurlHandler;
|
||||
use GuzzleHttp\Handler\CurlMultiHandler;
|
||||
use GuzzleHttp\Handler\Proxy;
|
||||
use GuzzleHttp\Handler\StreamHandler;
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
|
||||
/**
|
||||
* Expands a URI template
|
||||
*
|
||||
* @param string $template URI template
|
||||
* @param array $variables Template variables
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function uri_template($template, array $variables)
|
||||
{
|
||||
if (extension_loaded('uri_template')) {
|
||||
// @codeCoverageIgnoreStart
|
||||
return \uri_template($template, $variables);
|
||||
// @codeCoverageIgnoreEnd
|
||||
}
|
||||
|
||||
static $uriTemplate;
|
||||
if (!$uriTemplate) {
|
||||
$uriTemplate = new UriTemplate();
|
||||
}
|
||||
|
||||
return $uriTemplate->expand($template, $variables);
|
||||
}
|
||||
|
||||
/**
|
||||
* Debug function used to describe the provided value type and class.
|
||||
*
|
||||
* @param mixed $input
|
||||
*
|
||||
* @return string Returns a string containing the type of the variable and
|
||||
* if a class is provided, the class name.
|
||||
*/
|
||||
function describe_type($input)
|
||||
{
|
||||
switch (gettype($input)) {
|
||||
case 'object':
|
||||
return 'object(' . get_class($input) . ')';
|
||||
case 'array':
|
||||
return 'array(' . count($input) . ')';
|
||||
default:
|
||||
ob_start();
|
||||
var_dump($input);
|
||||
// normalize float vs double
|
||||
return str_replace('double(', 'float(', rtrim(ob_get_clean()));
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an array of header lines into an associative array of headers.
|
||||
*
|
||||
* @param array $lines Header lines array of strings in the following
|
||||
* format: "Name: Value"
|
||||
* @return array
|
||||
*/
|
||||
function headers_from_lines($lines)
|
||||
{
|
||||
$headers = [];
|
||||
|
||||
foreach ($lines as $line) {
|
||||
$parts = explode(':', $line, 2);
|
||||
$headers[trim($parts[0])][] = isset($parts[1])
|
||||
? trim($parts[1])
|
||||
: null;
|
||||
}
|
||||
|
||||
return $headers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a debug stream based on the provided variable.
|
||||
*
|
||||
* @param mixed $value Optional value
|
||||
*
|
||||
* @return resource
|
||||
*/
|
||||
function debug_resource($value = null)
|
||||
{
|
||||
if (is_resource($value)) {
|
||||
return $value;
|
||||
} elseif (defined('STDOUT')) {
|
||||
return STDOUT;
|
||||
}
|
||||
|
||||
return fopen('php://output', 'w');
|
||||
}
|
||||
|
||||
/**
|
||||
* Chooses and creates a default handler to use based on the environment.
|
||||
*
|
||||
* The returned handler is not wrapped by any default middlewares.
|
||||
*
|
||||
* @throws \RuntimeException if no viable Handler is available.
|
||||
* @return callable Returns the best handler for the given system.
|
||||
*/
|
||||
function choose_handler()
|
||||
{
|
||||
$handler = null;
|
||||
if (function_exists('curl_multi_exec') && function_exists('curl_exec')) {
|
||||
$handler = Proxy::wrapSync(new CurlMultiHandler(), new CurlHandler());
|
||||
} elseif (function_exists('curl_exec')) {
|
||||
$handler = new CurlHandler();
|
||||
} elseif (function_exists('curl_multi_exec')) {
|
||||
$handler = new CurlMultiHandler();
|
||||
}
|
||||
|
||||
if (ini_get('allow_url_fopen')) {
|
||||
$handler = $handler
|
||||
? Proxy::wrapStreaming($handler, new StreamHandler())
|
||||
: new StreamHandler();
|
||||
} elseif (!$handler) {
|
||||
throw new \RuntimeException('GuzzleHttp requires cURL, the '
|
||||
. 'allow_url_fopen ini setting, or a custom HTTP handler.');
|
||||
}
|
||||
|
||||
return $handler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the default User-Agent string to use with Guzzle
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function default_user_agent()
|
||||
{
|
||||
static $defaultAgent = '';
|
||||
|
||||
if (!$defaultAgent) {
|
||||
$defaultAgent = 'GuzzleHttp/' . Client::VERSION;
|
||||
if (extension_loaded('curl') && function_exists('curl_version')) {
|
||||
$defaultAgent .= ' curl/' . \curl_version()['version'];
|
||||
}
|
||||
$defaultAgent .= ' PHP/' . PHP_VERSION;
|
||||
}
|
||||
|
||||
return $defaultAgent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the default cacert bundle for the current system.
|
||||
*
|
||||
* First, the openssl.cafile and curl.cainfo php.ini settings are checked.
|
||||
* If those settings are not configured, then the common locations for
|
||||
* bundles found on Red Hat, CentOS, Fedora, Ubuntu, Debian, FreeBSD, OS X
|
||||
* and Windows are checked. If any of these file locations are found on
|
||||
* disk, they will be utilized.
|
||||
*
|
||||
* Note: the result of this function is cached for subsequent calls.
|
||||
*
|
||||
* @return string
|
||||
* @throws \RuntimeException if no bundle can be found.
|
||||
*/
|
||||
function default_ca_bundle()
|
||||
{
|
||||
static $cached = null;
|
||||
static $cafiles = [
|
||||
// Red Hat, CentOS, Fedora (provided by the ca-certificates package)
|
||||
'/etc/pki/tls/certs/ca-bundle.crt',
|
||||
// Ubuntu, Debian (provided by the ca-certificates package)
|
||||
'/etc/ssl/certs/ca-certificates.crt',
|
||||
// FreeBSD (provided by the ca_root_nss package)
|
||||
'/usr/local/share/certs/ca-root-nss.crt',
|
||||
// OS X provided by homebrew (using the default path)
|
||||
'/usr/local/etc/openssl/cert.pem',
|
||||
// Google app engine
|
||||
'/etc/ca-certificates.crt',
|
||||
// Windows?
|
||||
'C:\\windows\\system32\\curl-ca-bundle.crt',
|
||||
'C:\\windows\\curl-ca-bundle.crt',
|
||||
];
|
||||
|
||||
if ($cached) {
|
||||
return $cached;
|
||||
}
|
||||
|
||||
if ($ca = ini_get('openssl.cafile')) {
|
||||
return $cached = $ca;
|
||||
}
|
||||
|
||||
if ($ca = ini_get('curl.cainfo')) {
|
||||
return $cached = $ca;
|
||||
}
|
||||
|
||||
foreach ($cafiles as $filename) {
|
||||
if (file_exists($filename)) {
|
||||
return $cached = $filename;
|
||||
}
|
||||
}
|
||||
|
||||
throw new \RuntimeException(<<< EOT
|
||||
No system CA bundle could be found in any of the the common system locations.
|
||||
PHP versions earlier than 5.6 are not properly configured to use the system's
|
||||
CA bundle by default. In order to verify peer certificates, you will need to
|
||||
supply the path on disk to a certificate bundle to the 'verify' request
|
||||
option: http://docs.guzzlephp.org/en/latest/clients.html#verify. If you do not
|
||||
need a specific certificate bundle, then Mozilla provides a commonly used CA
|
||||
bundle which can be downloaded here (provided by the maintainer of cURL):
|
||||
https://raw.githubusercontent.com/bagder/ca-bundle/master/ca-bundle.crt. Once
|
||||
you have a CA bundle available on disk, you can set the 'openssl.cafile' PHP
|
||||
ini setting to point to the path to the file, allowing you to omit the 'verify'
|
||||
request option. See http://curl.haxx.se/docs/sslcerts.html for more
|
||||
information.
|
||||
EOT
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an associative array of lowercase header names to the actual
|
||||
* header casing.
|
||||
*
|
||||
* @param array $headers
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function normalize_header_keys(array $headers)
|
||||
{
|
||||
$result = [];
|
||||
foreach (array_keys($headers) as $key) {
|
||||
$result[strtolower($key)] = $key;
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the provided host matches any of the no proxy areas.
|
||||
*
|
||||
* This method will strip a port from the host if it is present. Each pattern
|
||||
* can be matched with an exact match (e.g., "foo.com" == "foo.com") or a
|
||||
* partial match: (e.g., "foo.com" == "baz.foo.com" and ".foo.com" ==
|
||||
* "baz.foo.com", but ".foo.com" != "foo.com").
|
||||
*
|
||||
* Areas are matched in the following cases:
|
||||
* 1. "*" (without quotes) always matches any hosts.
|
||||
* 2. An exact match.
|
||||
* 3. The area starts with "." and the area is the last part of the host. e.g.
|
||||
* '.mit.edu' will match any host that ends with '.mit.edu'.
|
||||
*
|
||||
* @param string $host Host to check against the patterns.
|
||||
* @param array $noProxyArray An array of host patterns.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function is_host_in_noproxy($host, array $noProxyArray)
|
||||
{
|
||||
if (strlen($host) === 0) {
|
||||
throw new \InvalidArgumentException('Empty host provided');
|
||||
}
|
||||
|
||||
// Strip port if present.
|
||||
if (strpos($host, ':')) {
|
||||
$host = explode($host, ':', 2)[0];
|
||||
}
|
||||
|
||||
foreach ($noProxyArray as $area) {
|
||||
// Always match on wildcards.
|
||||
if ($area === '*') {
|
||||
return true;
|
||||
} elseif (empty($area)) {
|
||||
// Don't match on empty values.
|
||||
continue;
|
||||
} elseif ($area === $host) {
|
||||
// Exact matches.
|
||||
return true;
|
||||
} else {
|
||||
// Special match if the area when prefixed with ".". Remove any
|
||||
// existing leading "." and add a new leading ".".
|
||||
$area = '.' . ltrim($area, '.');
|
||||
if (substr($host, -(strlen($area))) === $area) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
6
server/vendor/guzzlehttp/guzzle/src/functions_include.php
vendored
Normal file
6
server/vendor/guzzlehttp/guzzle/src/functions_include.php
vendored
Normal file
|
@ -0,0 +1,6 @@
|
|||
<?php
|
||||
|
||||
// Don't redefine the functions if included multiple times.
|
||||
if (!function_exists('GuzzleHttp\uri_template')) {
|
||||
require __DIR__ . '/functions.php';
|
||||
}
|
11
server/vendor/guzzlehttp/promises/.gitignore
vendored
Normal file
11
server/vendor/guzzlehttp/promises/.gitignore
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
phpunit.xml
|
||||
composer.phar
|
||||
composer.lock
|
||||
composer-test.lock
|
||||
vendor/
|
||||
build/artifacts/
|
||||
artifacts/
|
||||
docs/_build
|
||||
docs/*.pyc
|
||||
.idea
|
||||
.DS_STORE
|
19
server/vendor/guzzlehttp/promises/.travis.yml
vendored
Normal file
19
server/vendor/guzzlehttp/promises/.travis.yml
vendored
Normal file
|
@ -0,0 +1,19 @@
|
|||
language: php
|
||||
|
||||
php:
|
||||
- 5.5
|
||||
- 5.6
|
||||
- 7.0
|
||||
- hhvm
|
||||
|
||||
sudo: false
|
||||
|
||||
install:
|
||||
- travis_retry composer install --no-interaction --prefer-source
|
||||
|
||||
script: make test
|
||||
|
||||
matrix:
|
||||
allow_failures:
|
||||
- php: hhvm
|
||||
fast_finish: true
|
21
server/vendor/guzzlehttp/promises/CHANGELOG.md
vendored
Normal file
21
server/vendor/guzzlehttp/promises/CHANGELOG.md
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
# CHANGELOG
|
||||
|
||||
## 1.0.3 - 2015-10-15
|
||||
|
||||
* Update EachPromise to immediately resolve when the underlying promise iterator
|
||||
is empty. Previously, such a promise would throw an exception when its `wait`
|
||||
function was called.
|
||||
|
||||
## 1.0.2 - 2015-05-15
|
||||
|
||||
* Conditionally require functions.php.
|
||||
|
||||
## 1.0.1 - 2015-06-24
|
||||
|
||||
* Updating EachPromise to call next on the underlying promise iterator as late
|
||||
as possible to ensure that generators that generate new requests based on
|
||||
callbacks are not iterated until after callbacks are invoked.
|
||||
|
||||
## 1.0.0 - 2015-05-12
|
||||
|
||||
* Initial release
|
19
server/vendor/guzzlehttp/promises/LICENSE
vendored
Normal file
19
server/vendor/guzzlehttp/promises/LICENSE
vendored
Normal file
|
@ -0,0 +1,19 @@
|
|||
Copyright (c) 2015 Michael Dowling, https://github.com/mtdowling <mtdowling@gmail.com>
|
||||
|
||||
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.
|
13
server/vendor/guzzlehttp/promises/Makefile
vendored
Normal file
13
server/vendor/guzzlehttp/promises/Makefile
vendored
Normal file
|
@ -0,0 +1,13 @@
|
|||
all: clean test
|
||||
|
||||
test:
|
||||
vendor/bin/phpunit
|
||||
|
||||
coverage:
|
||||
vendor/bin/phpunit --coverage-html=artifacts/coverage
|
||||
|
||||
view-coverage:
|
||||
open artifacts/coverage/index.html
|
||||
|
||||
clean:
|
||||
rm -rf artifacts/*
|
501
server/vendor/guzzlehttp/promises/README.md
vendored
Normal file
501
server/vendor/guzzlehttp/promises/README.md
vendored
Normal file
|
@ -0,0 +1,501 @@
|
|||
# Guzzle Promises
|
||||
|
||||
[Promises/A+](https://promisesaplus.com/) implementation that handles promise
|
||||
chaining and resolution iteratively, allowing for "infinite" promise chaining
|
||||
while keeping the stack size constant. Read [this blog post](https://blog.domenic.me/youre-missing-the-point-of-promises/)
|
||||
for a general introduction to promises.
|
||||
|
||||
- [Features](#features)
|
||||
- [Quick start](#quick-start)
|
||||
- [Synchronous wait](#synchronous-wait)
|
||||
- [Cancellation](#cancellation)
|
||||
- [API](#api)
|
||||
- [Promise](#promise)
|
||||
- [FulfilledPromise](#fulfilledpromise)
|
||||
- [RejectedPromise](#rejectedpromise)
|
||||
- [Promise interop](#promise-interop)
|
||||
- [Implementation notes](#implementation-notes)
|
||||
|
||||
|
||||
# Features
|
||||
|
||||
- [Promises/A+](https://promisesaplus.com/) implementation.
|
||||
- Promise resolution and chaining is handled iteratively, allowing for
|
||||
"infinite" promise chaining.
|
||||
- Promises have a synchronous `wait` method.
|
||||
- Promises can be cancelled.
|
||||
- Works with any object that has a `then` function.
|
||||
- C# style async/await coroutine promises using
|
||||
`GuzzleHttp\Promise\coroutine()`.
|
||||
|
||||
|
||||
# Quick start
|
||||
|
||||
A *promise* represents the eventual result of an asynchronous operation. The
|
||||
primary way of interacting with a promise is through its `then` method, which
|
||||
registers callbacks to receive either a promise's eventual value or the reason
|
||||
why the promise cannot be fulfilled.
|
||||
|
||||
|
||||
## Callbacks
|
||||
|
||||
Callbacks are registered with the `then` method by providing an optional
|
||||
`$onFulfilled` followed by an optional `$onRejected` function.
|
||||
|
||||
|
||||
```php
|
||||
use GuzzleHttp\Promise\Promise;
|
||||
|
||||
$promise = new Promise();
|
||||
$promise->then(
|
||||
// $onFulfilled
|
||||
function ($value) {
|
||||
echo 'The promise was fulfilled.';
|
||||
},
|
||||
// $onRejected
|
||||
function ($reason) {
|
||||
echo 'The promise was rejected.';
|
||||
}
|
||||
);
|
||||
```
|
||||
|
||||
*Resolving* a promise means that you either fulfill a promise with a *value* or
|
||||
reject a promise with a *reason*. Resolving a promises triggers callbacks
|
||||
registered with the promises's `then` method. These callbacks are triggered
|
||||
only once and in the order in which they were added.
|
||||
|
||||
|
||||
## Resolving a promise
|
||||
|
||||
Promises are fulfilled using the `resolve($value)` method. Resolving a promise
|
||||
with any value other than a `GuzzleHttp\Promise\RejectedPromise` will trigger
|
||||
all of the onFulfilled callbacks (resolving a promise with a rejected promise
|
||||
will reject the promise and trigger the `$onRejected` callbacks).
|
||||
|
||||
```php
|
||||
use GuzzleHttp\Promise\Promise;
|
||||
|
||||
$promise = new Promise();
|
||||
$promise
|
||||
->then(function ($value) {
|
||||
// Return a value and don't break the chain
|
||||
return "Hello, " . $value;
|
||||
})
|
||||
// This then is executed after the first then and receives the value
|
||||
// returned from the first then.
|
||||
->then(function ($value) {
|
||||
echo $value;
|
||||
});
|
||||
|
||||
// Resolving the promise triggers the $onFulfilled callbacks and outputs
|
||||
// "Hello, reader".
|
||||
$promise->resolve('reader.');
|
||||
```
|
||||
|
||||
|
||||
## Promise forwarding
|
||||
|
||||
Promises can be chained one after the other. Each then in the chain is a new
|
||||
promise. The return value of of a promise is what's forwarded to the next
|
||||
promise in the chain. Returning a promise in a `then` callback will cause the
|
||||
subsequent promises in the chain to only be fulfilled when the returned promise
|
||||
has been fulfilled. The next promise in the chain will be invoked with the
|
||||
resolved value of the promise.
|
||||
|
||||
```php
|
||||
use GuzzleHttp\Promise\Promise;
|
||||
|
||||
$promise = new Promise();
|
||||
$nextPromise = new Promise();
|
||||
|
||||
$promise
|
||||
->then(function ($value) use ($nextPromise) {
|
||||
echo $value;
|
||||
return $nextPromise;
|
||||
})
|
||||
->then(function ($value) {
|
||||
echo $value;
|
||||
});
|
||||
|
||||
// Triggers the first callback and outputs "A"
|
||||
$promise->resolve('A');
|
||||
// Triggers the second callback and outputs "B"
|
||||
$nextPromise->resolve('B');
|
||||
```
|
||||
|
||||
## Promise rejection
|
||||
|
||||
When a promise is rejected, the `$onRejected` callbacks are invoked with the
|
||||
rejection reason.
|
||||
|
||||
```php
|
||||
use GuzzleHttp\Promise\Promise;
|
||||
|
||||
$promise = new Promise();
|
||||
$promise->then(null, function ($reason) {
|
||||
echo $reason;
|
||||
});
|
||||
|
||||
$promise->reject('Error!');
|
||||
// Outputs "Error!"
|
||||
```
|
||||
|
||||
## Rejection forwarding
|
||||
|
||||
If an exception is thrown in an `$onRejected` callback, subsequent
|
||||
`$onRejected` callbacks are invoked with the thrown exception as the reason.
|
||||
|
||||
```php
|
||||
use GuzzleHttp\Promise\Promise;
|
||||
|
||||
$promise = new Promise();
|
||||
$promise->then(null, function ($reason) {
|
||||
throw new \Exception($reason);
|
||||
})->then(null, function ($reason) {
|
||||
assert($reason->getMessage() === 'Error!');
|
||||
});
|
||||
|
||||
$promise->reject('Error!');
|
||||
```
|
||||
|
||||
You can also forward a rejection down the promise chain by returning a
|
||||
`GuzzleHttp\Promise\RejectedPromise` in either an `$onFulfilled` or
|
||||
`$onRejected` callback.
|
||||
|
||||
```php
|
||||
use GuzzleHttp\Promise\Promise;
|
||||
use GuzzleHttp\Promise\RejectedPromise;
|
||||
|
||||
$promise = new Promise();
|
||||
$promise->then(null, function ($reason) {
|
||||
return new RejectedPromise($reason);
|
||||
})->then(null, function ($reason) {
|
||||
assert($reason === 'Error!');
|
||||
});
|
||||
|
||||
$promise->reject('Error!');
|
||||
```
|
||||
|
||||
If an exception is not thrown in a `$onRejected` callback and the callback
|
||||
does not return a rejected promise, downstream `$onFulfilled` callbacks are
|
||||
invoked using the value returned from the `$onRejected` callback.
|
||||
|
||||
```php
|
||||
use GuzzleHttp\Promise\Promise;
|
||||
use GuzzleHttp\Promise\RejectedPromise;
|
||||
|
||||
$promise = new Promise();
|
||||
$promise
|
||||
->then(null, function ($reason) {
|
||||
return "It's ok";
|
||||
})
|
||||
->then(function ($value) {
|
||||
assert($value === "It's ok");
|
||||
});
|
||||
|
||||
$promise->reject('Error!');
|
||||
```
|
||||
|
||||
# Synchronous wait
|
||||
|
||||
You can synchronously force promises to complete using a promise's `wait`
|
||||
method. When creating a promise, you can provide a wait function that is used
|
||||
to synchronously force a promise to complete. When a wait function is invoked
|
||||
it is expected to deliver a value to the promise or reject the promise. If the
|
||||
wait function does not deliver a value, then an exception is thrown. The wait
|
||||
function provided to a promise constructor is invoked when the `wait` function
|
||||
of the promise is called.
|
||||
|
||||
```php
|
||||
$promise = new Promise(function () use (&$promise) {
|
||||
$promise->deliver('foo');
|
||||
});
|
||||
|
||||
// Calling wait will return the value of the promise.
|
||||
echo $promise->wait(); // outputs "foo"
|
||||
```
|
||||
|
||||
If an exception is encountered while invoking the wait function of a promise,
|
||||
the promise is rejected with the exception and the exception is thrown.
|
||||
|
||||
```php
|
||||
$promise = new Promise(function () use (&$promise) {
|
||||
throw new \Exception('foo');
|
||||
});
|
||||
|
||||
$promise->wait(); // throws the exception.
|
||||
```
|
||||
|
||||
Calling `wait` on a promise that has been fulfilled will not trigger the wait
|
||||
function. It will simply return the previously delivered value.
|
||||
|
||||
```php
|
||||
$promise = new Promise(function () { die('this is not called!'); });
|
||||
$promise->deliver('foo');
|
||||
echo $promise->wait(); // outputs "foo"
|
||||
```
|
||||
|
||||
Calling `wait` on a promise that has been rejected will throw an exception. If
|
||||
the rejection reason is an instance of `\Exception` the reason is thrown.
|
||||
Otherwise, a `GuzzleHttp\Promise\RejectionException` is thrown and the reason
|
||||
can be obtained by calling the `getReason` method of the exception.
|
||||
|
||||
```php
|
||||
$promise = new Promise();
|
||||
$promise->reject('foo');
|
||||
$promise->wait();
|
||||
```
|
||||
|
||||
> PHP Fatal error: Uncaught exception 'GuzzleHttp\Promise\RejectionException' with message 'The promise was rejected with value: foo'
|
||||
|
||||
|
||||
## Unwrapping a promise
|
||||
|
||||
When synchronously waiting on a promise, you are joining the state of the
|
||||
promise into the current state of execution (i.e., return the value of the
|
||||
promise if it was fulfilled or throw an exception if it was rejected). This is
|
||||
called "unwrapping" the promise. Waiting on a promise will by default unwrap
|
||||
the promise state.
|
||||
|
||||
You can force a promise to resolve and *not* unwrap the state of the promise
|
||||
by passing `false` to the first argument of the `wait` function:
|
||||
|
||||
```php
|
||||
$promise = new Promise();
|
||||
$promise->reject('foo');
|
||||
// This will not throw an exception. It simply ensures the promise has
|
||||
// been resolved.
|
||||
$promise->wait(false);
|
||||
```
|
||||
|
||||
When unwrapping a promise, the delivered value of the promise will be waited
|
||||
upon until the unwrapped value is not a promise. This means that if you resolve
|
||||
promise A with a promise B and unwrap promise A, the value returned by the
|
||||
wait function will be the value delivered to promise B.
|
||||
|
||||
**Note**: when you do not unwrap the promise, no value is returned.
|
||||
|
||||
|
||||
# Cancellation
|
||||
|
||||
You can cancel a promise that has not yet been fulfilled using the `cancel()`
|
||||
method of a promise. When creating a promise you can provide an optional
|
||||
cancel function that when invoked cancels the action of computing a resolution
|
||||
of the promise.
|
||||
|
||||
|
||||
# API
|
||||
|
||||
|
||||
## Promise
|
||||
|
||||
When creating a promise object, you can provide an optional `$waitFn` and
|
||||
`$cancelFn`. `$waitFn` is a function that is invoked with no arguments and is
|
||||
expected to resolve the promise. `$cancelFn` is a function with no arguments
|
||||
that is expected to cancel the computation of a promise. It is invoked when the
|
||||
`cancel()` method of a promise is called.
|
||||
|
||||
```php
|
||||
use GuzzleHttp\Promise\Promise;
|
||||
|
||||
$promise = new Promise(
|
||||
function () use (&$promise) {
|
||||
$promise->resolve('waited');
|
||||
},
|
||||
function () {
|
||||
// do something that will cancel the promise computation (e.g., close
|
||||
// a socket, cancel a database query, etc...)
|
||||
}
|
||||
);
|
||||
|
||||
assert('waited' === $promise->wait());
|
||||
```
|
||||
|
||||
A promise has the following methods:
|
||||
|
||||
- `then(callable $onFulfilled, callable $onRejected) : PromiseInterface`
|
||||
|
||||
Creates a new promise that is fulfilled or rejected when the promise is
|
||||
resolved.
|
||||
|
||||
- `wait($unwrap = true) : mixed`
|
||||
|
||||
Synchronously waits on the promise to complete.
|
||||
|
||||
`$unwrap` controls whether or not the value of the promise is returned for a
|
||||
fulfilled promise or if an exception is thrown if the promise is rejected.
|
||||
This is set to `true` by default.
|
||||
|
||||
- `cancel()`
|
||||
|
||||
Attempts to cancel the promise if possible. The promise being cancelled and
|
||||
the parent most ancestor that has not yet been resolved will also be
|
||||
cancelled. Any promises waiting on the cancelled promise to resolve will also
|
||||
be cancelled.
|
||||
|
||||
- `getState() : string`
|
||||
|
||||
Returns the state of the promise. One of `pending`, `fulfilled`, or
|
||||
`rejected`.
|
||||
|
||||
- `resolve($value)`
|
||||
|
||||
Fulfills the promise with the given `$value`.
|
||||
|
||||
- `reject($reason)`
|
||||
|
||||
Rejects the promise with the given `$reason`.
|
||||
|
||||
|
||||
## FulfilledPromise
|
||||
|
||||
A fulfilled promise can be created to represent a promise that has been
|
||||
fulfilled.
|
||||
|
||||
```php
|
||||
use GuzzleHttp\Promise\FulfilledPromise;
|
||||
|
||||
$promise = new FulfilledPromise('value');
|
||||
|
||||
// Fulfilled callbacks are immediately invoked.
|
||||
$promise->then(function ($value) {
|
||||
echo $value;
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
## RejectedPromise
|
||||
|
||||
A rejected promise can be created to represent a promise that has been
|
||||
rejected.
|
||||
|
||||
```php
|
||||
use GuzzleHttp\Promise\RejectedPromise;
|
||||
|
||||
$promise = new RejectedPromise('Error');
|
||||
|
||||
// Rejected callbacks are immediately invoked.
|
||||
$promise->then(null, function ($reason) {
|
||||
echo $reason;
|
||||
});
|
||||
```
|
||||
|
||||
|
||||
# Promise interop
|
||||
|
||||
This library works with foreign promises that have a `then` method. This means
|
||||
you can use Guzzle promises with [React promises](https://github.com/reactphp/promise)
|
||||
for example. When a foreign promise is returned inside of a then method
|
||||
callback, promise resolution will occur recursively.
|
||||
|
||||
```php
|
||||
// Create a React promise
|
||||
$deferred = new React\Promise\Deferred();
|
||||
$reactPromise = $deferred->promise();
|
||||
|
||||
// Create a Guzzle promise that is fulfilled with a React promise.
|
||||
$guzzlePromise = new \GuzzleHttp\Promise\Promise();
|
||||
$guzzlePromise->then(function ($value) use ($reactPromise) {
|
||||
// Do something something with the value...
|
||||
// Return the React promise
|
||||
return $reactPromise;
|
||||
});
|
||||
```
|
||||
|
||||
Please note that wait and cancel chaining is no longer possible when forwarding
|
||||
a foreign promise. You will need to wrap a third-party promise with a Guzzle
|
||||
promise in order to utilize wait and cancel functions with foreign promises.
|
||||
|
||||
|
||||
## Event Loop Integration
|
||||
|
||||
In order to keep the stack size constant, Guzzle promises are resolved
|
||||
asynchronously using a task queue. When waiting on promises synchronously, the
|
||||
task queue will be automatically run to ensure that the blocking promise and
|
||||
any forwarded promises are resolved. When using promises asynchronously in an
|
||||
event loop, you will need to run the task queue on each tick of the loop. If
|
||||
you do not run the task queue, then promises will not be resolved.
|
||||
|
||||
You can run the task queue using the `run()` method of the global task queue
|
||||
instance.
|
||||
|
||||
```php
|
||||
// Get the global task queue
|
||||
$queue = \GuzzleHttp\Promise\queue();
|
||||
$queue->run();
|
||||
```
|
||||
|
||||
For example, you could use Guzzle promises with React using a periodic timer:
|
||||
|
||||
```php
|
||||
$loop = React\EventLoop\Factory::create();
|
||||
$loop->addPeriodicTimer(0, [$queue, 'run']);
|
||||
```
|
||||
|
||||
*TODO*: Perhaps adding a `futureTick()` on each tick would be faster?
|
||||
|
||||
|
||||
# Implementation notes
|
||||
|
||||
|
||||
## Promise resolution and chaining is handled iteratively
|
||||
|
||||
By shuffling pending handlers from one owner to another, promises are
|
||||
resolved iteratively, allowing for "infinite" then chaining.
|
||||
|
||||
```php
|
||||
<?php
|
||||
require 'vendor/autoload.php';
|
||||
|
||||
use GuzzleHttp\Promise\Promise;
|
||||
|
||||
$parent = new Promise();
|
||||
$p = $parent;
|
||||
|
||||
for ($i = 0; $i < 1000; $i++) {
|
||||
$p = $p->then(function ($v) {
|
||||
// The stack size remains constant (a good thing)
|
||||
echo xdebug_get_stack_depth() . ', ';
|
||||
return $v + 1;
|
||||
});
|
||||
}
|
||||
|
||||
$parent->resolve(0);
|
||||
var_dump($p->wait()); // int(1000)
|
||||
|
||||
```
|
||||
|
||||
When a promise is fulfilled or rejected with a non-promise value, the promise
|
||||
then takes ownership of the handlers of each child promise and delivers values
|
||||
down the chain without using recursion.
|
||||
|
||||
When a promise is resolved with another promise, the original promise transfers
|
||||
all of its pending handlers to the new promise. When the new promise is
|
||||
eventually resolved, all of the pending handlers are delivered the forwarded
|
||||
value.
|
||||
|
||||
|
||||
## A promise is the deferred.
|
||||
|
||||
Some promise libraries implement promises using a deferred object to represent
|
||||
a computation and a promise object to represent the delivery of the result of
|
||||
the computation. This is a nice separation of computation and delivery because
|
||||
consumers of the promise cannot modify the value that will be eventually
|
||||
delivered.
|
||||
|
||||
One side effect of being able to implement promise resolution and chaining
|
||||
iteratively is that you need to be able for one promise to reach into the state
|
||||
of another promise to shuffle around ownership of handlers. In order to achieve
|
||||
this without making the handlers of a promise publicly mutable, a promise is
|
||||
also the deferred value, allowing promises of the same parent class to reach
|
||||
into and modify the private properties of promises of the same type. While this
|
||||
does allow consumers of the value to modify the resolution or rejection of the
|
||||
deferred, it is a small price to pay for keeping the stack size constant.
|
||||
|
||||
```php
|
||||
$promise = new Promise();
|
||||
$promise->then(function ($value) { echo $value; });
|
||||
// The promise is the deferred value, so you can deliver a value to it.
|
||||
$promise->deliver('foo');
|
||||
// prints "foo"
|
||||
```
|
31
server/vendor/guzzlehttp/promises/composer.json
vendored
Normal file
31
server/vendor/guzzlehttp/promises/composer.json
vendored
Normal file
|
@ -0,0 +1,31 @@
|
|||
{
|
||||
"name": "guzzlehttp/promises",
|
||||
"type": "library",
|
||||
"description": "Guzzle promises library",
|
||||
"keywords": ["promise"],
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Michael Dowling",
|
||||
"email": "mtdowling@gmail.com",
|
||||
"homepage": "https://github.com/mtdowling"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=5.5.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~4.0"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"GuzzleHttp\\Promise\\": "src/"
|
||||
},
|
||||
"files": ["src/functions_include.php"]
|
||||
},
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.0-dev"
|
||||
}
|
||||
}
|
||||
}
|
17
server/vendor/guzzlehttp/promises/phpunit.xml.dist
vendored
Normal file
17
server/vendor/guzzlehttp/promises/phpunit.xml.dist
vendored
Normal file
|
@ -0,0 +1,17 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phpunit bootstrap="./tests/bootstrap.php"
|
||||
colors="true">
|
||||
<testsuites>
|
||||
<testsuite>
|
||||
<directory>tests</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
<filter>
|
||||
<whitelist>
|
||||
<directory suffix=".php">src</directory>
|
||||
<exclude>
|
||||
<directory suffix="Interface.php">src/</directory>
|
||||
</exclude>
|
||||
</whitelist>
|
||||
</filter>
|
||||
</phpunit>
|
16
server/vendor/guzzlehttp/promises/src/AggregateException.php
vendored
Normal file
16
server/vendor/guzzlehttp/promises/src/AggregateException.php
vendored
Normal file
|
@ -0,0 +1,16 @@
|
|||
<?php
|
||||
namespace GuzzleHttp\Promise;
|
||||
|
||||
/**
|
||||
* Exception thrown when too many errors occur in the some() or any() methods.
|
||||
*/
|
||||
class AggregateException extends RejectionException
|
||||
{
|
||||
public function __construct($msg, array $reasons)
|
||||
{
|
||||
parent::__construct(
|
||||
$reasons,
|
||||
sprintf('%s; %d rejected promises', $msg, count($reasons))
|
||||
);
|
||||
}
|
||||
}
|
9
server/vendor/guzzlehttp/promises/src/CancellationException.php
vendored
Normal file
9
server/vendor/guzzlehttp/promises/src/CancellationException.php
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
<?php
|
||||
namespace GuzzleHttp\Promise;
|
||||
|
||||
/**
|
||||
* Exception that is set as the reason for a promise that has been cancelled.
|
||||
*/
|
||||
class CancellationException extends RejectionException
|
||||
{
|
||||
}
|
207
server/vendor/guzzlehttp/promises/src/EachPromise.php
vendored
Normal file
207
server/vendor/guzzlehttp/promises/src/EachPromise.php
vendored
Normal file
|
@ -0,0 +1,207 @@
|
|||
<?php
|
||||
namespace GuzzleHttp\Promise;
|
||||
|
||||
/**
|
||||
* Represents a promise that iterates over many promises and invokes
|
||||
* side-effect functions in the process.
|
||||
*/
|
||||
class EachPromise implements PromisorInterface
|
||||
{
|
||||
private $pending = [];
|
||||
|
||||
/** @var \Iterator */
|
||||
private $iterable;
|
||||
|
||||
/** @var callable|int */
|
||||
private $concurrency;
|
||||
|
||||
/** @var callable */
|
||||
private $onFulfilled;
|
||||
|
||||
/** @var callable */
|
||||
private $onRejected;
|
||||
|
||||
/** @var Promise */
|
||||
private $aggregate;
|
||||
|
||||
/**
|
||||
* Configuration hash can include the following key value pairs:
|
||||
*
|
||||
* - fulfilled: (callable) Invoked when a promise fulfills. The function
|
||||
* is invoked with three arguments: the fulfillment value, the index
|
||||
* position from the iterable list of the promise, and the aggregate
|
||||
* promise that manages all of the promises. The aggregate promise may
|
||||
* be resolved from within the callback to short-circuit the promise.
|
||||
* - rejected: (callable) Invoked when a promise is rejected. The
|
||||
* function is invoked with three arguments: the rejection reason, the
|
||||
* index position from the iterable list of the promise, and the
|
||||
* aggregate promise that manages all of the promises. The aggregate
|
||||
* promise may be resolved from within the callback to short-circuit
|
||||
* the promise.
|
||||
* - concurrency: (integer) Pass this configuration option to limit the
|
||||
* allowed number of outstanding concurrently executing promises,
|
||||
* creating a capped pool of promises. There is no limit by default.
|
||||
*
|
||||
* @param mixed $iterable Promises or values to iterate.
|
||||
* @param array $config Configuration options
|
||||
*/
|
||||
public function __construct($iterable, array $config = [])
|
||||
{
|
||||
$this->iterable = iter_for($iterable);
|
||||
|
||||
if (isset($config['concurrency'])) {
|
||||
$this->concurrency = $config['concurrency'];
|
||||
}
|
||||
|
||||
if (isset($config['fulfilled'])) {
|
||||
$this->onFulfilled = $config['fulfilled'];
|
||||
}
|
||||
|
||||
if (isset($config['rejected'])) {
|
||||
$this->onRejected = $config['rejected'];
|
||||
}
|
||||
}
|
||||
|
||||
public function promise()
|
||||
{
|
||||
if ($this->aggregate) {
|
||||
return $this->aggregate;
|
||||
}
|
||||
|
||||
try {
|
||||
$this->createPromise();
|
||||
$this->iterable->rewind();
|
||||
$this->refillPending();
|
||||
} catch (\Exception $e) {
|
||||
$this->aggregate->reject($e);
|
||||
}
|
||||
|
||||
return $this->aggregate;
|
||||
}
|
||||
|
||||
private function createPromise()
|
||||
{
|
||||
$this->aggregate = new Promise(function () {
|
||||
reset($this->pending);
|
||||
if (empty($this->pending) && !$this->iterable->valid()) {
|
||||
$this->aggregate->resolve(null);
|
||||
return;
|
||||
}
|
||||
|
||||
// Consume a potentially fluctuating list of promises while
|
||||
// ensuring that indexes are maintained (precluding array_shift).
|
||||
while ($promise = current($this->pending)) {
|
||||
next($this->pending);
|
||||
$promise->wait();
|
||||
if ($this->aggregate->getState() !== PromiseInterface::PENDING) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Clear the references when the promise is resolved.
|
||||
$clearFn = function () {
|
||||
$this->iterable = $this->concurrency = $this->pending = null;
|
||||
$this->onFulfilled = $this->onRejected = null;
|
||||
};
|
||||
|
||||
$this->aggregate->then($clearFn, $clearFn);
|
||||
}
|
||||
|
||||
private function refillPending()
|
||||
{
|
||||
if (!$this->concurrency) {
|
||||
// Add all pending promises.
|
||||
while ($this->addPending() && $this->advanceIterator());
|
||||
return;
|
||||
}
|
||||
|
||||
// Add only up to N pending promises.
|
||||
$concurrency = is_callable($this->concurrency)
|
||||
? call_user_func($this->concurrency, count($this->pending))
|
||||
: $this->concurrency;
|
||||
$concurrency = max($concurrency - count($this->pending), 0);
|
||||
// Concurrency may be set to 0 to disallow new promises.
|
||||
if (!$concurrency) {
|
||||
return;
|
||||
}
|
||||
// Add the first pending promise.
|
||||
$this->addPending();
|
||||
// Note this is special handling for concurrency=1 so that we do
|
||||
// not advance the iterator after adding the first promise. This
|
||||
// helps work around issues with generators that might not have the
|
||||
// next value to yield until promise callbacks are called.
|
||||
while (--$concurrency
|
||||
&& $this->advanceIterator()
|
||||
&& $this->addPending());
|
||||
}
|
||||
|
||||
private function addPending()
|
||||
{
|
||||
if (!$this->iterable || !$this->iterable->valid()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$promise = promise_for($this->iterable->current());
|
||||
$idx = $this->iterable->key();
|
||||
|
||||
$this->pending[$idx] = $promise->then(
|
||||
function ($value) use ($idx) {
|
||||
if ($this->onFulfilled) {
|
||||
call_user_func(
|
||||
$this->onFulfilled, $value, $idx, $this->aggregate
|
||||
);
|
||||
}
|
||||
$this->step($idx);
|
||||
},
|
||||
function ($reason) use ($idx) {
|
||||
if ($this->onRejected) {
|
||||
call_user_func(
|
||||
$this->onRejected, $reason, $idx, $this->aggregate
|
||||
);
|
||||
}
|
||||
$this->step($idx);
|
||||
}
|
||||
);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function advanceIterator()
|
||||
{
|
||||
try {
|
||||
$this->iterable->next();
|
||||
return true;
|
||||
} catch (\Exception $e) {
|
||||
$this->aggregate->reject($e);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private function step($idx)
|
||||
{
|
||||
// If the promise was already resolved, then ignore this step.
|
||||
if ($this->aggregate->getState() !== PromiseInterface::PENDING) {
|
||||
return;
|
||||
}
|
||||
|
||||
unset($this->pending[$idx]);
|
||||
$this->advanceIterator();
|
||||
|
||||
if (!$this->checkIfFinished()) {
|
||||
// Add more pending promises if possible.
|
||||
$this->refillPending();
|
||||
}
|
||||
}
|
||||
|
||||
private function checkIfFinished()
|
||||
{
|
||||
if (!$this->pending && !$this->iterable->valid()) {
|
||||
// Resolve the promise if there's nothing left to do.
|
||||
$this->aggregate->resolve(null);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
80
server/vendor/guzzlehttp/promises/src/FulfilledPromise.php
vendored
Normal file
80
server/vendor/guzzlehttp/promises/src/FulfilledPromise.php
vendored
Normal file
|
@ -0,0 +1,80 @@
|
|||
<?php
|
||||
namespace GuzzleHttp\Promise;
|
||||
|
||||
/**
|
||||
* A promise that has been fulfilled.
|
||||
*
|
||||
* Thenning off of this promise will invoke the onFulfilled callback
|
||||
* immediately and ignore other callbacks.
|
||||
*/
|
||||
class FulfilledPromise implements PromiseInterface
|
||||
{
|
||||
private $value;
|
||||
|
||||
public function __construct($value)
|
||||
{
|
||||
if (method_exists($value, 'then')) {
|
||||
throw new \InvalidArgumentException(
|
||||
'You cannot create a FulfilledPromise with a promise.');
|
||||
}
|
||||
|
||||
$this->value = $value;
|
||||
}
|
||||
|
||||
public function then(
|
||||
callable $onFulfilled = null,
|
||||
callable $onRejected = null
|
||||
) {
|
||||
// Return itself if there is no onFulfilled function.
|
||||
if (!$onFulfilled) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
$queue = queue();
|
||||
$p = new Promise([$queue, 'run']);
|
||||
$value = $this->value;
|
||||
$queue->add(static function () use ($p, $value, $onFulfilled) {
|
||||
if ($p->getState() === self::PENDING) {
|
||||
try {
|
||||
$p->resolve($onFulfilled($value));
|
||||
} catch (\Exception $e) {
|
||||
$p->reject($e);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return $p;
|
||||
}
|
||||
|
||||
public function otherwise(callable $onRejected)
|
||||
{
|
||||
return $this->then(null, $onRejected);
|
||||
}
|
||||
|
||||
public function wait($unwrap = true, $defaultDelivery = null)
|
||||
{
|
||||
return $unwrap ? $this->value : null;
|
||||
}
|
||||
|
||||
public function getState()
|
||||
{
|
||||
return self::FULFILLED;
|
||||
}
|
||||
|
||||
public function resolve($value)
|
||||
{
|
||||
if ($value !== $this->value) {
|
||||
throw new \LogicException("Cannot resolve a fulfilled promise");
|
||||
}
|
||||
}
|
||||
|
||||
public function reject($reason)
|
||||
{
|
||||
throw new \LogicException("Cannot reject a fulfilled promise");
|
||||
}
|
||||
|
||||
public function cancel()
|
||||
{
|
||||
// pass
|
||||
}
|
||||
}
|
268
server/vendor/guzzlehttp/promises/src/Promise.php
vendored
Normal file
268
server/vendor/guzzlehttp/promises/src/Promise.php
vendored
Normal file
|
@ -0,0 +1,268 @@
|
|||
<?php
|
||||
namespace GuzzleHttp\Promise;
|
||||
|
||||
/**
|
||||
* Promises/A+ implementation that avoids recursion when possible.
|
||||
*
|
||||
* @link https://promisesaplus.com/
|
||||
*/
|
||||
class Promise implements PromiseInterface
|
||||
{
|
||||
private $state = self::PENDING;
|
||||
private $result;
|
||||
private $cancelFn;
|
||||
private $waitFn;
|
||||
private $waitList;
|
||||
private $handlers = [];
|
||||
|
||||
/**
|
||||
* @param callable $waitFn Fn that when invoked resolves the promise.
|
||||
* @param callable $cancelFn Fn that when invoked cancels the promise.
|
||||
*/
|
||||
public function __construct(
|
||||
callable $waitFn = null,
|
||||
callable $cancelFn = null
|
||||
) {
|
||||
$this->waitFn = $waitFn;
|
||||
$this->cancelFn = $cancelFn;
|
||||
}
|
||||
|
||||
public function then(
|
||||
callable $onFulfilled = null,
|
||||
callable $onRejected = null
|
||||
) {
|
||||
if ($this->state === self::PENDING) {
|
||||
$p = new Promise(null, [$this, 'cancel']);
|
||||
$this->handlers[] = [$p, $onFulfilled, $onRejected];
|
||||
$p->waitList = $this->waitList;
|
||||
$p->waitList[] = $this;
|
||||
return $p;
|
||||
}
|
||||
|
||||
// Return a fulfilled promise and immediately invoke any callbacks.
|
||||
if ($this->state === self::FULFILLED) {
|
||||
return $onFulfilled
|
||||
? promise_for($this->result)->then($onFulfilled)
|
||||
: promise_for($this->result);
|
||||
}
|
||||
|
||||
// It's either cancelled or rejected, so return a rejected promise
|
||||
// and immediately invoke any callbacks.
|
||||
$rejection = rejection_for($this->result);
|
||||
return $onRejected ? $rejection->then(null, $onRejected) : $rejection;
|
||||
}
|
||||
|
||||
public function otherwise(callable $onRejected)
|
||||
{
|
||||
return $this->then(null, $onRejected);
|
||||
}
|
||||
|
||||
public function wait($unwrap = true)
|
||||
{
|
||||
$this->waitIfPending();
|
||||
|
||||
if (!$unwrap) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($this->result instanceof PromiseInterface) {
|
||||
return $this->result->wait($unwrap);
|
||||
} elseif ($this->state === self::FULFILLED) {
|
||||
return $this->result;
|
||||
} else {
|
||||
// It's rejected so "unwrap" and throw an exception.
|
||||
throw exception_for($this->result);
|
||||
}
|
||||
}
|
||||
|
||||
public function getState()
|
||||
{
|
||||
return $this->state;
|
||||
}
|
||||
|
||||
public function cancel()
|
||||
{
|
||||
if ($this->state !== self::PENDING) {
|
||||
return;
|
||||
}
|
||||
|
||||
$this->waitFn = $this->waitList = null;
|
||||
|
||||
if ($this->cancelFn) {
|
||||
$fn = $this->cancelFn;
|
||||
$this->cancelFn = null;
|
||||
try {
|
||||
$fn();
|
||||
} catch (\Exception $e) {
|
||||
$this->reject($e);
|
||||
}
|
||||
}
|
||||
|
||||
// Reject the promise only if it wasn't rejected in a then callback.
|
||||
if ($this->state === self::PENDING) {
|
||||
$this->reject(new CancellationException('Promise has been cancelled'));
|
||||
}
|
||||
}
|
||||
|
||||
public function resolve($value)
|
||||
{
|
||||
$this->settle(self::FULFILLED, $value);
|
||||
}
|
||||
|
||||
public function reject($reason)
|
||||
{
|
||||
$this->settle(self::REJECTED, $reason);
|
||||
}
|
||||
|
||||
private function settle($state, $value)
|
||||
{
|
||||
if ($this->state !== self::PENDING) {
|
||||
// Ignore calls with the same resolution.
|
||||
if ($state === $this->state && $value === $this->result) {
|
||||
return;
|
||||
}
|
||||
throw $this->state === $state
|
||||
? new \LogicException("The promise is already {$state}.")
|
||||
: new \LogicException("Cannot change a {$this->state} promise to {$state}");
|
||||
}
|
||||
|
||||
if ($value === $this) {
|
||||
throw new \LogicException('Cannot fulfill or reject a promise with itself');
|
||||
}
|
||||
|
||||
// Clear out the state of the promise but stash the handlers.
|
||||
$this->state = $state;
|
||||
$this->result = $value;
|
||||
$handlers = $this->handlers;
|
||||
$this->handlers = null;
|
||||
$this->waitList = $this->waitFn = null;
|
||||
$this->cancelFn = null;
|
||||
|
||||
if (!$handlers) {
|
||||
return;
|
||||
}
|
||||
|
||||
// If the value was not a settled promise or a thenable, then resolve
|
||||
// it in the task queue using the correct ID.
|
||||
if (!method_exists($value, 'then')) {
|
||||
$id = $state === self::FULFILLED ? 1 : 2;
|
||||
// It's a success, so resolve the handlers in the queue.
|
||||
queue()->add(static function () use ($id, $value, $handlers) {
|
||||
foreach ($handlers as $handler) {
|
||||
self::callHandler($id, $value, $handler);
|
||||
}
|
||||
});
|
||||
} elseif ($value instanceof Promise
|
||||
&& $value->getState() === self::PENDING
|
||||
) {
|
||||
// We can just merge our handlers onto the next promise.
|
||||
$value->handlers = array_merge($value->handlers, $handlers);
|
||||
} else {
|
||||
// Resolve the handlers when the forwarded promise is resolved.
|
||||
$value->then(
|
||||
static function ($value) use ($handlers) {
|
||||
foreach ($handlers as $handler) {
|
||||
self::callHandler(1, $value, $handler);
|
||||
}
|
||||
},
|
||||
static function ($reason) use ($handlers) {
|
||||
foreach ($handlers as $handler) {
|
||||
self::callHandler(2, $reason, $handler);
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Call a stack of handlers using a specific callback index and value.
|
||||
*
|
||||
* @param int $index 1 (resolve) or 2 (reject).
|
||||
* @param mixed $value Value to pass to the callback.
|
||||
* @param array $handler Array of handler data (promise and callbacks).
|
||||
*
|
||||
* @return array Returns the next group to resolve.
|
||||
*/
|
||||
private static function callHandler($index, $value, array $handler)
|
||||
{
|
||||
/** @var PromiseInterface $promise */
|
||||
$promise = $handler[0];
|
||||
|
||||
// The promise may have been cancelled or resolved before placing
|
||||
// this thunk in the queue.
|
||||
if ($promise->getState() !== self::PENDING) {
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
if (isset($handler[$index])) {
|
||||
$promise->resolve($handler[$index]($value));
|
||||
} elseif ($index === 1) {
|
||||
// Forward resolution values as-is.
|
||||
$promise->resolve($value);
|
||||
} else {
|
||||
// Forward rejections down the chain.
|
||||
$promise->reject($value);
|
||||
}
|
||||
} catch (\Exception $reason) {
|
||||
$promise->reject($reason);
|
||||
}
|
||||
}
|
||||
|
||||
private function waitIfPending()
|
||||
{
|
||||
if ($this->state !== self::PENDING) {
|
||||
return;
|
||||
} elseif ($this->waitFn) {
|
||||
$this->invokeWaitFn();
|
||||
} elseif ($this->waitList) {
|
||||
$this->invokeWaitList();
|
||||
} else {
|
||||
// If there's not wait function, then reject the promise.
|
||||
$this->reject('Cannot wait on a promise that has '
|
||||
. 'no internal wait function. You must provide a wait '
|
||||
. 'function when constructing the promise to be able to '
|
||||
. 'wait on a promise.');
|
||||
}
|
||||
|
||||
queue()->run();
|
||||
|
||||
if ($this->state === self::PENDING) {
|
||||
$this->reject('Invoking the wait callback did not resolve the promise');
|
||||
}
|
||||
}
|
||||
|
||||
private function invokeWaitFn()
|
||||
{
|
||||
try {
|
||||
$wfn = $this->waitFn;
|
||||
$this->waitFn = null;
|
||||
$wfn(true);
|
||||
} catch (\Exception $reason) {
|
||||
if ($this->state === self::PENDING) {
|
||||
// The promise has not been resolved yet, so reject the promise
|
||||
// with the exception.
|
||||
$this->reject($reason);
|
||||
} else {
|
||||
// The promise was already resolved, so there's a problem in
|
||||
// the application.
|
||||
throw $reason;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function invokeWaitList()
|
||||
{
|
||||
$waitList = $this->waitList;
|
||||
$this->waitList = null;
|
||||
|
||||
foreach ($waitList as $result) {
|
||||
descend:
|
||||
$result->waitIfPending();
|
||||
if ($result->result instanceof Promise) {
|
||||
$result = $result->result;
|
||||
goto descend;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
93
server/vendor/guzzlehttp/promises/src/PromiseInterface.php
vendored
Normal file
93
server/vendor/guzzlehttp/promises/src/PromiseInterface.php
vendored
Normal file
|
@ -0,0 +1,93 @@
|
|||
<?php
|
||||
namespace GuzzleHttp\Promise;
|
||||
|
||||
/**
|
||||
* A promise represents the eventual result of an asynchronous operation.
|
||||
*
|
||||
* The primary way of interacting with a promise is through its then method,
|
||||
* which registers callbacks to receive either a promise’s eventual value or
|
||||
* the reason why the promise cannot be fulfilled.
|
||||
*
|
||||
* @link https://promisesaplus.com/
|
||||
*/
|
||||
interface PromiseInterface
|
||||
{
|
||||
const PENDING = 'pending';
|
||||
const FULFILLED = 'fulfilled';
|
||||
const REJECTED = 'rejected';
|
||||
|
||||
/**
|
||||
* Appends fulfillment and rejection handlers to the promise, and returns
|
||||
* a new promise resolving to the return value of the called handler.
|
||||
*
|
||||
* @param callable $onFulfilled Invoked when the promise fulfills.
|
||||
* @param callable $onRejected Invoked when the promise is rejected.
|
||||
*
|
||||
* @return PromiseInterface
|
||||
*/
|
||||
public function then(
|
||||
callable $onFulfilled = null,
|
||||
callable $onRejected = null
|
||||
);
|
||||
|
||||
/**
|
||||
* Appends a rejection handler callback to the promise, and returns a new
|
||||
* promise resolving to the return value of the callback if it is called,
|
||||
* or to its original fulfillment value if the promise is instead
|
||||
* fulfilled.
|
||||
*
|
||||
* @param callable $onRejected Invoked when the promise is rejected.
|
||||
*
|
||||
* @return PromiseInterface
|
||||
*/
|
||||
public function otherwise(callable $onRejected);
|
||||
|
||||
/**
|
||||
* Get the state of the promise ("pending", "rejected", or "fulfilled").
|
||||
*
|
||||
* The three states can be checked against the constants defined on
|
||||
* PromiseInterface: PENDING, FULFILLED, and REJECTED.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getState();
|
||||
|
||||
/**
|
||||
* Resolve the promise with the given value.
|
||||
*
|
||||
* @param mixed $value
|
||||
* @throws \RuntimeException if the promise is already resolved.
|
||||
*/
|
||||
public function resolve($value);
|
||||
|
||||
/**
|
||||
* Reject the promise with the given reason.
|
||||
*
|
||||
* @param mixed $reason
|
||||
* @throws \RuntimeException if the promise is already resolved.
|
||||
*/
|
||||
public function reject($reason);
|
||||
|
||||
/**
|
||||
* Cancels the promise if possible.
|
||||
*
|
||||
* @link https://github.com/promises-aplus/cancellation-spec/issues/7
|
||||
*/
|
||||
public function cancel();
|
||||
|
||||
/**
|
||||
* Waits until the promise completes if possible.
|
||||
*
|
||||
* Pass $unwrap as true to unwrap the result of the promise, either
|
||||
* returning the resolved value or throwing the rejected exception.
|
||||
*
|
||||
* If the promise cannot be waited on, then the promise will be rejected.
|
||||
*
|
||||
* @param bool $unwrap
|
||||
*
|
||||
* @return mixed
|
||||
* @throws \LogicException if the promise has no wait function or if the
|
||||
* promise does not settle after waiting.
|
||||
*/
|
||||
public function wait($unwrap = true);
|
||||
}
|
15
server/vendor/guzzlehttp/promises/src/PromisorInterface.php
vendored
Normal file
15
server/vendor/guzzlehttp/promises/src/PromisorInterface.php
vendored
Normal file
|
@ -0,0 +1,15 @@
|
|||
<?php
|
||||
namespace GuzzleHttp\Promise;
|
||||
|
||||
/**
|
||||
* Interface used with classes that return a promise.
|
||||
*/
|
||||
interface PromisorInterface
|
||||
{
|
||||
/**
|
||||
* Returns a promise.
|
||||
*
|
||||
* @return PromiseInterface
|
||||
*/
|
||||
public function promise();
|
||||
}
|
84
server/vendor/guzzlehttp/promises/src/RejectedPromise.php
vendored
Normal file
84
server/vendor/guzzlehttp/promises/src/RejectedPromise.php
vendored
Normal file
|
@ -0,0 +1,84 @@
|
|||
<?php
|
||||
namespace GuzzleHttp\Promise;
|
||||
|
||||
/**
|
||||
* A promise that has been rejected.
|
||||
*
|
||||
* Thenning off of this promise will invoke the onRejected callback
|
||||
* immediately and ignore other callbacks.
|
||||
*/
|
||||
class RejectedPromise implements PromiseInterface
|
||||
{
|
||||
private $reason;
|
||||
|
||||
public function __construct($reason)
|
||||
{
|
||||
if (method_exists($reason, 'then')) {
|
||||
throw new \InvalidArgumentException(
|
||||
'You cannot create a RejectedPromise with a promise.');
|
||||
}
|
||||
|
||||
$this->reason = $reason;
|
||||
}
|
||||
|
||||
public function then(
|
||||
callable $onFulfilled = null,
|
||||
callable $onRejected = null
|
||||
) {
|
||||
// If there's no onRejected callback then just return self.
|
||||
if (!$onRejected) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
$queue = queue();
|
||||
$reason = $this->reason;
|
||||
$p = new Promise([$queue, 'run']);
|
||||
$queue->add(static function () use ($p, $reason, $onRejected) {
|
||||
if ($p->getState() === self::PENDING) {
|
||||
try {
|
||||
// Return a resolved promise if onRejected does not throw.
|
||||
$p->resolve($onRejected($reason));
|
||||
} catch (\Exception $e) {
|
||||
// onRejected threw, so return a rejected promise.
|
||||
$p->reject($e);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return $p;
|
||||
}
|
||||
|
||||
public function otherwise(callable $onRejected)
|
||||
{
|
||||
return $this->then(null, $onRejected);
|
||||
}
|
||||
|
||||
public function wait($unwrap = true, $defaultDelivery = null)
|
||||
{
|
||||
if ($unwrap) {
|
||||
throw exception_for($this->reason);
|
||||
}
|
||||
}
|
||||
|
||||
public function getState()
|
||||
{
|
||||
return self::REJECTED;
|
||||
}
|
||||
|
||||
public function resolve($value)
|
||||
{
|
||||
throw new \LogicException("Cannot resolve a rejected promise");
|
||||
}
|
||||
|
||||
public function reject($reason)
|
||||
{
|
||||
if ($reason !== $this->reason) {
|
||||
throw new \LogicException("Cannot reject a rejected promise");
|
||||
}
|
||||
}
|
||||
|
||||
public function cancel()
|
||||
{
|
||||
// pass
|
||||
}
|
||||
}
|
47
server/vendor/guzzlehttp/promises/src/RejectionException.php
vendored
Normal file
47
server/vendor/guzzlehttp/promises/src/RejectionException.php
vendored
Normal file
|
@ -0,0 +1,47 @@
|
|||
<?php
|
||||
namespace GuzzleHttp\Promise;
|
||||
|
||||
/**
|
||||
* A special exception that is thrown when waiting on a rejected promise.
|
||||
*
|
||||
* The reason value is available via the getReason() method.
|
||||
*/
|
||||
class RejectionException extends \RuntimeException
|
||||
{
|
||||
/** @var mixed Rejection reason. */
|
||||
private $reason;
|
||||
|
||||
/**
|
||||
* @param mixed $reason Rejection reason.
|
||||
* @param string $description Optional description
|
||||
*/
|
||||
public function __construct($reason, $description = null)
|
||||
{
|
||||
$this->reason = $reason;
|
||||
|
||||
$message = 'The promise was rejected';
|
||||
|
||||
if ($description) {
|
||||
$message .= ' with reason: ' . $description;
|
||||
} elseif (is_string($reason)
|
||||
|| (is_object($reason) && method_exists($reason, '__toString'))
|
||||
) {
|
||||
$message .= ' with reason: ' . $this->reason;
|
||||
} elseif ($reason instanceof \JsonSerializable) {
|
||||
$message .= ' with reason: '
|
||||
. json_encode($this->reason, JSON_PRETTY_PRINT);
|
||||
}
|
||||
|
||||
parent::__construct($message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the rejection reason.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getReason()
|
||||
{
|
||||
return $this->reason;
|
||||
}
|
||||
}
|
79
server/vendor/guzzlehttp/promises/src/TaskQueue.php
vendored
Normal file
79
server/vendor/guzzlehttp/promises/src/TaskQueue.php
vendored
Normal file
|
@ -0,0 +1,79 @@
|
|||
<?php
|
||||
namespace GuzzleHttp\Promise;
|
||||
|
||||
/**
|
||||
* A task queue that executes tasks in a FIFO order.
|
||||
*
|
||||
* This task queue class is used to settle promises asynchronously and
|
||||
* maintains a constant stack size. You can use the task queue asynchronously
|
||||
* by calling the `run()` function of the global task queue in an event loop.
|
||||
*
|
||||
* GuzzleHttp\Promise\queue()->run();
|
||||
*/
|
||||
class TaskQueue
|
||||
{
|
||||
private $enableShutdown = true;
|
||||
private $queue = [];
|
||||
|
||||
public function __construct($withShutdown = true)
|
||||
{
|
||||
if ($withShutdown) {
|
||||
register_shutdown_function(function () {
|
||||
if ($this->enableShutdown) {
|
||||
// Only run the tasks if an E_ERROR didn't occur.
|
||||
$err = error_get_last();
|
||||
if (!$err || ($err['type'] ^ E_ERROR)) {
|
||||
$this->run();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the queue is empty.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function isEmpty()
|
||||
{
|
||||
return !$this->queue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a task to the queue that will be executed the next time run is
|
||||
* called.
|
||||
*
|
||||
* @param callable $task
|
||||
*/
|
||||
public function add(callable $task)
|
||||
{
|
||||
$this->queue[] = $task;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute all of the pending task in the queue.
|
||||
*/
|
||||
public function run()
|
||||
{
|
||||
while ($task = array_shift($this->queue)) {
|
||||
$task();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The task queue will be run and exhausted by default when the process
|
||||
* exits IFF the exit is not the result of a PHP E_ERROR error.
|
||||
*
|
||||
* You can disable running the automatic shutdown of the queue by calling
|
||||
* this function. If you disable the task queue shutdown process, then you
|
||||
* MUST either run the task queue (as a result of running your event loop
|
||||
* or manually using the run() method) or wait on each outstanding promise.
|
||||
*
|
||||
* Note: This shutdown will occur before any destructors are triggered.
|
||||
*/
|
||||
public function disableShutdown()
|
||||
{
|
||||
$this->enableShutdown = false;
|
||||
}
|
||||
}
|
495
server/vendor/guzzlehttp/promises/src/functions.php
vendored
Normal file
495
server/vendor/guzzlehttp/promises/src/functions.php
vendored
Normal file
|
@ -0,0 +1,495 @@
|
|||
<?php
|
||||
namespace GuzzleHttp\Promise;
|
||||
|
||||
/**
|
||||
* Get the global task queue used for promise resolution.
|
||||
*
|
||||
* This task queue MUST be run in an event loop in order for promises to be
|
||||
* settled asynchronously. It will be automatically run when synchronously
|
||||
* waiting on a promise.
|
||||
*
|
||||
* <code>
|
||||
* while ($eventLoop->isRunning()) {
|
||||
* GuzzleHttp\Promise\queue()->run();
|
||||
* }
|
||||
* </code>
|
||||
*
|
||||
* @return TaskQueue
|
||||
*/
|
||||
function queue()
|
||||
{
|
||||
static $queue;
|
||||
|
||||
if (!$queue) {
|
||||
$queue = new TaskQueue();
|
||||
}
|
||||
|
||||
return $queue;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a function to run in the task queue when it is next `run()` and returns
|
||||
* a promise that is fulfilled or rejected with the result.
|
||||
*
|
||||
* @param callable $task Task function to run.
|
||||
*
|
||||
* @return PromiseInterface
|
||||
*/
|
||||
function task(callable $task)
|
||||
{
|
||||
$queue = queue();
|
||||
$promise = new Promise([$queue, 'run']);
|
||||
$queue->add(function () use ($task, $promise) {
|
||||
try {
|
||||
$promise->resolve($task());
|
||||
} catch (\Exception $e) {
|
||||
$promise->reject($e);
|
||||
}
|
||||
});
|
||||
|
||||
return $promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a promise for a value if the value is not a promise.
|
||||
*
|
||||
* @param mixed $value Promise or value.
|
||||
*
|
||||
* @return PromiseInterface
|
||||
*/
|
||||
function promise_for($value)
|
||||
{
|
||||
if ($value instanceof PromiseInterface) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
// Return a Guzzle promise that shadows the given promise.
|
||||
if (method_exists($value, 'then')) {
|
||||
$wfn = method_exists($value, 'wait') ? [$value, 'wait'] : null;
|
||||
$cfn = method_exists($value, 'cancel') ? [$value, 'cancel'] : null;
|
||||
$promise = new Promise($wfn, $cfn);
|
||||
$value->then([$promise, 'resolve'], [$promise, 'reject']);
|
||||
return $promise;
|
||||
}
|
||||
|
||||
return new FulfilledPromise($value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a rejected promise for a reason if the reason is not a promise. If
|
||||
* the provided reason is a promise, then it is returned as-is.
|
||||
*
|
||||
* @param mixed $reason Promise or reason.
|
||||
*
|
||||
* @return PromiseInterface
|
||||
*/
|
||||
function rejection_for($reason)
|
||||
{
|
||||
if ($reason instanceof PromiseInterface) {
|
||||
return $reason;
|
||||
}
|
||||
|
||||
return new RejectedPromise($reason);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an exception for a rejected promise value.
|
||||
*
|
||||
* @param mixed $reason
|
||||
*
|
||||
* @return \Exception
|
||||
*/
|
||||
function exception_for($reason)
|
||||
{
|
||||
return $reason instanceof \Exception
|
||||
? $reason
|
||||
: new RejectionException($reason);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an iterator for the given value.
|
||||
*
|
||||
* @param mixed $value
|
||||
*
|
||||
* @return \Iterator
|
||||
*/
|
||||
function iter_for($value)
|
||||
{
|
||||
if ($value instanceof \Iterator) {
|
||||
return $value;
|
||||
} elseif (is_array($value)) {
|
||||
return new \ArrayIterator($value);
|
||||
} else {
|
||||
return new \ArrayIterator([$value]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Synchronously waits on a promise to resolve and returns an inspection state
|
||||
* array.
|
||||
*
|
||||
* Returns a state associative array containing a "state" key mapping to a
|
||||
* valid promise state. If the state of the promise is "fulfilled", the array
|
||||
* will contain a "value" key mapping to the fulfilled value of the promise. If
|
||||
* the promise is rejected, the array will contain a "reason" key mapping to
|
||||
* the rejection reason of the promise.
|
||||
*
|
||||
* @param PromiseInterface $promise Promise or value.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function inspect(PromiseInterface $promise)
|
||||
{
|
||||
try {
|
||||
return [
|
||||
'state' => PromiseInterface::FULFILLED,
|
||||
'value' => $promise->wait()
|
||||
];
|
||||
} catch (RejectionException $e) {
|
||||
return ['state' => 'rejected', 'reason' => $e->getReason()];
|
||||
} catch (\Exception $e) {
|
||||
return ['state' => 'rejected', 'reason' => $e];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits on all of the provided promises, but does not unwrap rejected promises
|
||||
* as thrown exception.
|
||||
*
|
||||
* Returns an array of inspection state arrays.
|
||||
*
|
||||
* @param PromiseInterface[] $promises Traversable of promises to wait upon.
|
||||
*
|
||||
* @return array
|
||||
* @see GuzzleHttp\Promise\inspect for the inspection state array format.
|
||||
*/
|
||||
function inspect_all($promises)
|
||||
{
|
||||
$results = [];
|
||||
foreach ($promises as $key => $promise) {
|
||||
$results[$key] = inspect($promise);
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Waits on all of the provided promises and returns the fulfilled values.
|
||||
*
|
||||
* Returns an array that contains the value of each promise (in the same order
|
||||
* the promises were provided). An exception is thrown if any of the promises
|
||||
* are rejected.
|
||||
*
|
||||
* @param mixed $promises Iterable of PromiseInterface objects to wait on.
|
||||
*
|
||||
* @return array
|
||||
* @throws \Exception on error
|
||||
*/
|
||||
function unwrap($promises)
|
||||
{
|
||||
$results = [];
|
||||
foreach ($promises as $key => $promise) {
|
||||
$results[$key] = $promise->wait();
|
||||
}
|
||||
|
||||
return $results;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an array of promises, return a promise that is fulfilled when all the
|
||||
* items in the array are fulfilled.
|
||||
*
|
||||
* The promise's fulfillment value is an array with fulfillment values at
|
||||
* respective positions to the original array. If any promise in the array
|
||||
* rejects, the returned promise is rejected with the rejection reason.
|
||||
*
|
||||
* @param mixed $promises Promises or values.
|
||||
*
|
||||
* @return Promise
|
||||
*/
|
||||
function all($promises)
|
||||
{
|
||||
$results = [];
|
||||
return each(
|
||||
$promises,
|
||||
function ($value, $idx) use (&$results) {
|
||||
$results[$idx] = $value;
|
||||
},
|
||||
function ($reason, $idx, Promise $aggregate) {
|
||||
$aggregate->reject($reason);
|
||||
}
|
||||
)->then(function () use (&$results) {
|
||||
ksort($results);
|
||||
return $results;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiate a competitive race between multiple promises or values (values will
|
||||
* become immediately fulfilled promises).
|
||||
*
|
||||
* When count amount of promises have been fulfilled, the returned promise is
|
||||
* fulfilled with an array that contains the fulfillment values of the winners
|
||||
* in order of resolution.
|
||||
*
|
||||
* This prommise is rejected with a {@see GuzzleHttp\Promise\AggregateException}
|
||||
* if the number of fulfilled promises is less than the desired $count.
|
||||
*
|
||||
* @param int $count Total number of promises.
|
||||
* @param mixed $promises Promises or values.
|
||||
*
|
||||
* @return Promise
|
||||
*/
|
||||
function some($count, $promises)
|
||||
{
|
||||
$results = [];
|
||||
$rejections = [];
|
||||
|
||||
return each(
|
||||
$promises,
|
||||
function ($value, $idx, PromiseInterface $p) use (&$results, $count) {
|
||||
if ($p->getState() !== PromiseInterface::PENDING) {
|
||||
return;
|
||||
}
|
||||
$results[$idx] = $value;
|
||||
if (count($results) >= $count) {
|
||||
$p->resolve(null);
|
||||
}
|
||||
},
|
||||
function ($reason) use (&$rejections) {
|
||||
$rejections[] = $reason;
|
||||
}
|
||||
)->then(
|
||||
function () use (&$results, &$rejections, $count) {
|
||||
if (count($results) !== $count) {
|
||||
throw new AggregateException(
|
||||
'Not enough promises to fulfill count',
|
||||
$rejections
|
||||
);
|
||||
}
|
||||
ksort($results);
|
||||
return array_values($results);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Like some(), with 1 as count. However, if the promise fulfills, the
|
||||
* fulfillment value is not an array of 1 but the value directly.
|
||||
*
|
||||
* @param mixed $promises Promises or values.
|
||||
*
|
||||
* @return PromiseInterface
|
||||
*/
|
||||
function any($promises)
|
||||
{
|
||||
return some(1, $promises)->then(function ($values) { return $values[0]; });
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a promise that is fulfilled when all of the provided promises have
|
||||
* been fulfilled or rejected.
|
||||
*
|
||||
* The returned promise is fulfilled with an array of inspection state arrays.
|
||||
*
|
||||
* @param mixed $promises Promises or values.
|
||||
*
|
||||
* @return Promise
|
||||
* @see GuzzleHttp\Promise\inspect for the inspection state array format.
|
||||
*/
|
||||
function settle($promises)
|
||||
{
|
||||
$results = [];
|
||||
|
||||
return each(
|
||||
$promises,
|
||||
function ($value, $idx) use (&$results) {
|
||||
$results[$idx] = ['state' => 'fulfilled', 'value' => $value];
|
||||
},
|
||||
function ($reason, $idx) use (&$results) {
|
||||
$results[$idx] = ['state' => 'rejected', 'reason' => $reason];
|
||||
}
|
||||
)->then(function () use (&$results) {
|
||||
ksort($results);
|
||||
return $results;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an iterator that yields promises or values, returns a promise that is
|
||||
* fulfilled with a null value when the iterator has been consumed or the
|
||||
* aggregate promise has been fulfilled or rejected.
|
||||
*
|
||||
* $onFulfilled is a function that accepts the fulfilled value, iterator
|
||||
* index, and the aggregate promise. The callback can invoke any necessary side
|
||||
* effects and choose to resolve or reject the aggregate promise if needed.
|
||||
*
|
||||
* $onRejected is a function that accepts the rejection reason, iterator
|
||||
* index, and the aggregate promise. The callback can invoke any necessary side
|
||||
* effects and choose to resolve or reject the aggregate promise if needed.
|
||||
*
|
||||
* @param mixed $iterable Iterator or array to iterate over.
|
||||
* @param callable $onFulfilled
|
||||
* @param callable $onRejected
|
||||
*
|
||||
* @return Promise
|
||||
*/
|
||||
function each(
|
||||
$iterable,
|
||||
callable $onFulfilled = null,
|
||||
callable $onRejected = null
|
||||
) {
|
||||
return (new EachPromise($iterable, [
|
||||
'fulfilled' => $onFulfilled,
|
||||
'rejected' => $onRejected
|
||||
]))->promise();
|
||||
}
|
||||
|
||||
/**
|
||||
* Like each, but only allows a certain number of outstanding promises at any
|
||||
* given time.
|
||||
*
|
||||
* $concurrency may be an integer or a function that accepts the number of
|
||||
* pending promises and returns a numeric concurrency limit value to allow for
|
||||
* dynamic a concurrency size.
|
||||
*
|
||||
* @param mixed $iterable
|
||||
* @param int|callable $concurrency
|
||||
* @param callable $onFulfilled
|
||||
* @param callable $onRejected
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
function each_limit(
|
||||
$iterable,
|
||||
$concurrency,
|
||||
callable $onFulfilled = null,
|
||||
callable $onRejected = null
|
||||
) {
|
||||
return (new EachPromise($iterable, [
|
||||
'fulfilled' => $onFulfilled,
|
||||
'rejected' => $onRejected,
|
||||
'concurrency' => $concurrency
|
||||
]))->promise();
|
||||
}
|
||||
|
||||
/**
|
||||
* Like each_limit, but ensures that no promise in the given $iterable argument
|
||||
* is rejected. If any promise is rejected, then the aggregate promise is
|
||||
* rejected with the encountered rejection.
|
||||
*
|
||||
* @param mixed $iterable
|
||||
* @param int|callable $concurrency
|
||||
* @param callable $onFulfilled
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
function each_limit_all(
|
||||
$iterable,
|
||||
$concurrency,
|
||||
callable $onFulfilled = null
|
||||
) {
|
||||
return each_limit(
|
||||
$iterable,
|
||||
$concurrency,
|
||||
$onFulfilled,
|
||||
function ($reason, $idx, PromiseInterface $aggregate) {
|
||||
$aggregate->reject($reason);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if a promise is fulfilled.
|
||||
*
|
||||
* @param PromiseInterface $promise
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function is_fulfilled(PromiseInterface $promise)
|
||||
{
|
||||
return $promise->getState() === PromiseInterface::FULFILLED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if a promise is rejected.
|
||||
*
|
||||
* @param PromiseInterface $promise
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function is_rejected(PromiseInterface $promise)
|
||||
{
|
||||
return $promise->getState() === PromiseInterface::REJECTED;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if a promise is fulfilled or rejected.
|
||||
*
|
||||
* @param PromiseInterface $promise
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function is_settled(PromiseInterface $promise)
|
||||
{
|
||||
return $promise->getState() !== PromiseInterface::PENDING;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a promise that is resolved using a generator that yields values or
|
||||
* promises (somewhat similar to C#'s async keyword).
|
||||
*
|
||||
* When called, the coroutine function will start an instance of the generator
|
||||
* and returns a promise that is fulfilled with its final yielded value.
|
||||
*
|
||||
* Control is returned back to the generator when the yielded promise settles.
|
||||
* This can lead to less verbose code when doing lots of sequential async calls
|
||||
* with minimal processing in between.
|
||||
*
|
||||
* use GuzzleHttp\Promise;
|
||||
*
|
||||
* function createPromise($value) {
|
||||
* return new Promise\FulfilledPromise($value);
|
||||
* }
|
||||
*
|
||||
* $promise = Promise\coroutine(function () {
|
||||
* $value = (yield createPromise('a'));
|
||||
* try {
|
||||
* $value = (yield createPromise($value . 'b'));
|
||||
* } catch (\Exception $e) {
|
||||
* // The promise was rejected.
|
||||
* }
|
||||
* yield $value . 'c';
|
||||
* });
|
||||
*
|
||||
* // Outputs "abc"
|
||||
* $promise->then(function ($v) { echo $v; });
|
||||
*
|
||||
* @param callable $generatorFn Generator function to wrap into a promise.
|
||||
*
|
||||
* @return Promise
|
||||
* @link https://github.com/petkaantonov/bluebird/blob/master/API.md#generators inspiration
|
||||
*/
|
||||
function coroutine(callable $generatorFn)
|
||||
{
|
||||
$generator = $generatorFn();
|
||||
return __next_coroutine($generator->current(), $generator)->then();
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
function __next_coroutine($yielded, \Generator $generator)
|
||||
{
|
||||
return promise_for($yielded)->then(
|
||||
function ($value) use ($generator) {
|
||||
$nextYield = $generator->send($value);
|
||||
return $generator->valid()
|
||||
? __next_coroutine($nextYield, $generator)
|
||||
: $value;
|
||||
},
|
||||
function ($reason) use ($generator) {
|
||||
$nextYield = $generator->throw(exception_for($reason));
|
||||
// The throw was caught, so keep iterating on the coroutine
|
||||
return __next_coroutine($nextYield, $generator);
|
||||
}
|
||||
);
|
||||
}
|
6
server/vendor/guzzlehttp/promises/src/functions_include.php
vendored
Normal file
6
server/vendor/guzzlehttp/promises/src/functions_include.php
vendored
Normal file
|
@ -0,0 +1,6 @@
|
|||
<?php
|
||||
|
||||
// Don't redefine the functions if included multiple times.
|
||||
if (!function_exists('GuzzleHttp\Promise\promise_for')) {
|
||||
require __DIR__ . '/functions.php';
|
||||
}
|
14
server/vendor/guzzlehttp/promises/tests/AggregateExceptionTest.php
vendored
Normal file
14
server/vendor/guzzlehttp/promises/tests/AggregateExceptionTest.php
vendored
Normal file
|
@ -0,0 +1,14 @@
|
|||
<?php
|
||||
namespace GuzzleHttp\Promise\Tests;
|
||||
|
||||
use GuzzleHttp\Promise\AggregateException;
|
||||
|
||||
class AggregateExceptionTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testHasReason()
|
||||
{
|
||||
$e = new AggregateException('foo', ['baz', 'bar']);
|
||||
$this->assertContains('foo', $e->getMessage());
|
||||
$this->assertEquals(['baz', 'bar'], $e->getReason());
|
||||
}
|
||||
}
|
294
server/vendor/guzzlehttp/promises/tests/EachPromiseTest.php
vendored
Normal file
294
server/vendor/guzzlehttp/promises/tests/EachPromiseTest.php
vendored
Normal file
|
@ -0,0 +1,294 @@
|
|||
<?php
|
||||
namespace GuzzleHttp\Promise\Tests;
|
||||
|
||||
use GuzzleHttp\Promise\RejectedPromise;
|
||||
use GuzzleHttp\Promise\FulfilledPromise;
|
||||
use GuzzleHttp\Promise\Promise;
|
||||
use GuzzleHttp\Promise\PromiseInterface;
|
||||
use GuzzleHttp\Promise\EachPromise;
|
||||
use GuzzleHttp\Promise as P;
|
||||
|
||||
/**
|
||||
* @covers GuzzleHttp\Promise\EachPromise
|
||||
*/
|
||||
class EachPromiseTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testReturnsSameInstance()
|
||||
{
|
||||
$each = new EachPromise([], ['concurrency' => 100]);
|
||||
$this->assertSame($each->promise(), $each->promise());
|
||||
}
|
||||
|
||||
public function testInvokesAllPromises()
|
||||
{
|
||||
$promises = [new Promise(), new Promise(), new Promise()];
|
||||
$called = [];
|
||||
$each = new EachPromise($promises, [
|
||||
'fulfilled' => function ($value) use (&$called) {
|
||||
$called[] = $value;
|
||||
}
|
||||
]);
|
||||
$p = $each->promise();
|
||||
$promises[0]->resolve('a');
|
||||
$promises[1]->resolve('c');
|
||||
$promises[2]->resolve('b');
|
||||
P\queue()->run();
|
||||
$this->assertEquals(['a', 'c', 'b'], $called);
|
||||
$this->assertEquals(PromiseInterface::FULFILLED, $p->getState());
|
||||
}
|
||||
|
||||
public function testIsWaitable()
|
||||
{
|
||||
$a = new Promise(function () use (&$a) { $a->resolve('a'); });
|
||||
$b = new Promise(function () use (&$b) { $b->resolve('b'); });
|
||||
$called = [];
|
||||
$each = new EachPromise([$a, $b], [
|
||||
'fulfilled' => function ($value) use (&$called) { $called[] = $value; }
|
||||
]);
|
||||
$p = $each->promise();
|
||||
$this->assertNull($p->wait());
|
||||
$this->assertEquals(PromiseInterface::FULFILLED, $p->getState());
|
||||
$this->assertEquals(['a', 'b'], $called);
|
||||
}
|
||||
|
||||
public function testCanResolveBeforeConsumingAll()
|
||||
{
|
||||
$called = 0;
|
||||
$a = new Promise(function () use (&$a) { $a->resolve('a'); });
|
||||
$b = new Promise(function () { $this->fail(); });
|
||||
$each = new EachPromise([$a, $b], [
|
||||
'fulfilled' => function ($value, $idx, Promise $aggregate) use (&$called) {
|
||||
$this->assertSame($idx, 0);
|
||||
$this->assertEquals('a', $value);
|
||||
$aggregate->resolve(null);
|
||||
$called++;
|
||||
},
|
||||
'rejected' => function (\Exception $reason) {
|
||||
$this->fail($reason->getMessage());
|
||||
}
|
||||
]);
|
||||
$p = $each->promise();
|
||||
$p->wait();
|
||||
$this->assertNull($p->wait());
|
||||
$this->assertEquals(1, $called);
|
||||
$this->assertEquals(PromiseInterface::FULFILLED, $a->getState());
|
||||
$this->assertEquals(PromiseInterface::PENDING, $b->getState());
|
||||
// Resolving $b has no effect on the aggregate promise.
|
||||
$b->resolve('foo');
|
||||
$this->assertEquals(1, $called);
|
||||
}
|
||||
|
||||
public function testLimitsPendingPromises()
|
||||
{
|
||||
$pending = [new Promise(), new Promise(), new Promise(), new Promise()];
|
||||
$promises = new \ArrayIterator($pending);
|
||||
$each = new EachPromise($promises, ['concurrency' => 2]);
|
||||
$p = $each->promise();
|
||||
$this->assertCount(2, $this->readAttribute($each, 'pending'));
|
||||
$pending[0]->resolve('a');
|
||||
$this->assertCount(2, $this->readAttribute($each, 'pending'));
|
||||
$this->assertTrue($promises->valid());
|
||||
$pending[1]->resolve('b');
|
||||
P\queue()->run();
|
||||
$this->assertCount(2, $this->readAttribute($each, 'pending'));
|
||||
$this->assertTrue($promises->valid());
|
||||
$promises[2]->resolve('c');
|
||||
P\queue()->run();
|
||||
$this->assertCount(1, $this->readAttribute($each, 'pending'));
|
||||
$this->assertEquals(PromiseInterface::PENDING, $p->getState());
|
||||
$promises[3]->resolve('d');
|
||||
P\queue()->run();
|
||||
$this->assertNull($this->readAttribute($each, 'pending'));
|
||||
$this->assertEquals(PromiseInterface::FULFILLED, $p->getState());
|
||||
$this->assertFalse($promises->valid());
|
||||
}
|
||||
|
||||
public function testDynamicallyLimitsPendingPromises()
|
||||
{
|
||||
$calls = [];
|
||||
$pendingFn = function ($count) use (&$calls) {
|
||||
$calls[] = $count;
|
||||
return 2;
|
||||
};
|
||||
$pending = [new Promise(), new Promise(), new Promise(), new Promise()];
|
||||
$promises = new \ArrayIterator($pending);
|
||||
$each = new EachPromise($promises, ['concurrency' => $pendingFn]);
|
||||
$p = $each->promise();
|
||||
$this->assertCount(2, $this->readAttribute($each, 'pending'));
|
||||
$pending[0]->resolve('a');
|
||||
$this->assertCount(2, $this->readAttribute($each, 'pending'));
|
||||
$this->assertTrue($promises->valid());
|
||||
$pending[1]->resolve('b');
|
||||
$this->assertCount(2, $this->readAttribute($each, 'pending'));
|
||||
P\queue()->run();
|
||||
$this->assertTrue($promises->valid());
|
||||
$promises[2]->resolve('c');
|
||||
P\queue()->run();
|
||||
$this->assertCount(1, $this->readAttribute($each, 'pending'));
|
||||
$this->assertEquals(PromiseInterface::PENDING, $p->getState());
|
||||
$promises[3]->resolve('d');
|
||||
P\queue()->run();
|
||||
$this->assertNull($this->readAttribute($each, 'pending'));
|
||||
$this->assertEquals(PromiseInterface::FULFILLED, $p->getState());
|
||||
$this->assertEquals([0, 1, 1, 1], $calls);
|
||||
$this->assertFalse($promises->valid());
|
||||
}
|
||||
|
||||
public function testClearsReferencesWhenResolved()
|
||||
{
|
||||
$called = false;
|
||||
$a = new Promise(function () use (&$a, &$called) {
|
||||
$a->resolve('a');
|
||||
$called = true;
|
||||
});
|
||||
$each = new EachPromise([$a], [
|
||||
'concurrency' => function () { return 1; },
|
||||
'fulfilled' => function () {},
|
||||
'rejected' => function () {}
|
||||
]);
|
||||
$each->promise()->wait();
|
||||
$this->assertNull($this->readAttribute($each, 'onFulfilled'));
|
||||
$this->assertNull($this->readAttribute($each, 'onRejected'));
|
||||
$this->assertNull($this->readAttribute($each, 'iterable'));
|
||||
$this->assertNull($this->readAttribute($each, 'pending'));
|
||||
$this->assertNull($this->readAttribute($each, 'concurrency'));
|
||||
$this->assertTrue($called);
|
||||
}
|
||||
|
||||
public function testCanBeCancelled()
|
||||
{
|
||||
$this->markTestIncomplete();
|
||||
}
|
||||
|
||||
public function testFulfillsImmediatelyWhenGivenAnEmptyIterator()
|
||||
{
|
||||
$each = new EachPromise(new \ArrayIterator([]));
|
||||
$result = $each->promise()->wait();
|
||||
}
|
||||
|
||||
public function testDoesNotBlowStackWithFulfilledPromises()
|
||||
{
|
||||
$pending = [];
|
||||
for ($i = 0; $i < 100; $i++) {
|
||||
$pending[] = new FulfilledPromise($i);
|
||||
}
|
||||
$values = [];
|
||||
$each = new EachPromise($pending, [
|
||||
'fulfilled' => function ($value) use (&$values) {
|
||||
$values[] = $value;
|
||||
}
|
||||
]);
|
||||
$called = false;
|
||||
$each->promise()->then(function () use (&$called) {
|
||||
$called = true;
|
||||
});
|
||||
$this->assertFalse($called);
|
||||
P\queue()->run();
|
||||
$this->assertTrue($called);
|
||||
$this->assertEquals(range(0, 99), $values);
|
||||
}
|
||||
|
||||
public function testDoesNotBlowStackWithRejectedPromises()
|
||||
{
|
||||
$pending = [];
|
||||
for ($i = 0; $i < 100; $i++) {
|
||||
$pending[] = new RejectedPromise($i);
|
||||
}
|
||||
$values = [];
|
||||
$each = new EachPromise($pending, [
|
||||
'rejected' => function ($value) use (&$values) {
|
||||
$values[] = $value;
|
||||
}
|
||||
]);
|
||||
$called = false;
|
||||
$each->promise()->then(
|
||||
function () use (&$called) { $called = true; },
|
||||
function () { $this->fail('Should not have rejected.'); }
|
||||
);
|
||||
$this->assertFalse($called);
|
||||
P\queue()->run();
|
||||
$this->assertTrue($called);
|
||||
$this->assertEquals(range(0, 99), $values);
|
||||
}
|
||||
|
||||
public function testReturnsPromiseForWhatever()
|
||||
{
|
||||
$called = [];
|
||||
$arr = ['a', 'b'];
|
||||
$each = new EachPromise($arr, [
|
||||
'fulfilled' => function ($v) use (&$called) { $called[] = $v; }
|
||||
]);
|
||||
$p = $each->promise();
|
||||
$this->assertNull($p->wait());
|
||||
$this->assertEquals(['a', 'b'], $called);
|
||||
}
|
||||
|
||||
public function testRejectsAggregateWhenNextThrows()
|
||||
{
|
||||
$iter = function () {
|
||||
yield 'a';
|
||||
throw new \Exception('Failure');
|
||||
};
|
||||
$each = new EachPromise($iter());
|
||||
$p = $each->promise();
|
||||
$e = null;
|
||||
$received = null;
|
||||
$p->then(null, function ($reason) use (&$e) { $e = $reason; });
|
||||
P\queue()->run();
|
||||
$this->assertInstanceOf('Exception', $e);
|
||||
$this->assertEquals('Failure', $e->getMessage());
|
||||
}
|
||||
|
||||
public function testDoesNotCallNextOnIteratorUntilNeededWhenWaiting()
|
||||
{
|
||||
$results = [];
|
||||
$values = [10];
|
||||
$remaining = 9;
|
||||
$iter = function () use (&$values) {
|
||||
while ($value = array_pop($values)) {
|
||||
yield $value;
|
||||
}
|
||||
};
|
||||
$each = new EachPromise($iter(), [
|
||||
'concurrency' => 1,
|
||||
'fulfilled' => function ($r) use (&$results, &$values, &$remaining) {
|
||||
$results[] = $r;
|
||||
if ($remaining > 0) {
|
||||
$values[] = $remaining--;
|
||||
}
|
||||
}
|
||||
]);
|
||||
$each->promise()->wait();
|
||||
$this->assertEquals(range(10, 1), $results);
|
||||
}
|
||||
|
||||
public function testDoesNotCallNextOnIteratorUntilNeededWhenAsync()
|
||||
{
|
||||
$firstPromise = new Promise();
|
||||
$pending = [$firstPromise];
|
||||
$values = [$firstPromise];
|
||||
$results = [];
|
||||
$remaining = 9;
|
||||
$iter = function () use (&$values) {
|
||||
while ($value = array_pop($values)) {
|
||||
yield $value;
|
||||
}
|
||||
};
|
||||
$each = new EachPromise($iter(), [
|
||||
'concurrency' => 1,
|
||||
'fulfilled' => function ($r) use (&$results, &$values, &$remaining, &$pending) {
|
||||
$results[] = $r;
|
||||
if ($remaining-- > 0) {
|
||||
$pending[] = $values[] = new Promise();
|
||||
}
|
||||
}
|
||||
]);
|
||||
$i = 0;
|
||||
$each->promise();
|
||||
while ($promise = array_pop($pending)) {
|
||||
$promise->resolve($i++);
|
||||
P\queue()->run();
|
||||
}
|
||||
$this->assertEquals(range(0, 9), $results);
|
||||
}
|
||||
}
|
108
server/vendor/guzzlehttp/promises/tests/FulfilledPromiseTest.php
vendored
Normal file
108
server/vendor/guzzlehttp/promises/tests/FulfilledPromiseTest.php
vendored
Normal file
|
@ -0,0 +1,108 @@
|
|||
<?php
|
||||
namespace GuzzleHttp\Tests\Promise;
|
||||
|
||||
use GuzzleHttp\Promise\Promise;
|
||||
use GuzzleHttp\Promise\FulfilledPromise;
|
||||
|
||||
/**
|
||||
* @covers GuzzleHttp\Promise\FulfilledPromise
|
||||
*/
|
||||
class FulfilledPromiseTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testReturnsValueWhenWaitedUpon()
|
||||
{
|
||||
$p = new FulfilledPromise('foo');
|
||||
$this->assertEquals('fulfilled', $p->getState());
|
||||
$this->assertEquals('foo', $p->wait(true));
|
||||
}
|
||||
|
||||
public function testCannotCancel()
|
||||
{
|
||||
$p = new FulfilledPromise('foo');
|
||||
$this->assertEquals('fulfilled', $p->getState());
|
||||
$p->cancel();
|
||||
$this->assertEquals('foo', $p->wait());
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \LogicException
|
||||
* @exepctedExceptionMessage Cannot resolve a fulfilled promise
|
||||
*/
|
||||
public function testCannotResolve()
|
||||
{
|
||||
$p = new FulfilledPromise('foo');
|
||||
$p->resolve('bar');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \LogicException
|
||||
* @exepctedExceptionMessage Cannot reject a fulfilled promise
|
||||
*/
|
||||
public function testCannotReject()
|
||||
{
|
||||
$p = new FulfilledPromise('foo');
|
||||
$p->reject('bar');
|
||||
}
|
||||
|
||||
public function testCanResolveWithSameValue()
|
||||
{
|
||||
$p = new FulfilledPromise('foo');
|
||||
$p->resolve('foo');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \InvalidArgumentException
|
||||
*/
|
||||
public function testCannotResolveWithPromise()
|
||||
{
|
||||
new FulfilledPromise(new Promise());
|
||||
}
|
||||
|
||||
public function testReturnsSelfWhenNoOnFulfilled()
|
||||
{
|
||||
$p = new FulfilledPromise('a');
|
||||
$this->assertSame($p, $p->then());
|
||||
}
|
||||
|
||||
public function testAsynchronouslyInvokesOnFulfilled()
|
||||
{
|
||||
$p = new FulfilledPromise('a');
|
||||
$r = null;
|
||||
$f = function ($d) use (&$r) { $r = $d; };
|
||||
$p2 = $p->then($f);
|
||||
$this->assertNotSame($p, $p2);
|
||||
$this->assertNull($r);
|
||||
\GuzzleHttp\Promise\queue()->run();
|
||||
$this->assertEquals('a', $r);
|
||||
}
|
||||
|
||||
public function testReturnsNewRejectedWhenOnFulfilledFails()
|
||||
{
|
||||
$p = new FulfilledPromise('a');
|
||||
$f = function () { throw new \Exception('b'); };
|
||||
$p2 = $p->then($f);
|
||||
$this->assertNotSame($p, $p2);
|
||||
try {
|
||||
$p2->wait();
|
||||
$this->fail();
|
||||
} catch (\Exception $e) {
|
||||
$this->assertEquals('b', $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function testOtherwiseIsSugarForRejections()
|
||||
{
|
||||
$c = null;
|
||||
$p = new FulfilledPromise('foo');
|
||||
$p->otherwise(function ($v) use (&$c) { $c = $v; });
|
||||
$this->assertNull($c);
|
||||
}
|
||||
|
||||
public function testDoesNotTryToFulfillTwiceDuringTrampoline()
|
||||
{
|
||||
$fp = new FulfilledPromise('a');
|
||||
$t1 = $fp->then(function ($v) { return $v . ' b'; });
|
||||
$t1->resolve('why!');
|
||||
$this->assertEquals('why!', $t1->wait());
|
||||
}
|
||||
}
|
50
server/vendor/guzzlehttp/promises/tests/NotPromiseInstance.php
vendored
Normal file
50
server/vendor/guzzlehttp/promises/tests/NotPromiseInstance.php
vendored
Normal file
|
@ -0,0 +1,50 @@
|
|||
<?php
|
||||
namespace GuzzleHttp\Promise\Tests;
|
||||
|
||||
use GuzzleHttp\Promise\Promise;
|
||||
use GuzzleHttp\Promise\PromiseInterface;
|
||||
|
||||
class NotPromiseInstance extends Thennable implements PromiseInterface
|
||||
{
|
||||
private $nextPromise = null;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->nextPromise = new Promise();
|
||||
}
|
||||
|
||||
public function then(callable $res = null, callable $rej = null)
|
||||
{
|
||||
return $this->nextPromise->then($res, $rej);
|
||||
}
|
||||
|
||||
public function otherwise(callable $onRejected)
|
||||
{
|
||||
return $this->then($onRejected);
|
||||
}
|
||||
|
||||
public function resolve($value)
|
||||
{
|
||||
$this->nextPromise->resolve($value);
|
||||
}
|
||||
|
||||
public function reject($reason)
|
||||
{
|
||||
$this->nextPromise->reject($reason);
|
||||
}
|
||||
|
||||
public function wait($unwrap = true, $defaultResolution = null)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public function cancel()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
public function getState()
|
||||
{
|
||||
return $this->nextPromise->getState();
|
||||
}
|
||||
}
|
579
server/vendor/guzzlehttp/promises/tests/PromiseTest.php
vendored
Normal file
579
server/vendor/guzzlehttp/promises/tests/PromiseTest.php
vendored
Normal file
|
@ -0,0 +1,579 @@
|
|||
<?php
|
||||
namespace GuzzleHttp\Promise\Tests;
|
||||
|
||||
use GuzzleHttp\Promise\CancellationException;
|
||||
use GuzzleHttp\Promise as P;
|
||||
use GuzzleHttp\Promise\Promise;
|
||||
use GuzzleHttp\Promise\RejectedPromise;
|
||||
use GuzzleHttp\Promise\RejectionException;
|
||||
|
||||
/**
|
||||
* @covers GuzzleHttp\Promise\Promise
|
||||
*/
|
||||
class PromiseTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
/**
|
||||
* @expectedException \LogicException
|
||||
* @expectedExceptionMessage The promise is already fulfilled
|
||||
*/
|
||||
public function testCannotResolveNonPendingPromise()
|
||||
{
|
||||
$p = new Promise();
|
||||
$p->resolve('foo');
|
||||
$p->resolve('bar');
|
||||
$this->assertEquals('foo', $p->wait());
|
||||
}
|
||||
|
||||
public function testCanResolveWithSameValue()
|
||||
{
|
||||
$p = new Promise();
|
||||
$p->resolve('foo');
|
||||
$p->resolve('foo');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \LogicException
|
||||
* @expectedExceptionMessage Cannot change a fulfilled promise to rejected
|
||||
*/
|
||||
public function testCannotRejectNonPendingPromise()
|
||||
{
|
||||
$p = new Promise();
|
||||
$p->resolve('foo');
|
||||
$p->reject('bar');
|
||||
$this->assertEquals('foo', $p->wait());
|
||||
}
|
||||
|
||||
public function testCanRejectWithSameValue()
|
||||
{
|
||||
$p = new Promise();
|
||||
$p->reject('foo');
|
||||
$p->reject('foo');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \LogicException
|
||||
* @expectedExceptionMessage Cannot change a fulfilled promise to rejected
|
||||
*/
|
||||
public function testCannotRejectResolveWithSameValue()
|
||||
{
|
||||
$p = new Promise();
|
||||
$p->resolve('foo');
|
||||
$p->reject('foo');
|
||||
}
|
||||
|
||||
public function testInvokesWaitFunction()
|
||||
{
|
||||
$p = new Promise(function () use (&$p) { $p->resolve('10'); });
|
||||
$this->assertEquals('10', $p->wait());
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \GuzzleHttp\Promise\RejectionException
|
||||
*/
|
||||
public function testRejectsAndThrowsWhenWaitFailsToResolve()
|
||||
{
|
||||
$p = new Promise(function () {});
|
||||
$p->wait();
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \GuzzleHttp\Promise\RejectionException
|
||||
* @expectedExceptionMessage The promise was rejected with reason: foo
|
||||
*/
|
||||
public function testThrowsWhenUnwrapIsRejectedWithNonException()
|
||||
{
|
||||
$p = new Promise(function () use (&$p) { $p->reject('foo'); });
|
||||
$p->wait();
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \UnexpectedValueException
|
||||
* @expectedExceptionMessage foo
|
||||
*/
|
||||
public function testThrowsWhenUnwrapIsRejectedWithException()
|
||||
{
|
||||
$e = new \UnexpectedValueException('foo');
|
||||
$p = new Promise(function () use (&$p, $e) { $p->reject($e); });
|
||||
$p->wait();
|
||||
}
|
||||
|
||||
public function testDoesNotUnwrapExceptionsWhenDisabled()
|
||||
{
|
||||
$p = new Promise(function () use (&$p) { $p->reject('foo'); });
|
||||
$this->assertEquals('pending', $p->getState());
|
||||
$p->wait(false);
|
||||
$this->assertEquals('rejected', $p->getState());
|
||||
}
|
||||
|
||||
public function testRejectsSelfWhenWaitThrows()
|
||||
{
|
||||
$e = new \UnexpectedValueException('foo');
|
||||
$p = new Promise(function () use ($e) { throw $e; });
|
||||
try {
|
||||
$p->wait();
|
||||
$this->fail();
|
||||
} catch (\UnexpectedValueException $e) {
|
||||
$this->assertEquals('rejected', $p->getState());
|
||||
}
|
||||
}
|
||||
|
||||
public function testWaitsOnNestedPromises()
|
||||
{
|
||||
$p = new Promise(function () use (&$p) { $p->resolve('_'); });
|
||||
$p2 = new Promise(function () use (&$p2) { $p2->resolve('foo'); });
|
||||
$p3 = $p->then(function () use ($p2) { return $p2; });
|
||||
$this->assertSame('foo', $p3->wait());
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \GuzzleHttp\Promise\RejectionException
|
||||
*/
|
||||
public function testThrowsWhenWaitingOnPromiseWithNoWaitFunction()
|
||||
{
|
||||
$p = new Promise();
|
||||
$p->wait();
|
||||
}
|
||||
|
||||
public function testThrowsWaitExceptionAfterPromiseIsResolved()
|
||||
{
|
||||
$p = new Promise(function () use (&$p) {
|
||||
$p->reject('Foo!');
|
||||
throw new \Exception('Bar?');
|
||||
});
|
||||
|
||||
try {
|
||||
$p->wait();
|
||||
$this->fail();
|
||||
} catch (\Exception $e) {
|
||||
$this->assertEquals('Bar?', $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function testGetsActualWaitValueFromThen()
|
||||
{
|
||||
$p = new Promise(function () use (&$p) { $p->reject('Foo!'); });
|
||||
$p2 = $p->then(null, function ($reason) {
|
||||
return new RejectedPromise([$reason]);
|
||||
});
|
||||
|
||||
try {
|
||||
$p2->wait();
|
||||
$this->fail('Should have thrown');
|
||||
} catch (RejectionException $e) {
|
||||
$this->assertEquals(['Foo!'], $e->getReason());
|
||||
}
|
||||
}
|
||||
|
||||
public function testWaitBehaviorIsBasedOnLastPromiseInChain()
|
||||
{
|
||||
$p3 = new Promise(function () use (&$p3) { $p3->resolve('Whoop'); });
|
||||
$p2 = new Promise(function () use (&$p2, $p3) { $p2->reject($p3); });
|
||||
$p = new Promise(function () use (&$p, $p2) { $p->reject($p2); });
|
||||
$this->assertEquals('Whoop', $p->wait());
|
||||
}
|
||||
|
||||
public function testCannotCancelNonPending()
|
||||
{
|
||||
$p = new Promise();
|
||||
$p->resolve('foo');
|
||||
$p->cancel();
|
||||
$this->assertEquals('fulfilled', $p->getState());
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \GuzzleHttp\Promise\CancellationException
|
||||
*/
|
||||
public function testCancelsPromiseWhenNoCancelFunction()
|
||||
{
|
||||
$p = new Promise();
|
||||
$p->cancel();
|
||||
$this->assertEquals('rejected', $p->getState());
|
||||
$p->wait();
|
||||
}
|
||||
|
||||
public function testCancelsPromiseWithCancelFunction()
|
||||
{
|
||||
$called = false;
|
||||
$p = new Promise(null, function () use (&$called) { $called = true; });
|
||||
$p->cancel();
|
||||
$this->assertEquals('rejected', $p->getState());
|
||||
$this->assertTrue($called);
|
||||
}
|
||||
|
||||
public function testCancelsUppermostPendingPromise()
|
||||
{
|
||||
$called = false;
|
||||
$p1 = new Promise(null, function () use (&$called) { $called = true; });
|
||||
$p2 = $p1->then(function () {});
|
||||
$p3 = $p2->then(function () {});
|
||||
$p4 = $p3->then(function () {});
|
||||
$p3->cancel();
|
||||
$this->assertEquals('rejected', $p1->getState());
|
||||
$this->assertEquals('rejected', $p2->getState());
|
||||
$this->assertEquals('rejected', $p3->getState());
|
||||
$this->assertEquals('pending', $p4->getState());
|
||||
$this->assertTrue($called);
|
||||
|
||||
try {
|
||||
$p3->wait();
|
||||
$this->fail();
|
||||
} catch (CancellationException $e) {
|
||||
$this->assertContains('cancelled', $e->getMessage());
|
||||
}
|
||||
|
||||
try {
|
||||
$p4->wait();
|
||||
$this->fail();
|
||||
} catch (CancellationException $e) {
|
||||
$this->assertContains('cancelled', $e->getMessage());
|
||||
}
|
||||
|
||||
$this->assertEquals('rejected', $p4->getState());
|
||||
}
|
||||
|
||||
public function testCancelsChildPromises()
|
||||
{
|
||||
$called1 = $called2 = $called3 = false;
|
||||
$p1 = new Promise(null, function () use (&$called1) { $called1 = true; });
|
||||
$p2 = new Promise(null, function () use (&$called2) { $called2 = true; });
|
||||
$p3 = new Promise(null, function () use (&$called3) { $called3 = true; });
|
||||
$p4 = $p2->then(function () use ($p3) { return $p3; });
|
||||
$p5 = $p4->then(function () { $this->fail(); });
|
||||
$p4->cancel();
|
||||
$this->assertEquals('pending', $p1->getState());
|
||||
$this->assertEquals('rejected', $p2->getState());
|
||||
$this->assertEquals('rejected', $p4->getState());
|
||||
$this->assertEquals('pending', $p5->getState());
|
||||
$this->assertFalse($called1);
|
||||
$this->assertTrue($called2);
|
||||
$this->assertFalse($called3);
|
||||
}
|
||||
|
||||
public function testRejectsPromiseWhenCancelFails()
|
||||
{
|
||||
$called = false;
|
||||
$p = new Promise(null, function () use (&$called) {
|
||||
$called = true;
|
||||
throw new \Exception('e');
|
||||
});
|
||||
$p->cancel();
|
||||
$this->assertEquals('rejected', $p->getState());
|
||||
$this->assertTrue($called);
|
||||
try {
|
||||
$p->wait();
|
||||
$this->fail();
|
||||
} catch (\Exception $e) {
|
||||
$this->assertEquals('e', $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function testCreatesPromiseWhenFulfilledAfterThen()
|
||||
{
|
||||
$p = new Promise();
|
||||
$carry = null;
|
||||
$p2 = $p->then(function ($v) use (&$carry) { $carry = $v; });
|
||||
$this->assertNotSame($p, $p2);
|
||||
$p->resolve('foo');
|
||||
P\queue()->run();
|
||||
|
||||
$this->assertEquals('foo', $carry);
|
||||
}
|
||||
|
||||
public function testCreatesPromiseWhenFulfilledBeforeThen()
|
||||
{
|
||||
$p = new Promise();
|
||||
$p->resolve('foo');
|
||||
$carry = null;
|
||||
$p2 = $p->then(function ($v) use (&$carry) { $carry = $v; });
|
||||
$this->assertNotSame($p, $p2);
|
||||
$this->assertNull($carry);
|
||||
\GuzzleHttp\Promise\queue()->run();
|
||||
$this->assertEquals('foo', $carry);
|
||||
}
|
||||
|
||||
public function testCreatesPromiseWhenFulfilledWithNoCallback()
|
||||
{
|
||||
$p = new Promise();
|
||||
$p->resolve('foo');
|
||||
$p2 = $p->then();
|
||||
$this->assertNotSame($p, $p2);
|
||||
$this->assertInstanceOf('GuzzleHttp\Promise\FulfilledPromise', $p2);
|
||||
}
|
||||
|
||||
public function testCreatesPromiseWhenRejectedAfterThen()
|
||||
{
|
||||
$p = new Promise();
|
||||
$carry = null;
|
||||
$p2 = $p->then(null, function ($v) use (&$carry) { $carry = $v; });
|
||||
$this->assertNotSame($p, $p2);
|
||||
$p->reject('foo');
|
||||
P\queue()->run();
|
||||
$this->assertEquals('foo', $carry);
|
||||
}
|
||||
|
||||
public function testCreatesPromiseWhenRejectedBeforeThen()
|
||||
{
|
||||
$p = new Promise();
|
||||
$p->reject('foo');
|
||||
$carry = null;
|
||||
$p2 = $p->then(null, function ($v) use (&$carry) { $carry = $v; });
|
||||
$this->assertNotSame($p, $p2);
|
||||
$this->assertNull($carry);
|
||||
P\queue()->run();
|
||||
$this->assertEquals('foo', $carry);
|
||||
}
|
||||
|
||||
public function testCreatesPromiseWhenRejectedWithNoCallback()
|
||||
{
|
||||
$p = new Promise();
|
||||
$p->reject('foo');
|
||||
$p2 = $p->then();
|
||||
$this->assertNotSame($p, $p2);
|
||||
$this->assertInstanceOf('GuzzleHttp\Promise\RejectedPromise', $p2);
|
||||
}
|
||||
|
||||
public function testInvokesWaitFnsForThens()
|
||||
{
|
||||
$p = new Promise(function () use (&$p) { $p->resolve('a'); });
|
||||
$p2 = $p
|
||||
->then(function ($v) { return $v . '-1-'; })
|
||||
->then(function ($v) { return $v . '2'; });
|
||||
$this->assertEquals('a-1-2', $p2->wait());
|
||||
}
|
||||
|
||||
public function testStacksThenWaitFunctions()
|
||||
{
|
||||
$p1 = new Promise(function () use (&$p1) { $p1->resolve('a'); });
|
||||
$p2 = new Promise(function () use (&$p2) { $p2->resolve('b'); });
|
||||
$p3 = new Promise(function () use (&$p3) { $p3->resolve('c'); });
|
||||
$p4 = $p1
|
||||
->then(function () use ($p2) { return $p2; })
|
||||
->then(function () use ($p3) { return $p3; });
|
||||
$this->assertEquals('c', $p4->wait());
|
||||
}
|
||||
|
||||
public function testForwardsFulfilledDownChainBetweenGaps()
|
||||
{
|
||||
$p = new Promise();
|
||||
$r = $r2 = null;
|
||||
$p->then(null, null)
|
||||
->then(function ($v) use (&$r) { $r = $v; return $v . '2'; })
|
||||
->then(function ($v) use (&$r2) { $r2 = $v; });
|
||||
$p->resolve('foo');
|
||||
P\queue()->run();
|
||||
$this->assertEquals('foo', $r);
|
||||
$this->assertEquals('foo2', $r2);
|
||||
}
|
||||
|
||||
public function testForwardsRejectedPromisesDownChainBetweenGaps()
|
||||
{
|
||||
$p = new Promise();
|
||||
$r = $r2 = null;
|
||||
$p->then(null, null)
|
||||
->then(null, function ($v) use (&$r) { $r = $v; return $v . '2'; })
|
||||
->then(function ($v) use (&$r2) { $r2 = $v; });
|
||||
$p->reject('foo');
|
||||
P\queue()->run();
|
||||
$this->assertEquals('foo', $r);
|
||||
$this->assertEquals('foo2', $r2);
|
||||
}
|
||||
|
||||
public function testForwardsThrownPromisesDownChainBetweenGaps()
|
||||
{
|
||||
$e = new \Exception();
|
||||
$p = new Promise();
|
||||
$r = $r2 = null;
|
||||
$p->then(null, null)
|
||||
->then(null, function ($v) use (&$r, $e) {
|
||||
$r = $v;
|
||||
throw $e;
|
||||
})
|
||||
->then(
|
||||
null,
|
||||
function ($v) use (&$r2) { $r2 = $v; }
|
||||
);
|
||||
$p->reject('foo');
|
||||
P\queue()->run();
|
||||
$this->assertEquals('foo', $r);
|
||||
$this->assertSame($e, $r2);
|
||||
}
|
||||
|
||||
public function testForwardsReturnedRejectedPromisesDownChainBetweenGaps()
|
||||
{
|
||||
$p = new Promise();
|
||||
$rejected = new RejectedPromise('bar');
|
||||
$r = $r2 = null;
|
||||
$p->then(null, null)
|
||||
->then(null, function ($v) use (&$r, $rejected) {
|
||||
$r = $v;
|
||||
return $rejected;
|
||||
})
|
||||
->then(
|
||||
null,
|
||||
function ($v) use (&$r2) { $r2 = $v; }
|
||||
);
|
||||
$p->reject('foo');
|
||||
P\queue()->run();
|
||||
$this->assertEquals('foo', $r);
|
||||
$this->assertEquals('bar', $r2);
|
||||
try {
|
||||
$p->wait();
|
||||
} catch (RejectionException $e) {
|
||||
$this->assertEquals('foo', $e->getReason());
|
||||
}
|
||||
}
|
||||
|
||||
public function testForwardsHandlersToNextPromise()
|
||||
{
|
||||
$p = new Promise();
|
||||
$p2 = new Promise();
|
||||
$resolved = null;
|
||||
$p
|
||||
->then(function ($v) use ($p2) { return $p2; })
|
||||
->then(function ($value) use (&$resolved) { $resolved = $value; });
|
||||
$p->resolve('a');
|
||||
$p2->resolve('b');
|
||||
P\queue()->run();
|
||||
$this->assertEquals('b', $resolved);
|
||||
}
|
||||
|
||||
public function testRemovesReferenceFromChildWhenParentWaitedUpon()
|
||||
{
|
||||
$r = null;
|
||||
$p = new Promise(function () use (&$p) { $p->resolve('a'); });
|
||||
$p2 = new Promise(function () use (&$p2) { $p2->resolve('b'); });
|
||||
$pb = $p->then(
|
||||
function ($v) use ($p2, &$r) {
|
||||
$r = $v;
|
||||
return $p2;
|
||||
})
|
||||
->then(function ($v) { return $v . '.'; });
|
||||
$this->assertEquals('a', $p->wait());
|
||||
$this->assertEquals('b', $p2->wait());
|
||||
$this->assertEquals('b.', $pb->wait());
|
||||
$this->assertEquals('a', $r);
|
||||
}
|
||||
|
||||
public function testForwardsHandlersWhenFulfilledPromiseIsReturned()
|
||||
{
|
||||
$res = [];
|
||||
$p = new Promise();
|
||||
$p2 = new Promise();
|
||||
$p2->resolve('foo');
|
||||
$p2->then(function ($v) use (&$res) { $res[] = 'A:' . $v; });
|
||||
// $res is A:foo
|
||||
$p
|
||||
->then(function () use ($p2, &$res) { $res[] = 'B'; return $p2; })
|
||||
->then(function ($v) use (&$res) { $res[] = 'C:' . $v; });
|
||||
$p->resolve('a');
|
||||
$p->then(function ($v) use (&$res) { $res[] = 'D:' . $v; });
|
||||
P\queue()->run();
|
||||
$this->assertEquals(['A:foo', 'B', 'D:a', 'C:foo'], $res);
|
||||
}
|
||||
|
||||
public function testForwardsHandlersWhenRejectedPromiseIsReturned()
|
||||
{
|
||||
$res = [];
|
||||
$p = new Promise();
|
||||
$p2 = new Promise();
|
||||
$p2->reject('foo');
|
||||
$p2->then(null, function ($v) use (&$res) { $res[] = 'A:' . $v; });
|
||||
$p->then(null, function () use ($p2, &$res) { $res[] = 'B'; return $p2; })
|
||||
->then(null, function ($v) use (&$res) { $res[] = 'C:' . $v; });
|
||||
$p->reject('a');
|
||||
$p->then(null, function ($v) use (&$res) { $res[] = 'D:' . $v; });
|
||||
P\queue()->run();
|
||||
$this->assertEquals(['A:foo', 'B', 'D:a', 'C:foo'], $res);
|
||||
}
|
||||
|
||||
public function testDoesNotForwardRejectedPromise()
|
||||
{
|
||||
$res = [];
|
||||
$p = new Promise();
|
||||
$p2 = new Promise();
|
||||
$p2->cancel();
|
||||
$p2->then(function ($v) use (&$res) { $res[] = "B:$v"; return $v; });
|
||||
$p->then(function ($v) use ($p2, &$res) { $res[] = "B:$v"; return $p2; })
|
||||
->then(function ($v) use (&$res) { $res[] = 'C:' . $v; });
|
||||
$p->resolve('a');
|
||||
$p->then(function ($v) use (&$res) { $res[] = 'D:' . $v; });
|
||||
P\queue()->run();
|
||||
$this->assertEquals(['B:a', 'D:a'], $res);
|
||||
}
|
||||
|
||||
public function testRecursivelyForwardsWhenOnlyThennable()
|
||||
{
|
||||
$res = [];
|
||||
$p = new Promise();
|
||||
$p2 = new Thennable();
|
||||
$p2->resolve('foo');
|
||||
$p2->then(function ($v) use (&$res) { $res[] = 'A:' . $v; });
|
||||
$p->then(function () use ($p2, &$res) { $res[] = 'B'; return $p2; })
|
||||
->then(function ($v) use (&$res) { $res[] = 'C:' . $v; });
|
||||
$p->resolve('a');
|
||||
$p->then(function ($v) use (&$res) { $res[] = 'D:' . $v; });
|
||||
P\queue()->run();
|
||||
$this->assertEquals(['A:foo', 'B', 'D:a', 'C:foo'], $res);
|
||||
}
|
||||
|
||||
public function testRecursivelyForwardsWhenNotInstanceOfPromise()
|
||||
{
|
||||
$res = [];
|
||||
$p = new Promise();
|
||||
$p2 = new NotPromiseInstance();
|
||||
$p2->then(function ($v) use (&$res) { $res[] = 'A:' . $v; });
|
||||
$p->then(function () use ($p2, &$res) { $res[] = 'B'; return $p2; })
|
||||
->then(function ($v) use (&$res) { $res[] = 'C:' . $v; });
|
||||
$p->resolve('a');
|
||||
$p->then(function ($v) use (&$res) { $res[] = 'D:' . $v; });
|
||||
P\queue()->run();
|
||||
$this->assertEquals(['B', 'D:a'], $res);
|
||||
$p2->resolve('foo');
|
||||
P\queue()->run();
|
||||
$this->assertEquals(['B', 'D:a', 'A:foo', 'C:foo'], $res);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \LogicException
|
||||
* @expectedExceptionMessage Cannot fulfill or reject a promise with itself
|
||||
*/
|
||||
public function testCannotResolveWithSelf()
|
||||
{
|
||||
$p = new Promise();
|
||||
$p->resolve($p);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \LogicException
|
||||
* @expectedExceptionMessage Cannot fulfill or reject a promise with itself
|
||||
*/
|
||||
public function testCannotRejectWithSelf()
|
||||
{
|
||||
$p = new Promise();
|
||||
$p->reject($p);
|
||||
}
|
||||
|
||||
public function testDoesNotBlowStackWhenWaitingOnNestedThens()
|
||||
{
|
||||
$inner = new Promise(function () use (&$inner) { $inner->resolve(0); });
|
||||
$prev = $inner;
|
||||
for ($i = 1; $i < 100; $i++) {
|
||||
$prev = $prev->then(function ($i) { return $i + 1; });
|
||||
}
|
||||
|
||||
$parent = new Promise(function () use (&$parent, $prev) {
|
||||
$parent->resolve($prev);
|
||||
});
|
||||
|
||||
$this->assertEquals(99, $parent->wait());
|
||||
}
|
||||
|
||||
public function testOtherwiseIsSugarForRejections()
|
||||
{
|
||||
$p = new Promise();
|
||||
$p->reject('foo');
|
||||
$p->otherwise(function ($v) use (&$c) { $c = $v; });
|
||||
P\queue()->run();
|
||||
$this->assertEquals($c, 'foo');
|
||||
}
|
||||
}
|
143
server/vendor/guzzlehttp/promises/tests/RejectedPromiseTest.php
vendored
Normal file
143
server/vendor/guzzlehttp/promises/tests/RejectedPromiseTest.php
vendored
Normal file
|
@ -0,0 +1,143 @@
|
|||
<?php
|
||||
namespace GuzzleHttp\Promise\Tests;
|
||||
|
||||
use GuzzleHttp\Promise\Promise;
|
||||
use GuzzleHttp\Promise\RejectedPromise;
|
||||
|
||||
/**
|
||||
* @covers GuzzleHttp\Promise\RejectedPromise
|
||||
*/
|
||||
class RejectedPromiseTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testThrowsReasonWhenWaitedUpon()
|
||||
{
|
||||
$p = new RejectedPromise('foo');
|
||||
$this->assertEquals('rejected', $p->getState());
|
||||
try {
|
||||
$p->wait(true);
|
||||
$this->fail();
|
||||
} catch (\Exception $e) {
|
||||
$this->assertEquals('rejected', $p->getState());
|
||||
$this->assertContains('foo', $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function testCannotCancel()
|
||||
{
|
||||
$p = new RejectedPromise('foo');
|
||||
$p->cancel();
|
||||
$this->assertEquals('rejected', $p->getState());
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \LogicException
|
||||
* @exepctedExceptionMessage Cannot resolve a rejected promise
|
||||
*/
|
||||
public function testCannotResolve()
|
||||
{
|
||||
$p = new RejectedPromise('foo');
|
||||
$p->resolve('bar');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \LogicException
|
||||
* @exepctedExceptionMessage Cannot reject a rejected promise
|
||||
*/
|
||||
public function testCannotReject()
|
||||
{
|
||||
$p = new RejectedPromise('foo');
|
||||
$p->reject('bar');
|
||||
}
|
||||
|
||||
public function testCanRejectWithSameValue()
|
||||
{
|
||||
$p = new RejectedPromise('foo');
|
||||
$p->reject('foo');
|
||||
}
|
||||
|
||||
public function testThrowsSpecificException()
|
||||
{
|
||||
$e = new \Exception();
|
||||
$p = new RejectedPromise($e);
|
||||
try {
|
||||
$p->wait(true);
|
||||
$this->fail();
|
||||
} catch (\Exception $e2) {
|
||||
$this->assertSame($e, $e2);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \InvalidArgumentException
|
||||
*/
|
||||
public function testCannotResolveWithPromise()
|
||||
{
|
||||
new RejectedPromise(new Promise());
|
||||
}
|
||||
|
||||
public function testReturnsSelfWhenNoOnReject()
|
||||
{
|
||||
$p = new RejectedPromise('a');
|
||||
$this->assertSame($p, $p->then());
|
||||
}
|
||||
|
||||
public function testInvokesOnRejectedAsynchronously()
|
||||
{
|
||||
$p = new RejectedPromise('a');
|
||||
$r = null;
|
||||
$f = function ($reason) use (&$r) { $r = $reason; };
|
||||
$p->then(null, $f);
|
||||
$this->assertNull($r);
|
||||
\GuzzleHttp\Promise\queue()->run();
|
||||
$this->assertEquals('a', $r);
|
||||
}
|
||||
|
||||
public function testReturnsNewRejectedWhenOnRejectedFails()
|
||||
{
|
||||
$p = new RejectedPromise('a');
|
||||
$f = function () { throw new \Exception('b'); };
|
||||
$p2 = $p->then(null, $f);
|
||||
$this->assertNotSame($p, $p2);
|
||||
try {
|
||||
$p2->wait();
|
||||
$this->fail();
|
||||
} catch (\Exception $e) {
|
||||
$this->assertEquals('b', $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function testWaitingIsNoOp()
|
||||
{
|
||||
$p = new RejectedPromise('a');
|
||||
$p->wait(false);
|
||||
}
|
||||
|
||||
public function testOtherwiseIsSugarForRejections()
|
||||
{
|
||||
$p = new RejectedPromise('foo');
|
||||
$p->otherwise(function ($v) use (&$c) { $c = $v; });
|
||||
\GuzzleHttp\Promise\queue()->run();
|
||||
$this->assertSame('foo', $c);
|
||||
}
|
||||
|
||||
public function testCanResolveThenWithSuccess()
|
||||
{
|
||||
$actual = null;
|
||||
$p = new RejectedPromise('foo');
|
||||
$p->otherwise(function ($v) {
|
||||
return $v . ' bar';
|
||||
})->then(function ($v) use (&$actual) {
|
||||
$actual = $v;
|
||||
});
|
||||
\GuzzleHttp\Promise\queue()->run();
|
||||
$this->assertEquals('foo bar', $actual);
|
||||
}
|
||||
|
||||
public function testDoesNotTryToRejectTwiceDuringTrampoline()
|
||||
{
|
||||
$fp = new RejectedPromise('a');
|
||||
$t1 = $fp->then(null, function ($v) { return $v . ' b'; });
|
||||
$t1->resolve('why!');
|
||||
$this->assertEquals('why!', $t1->wait());
|
||||
}
|
||||
}
|
47
server/vendor/guzzlehttp/promises/tests/RejectionExceptionTest.php
vendored
Normal file
47
server/vendor/guzzlehttp/promises/tests/RejectionExceptionTest.php
vendored
Normal file
|
@ -0,0 +1,47 @@
|
|||
<?php
|
||||
namespace GuzzleHttp\Promise\Tests;
|
||||
|
||||
use GuzzleHttp\Promise\RejectionException;
|
||||
|
||||
class Thing1
|
||||
{
|
||||
public function __construct($message)
|
||||
{
|
||||
$this->message = $message;
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
return $this->message;
|
||||
}
|
||||
}
|
||||
|
||||
class Thing2 implements \JsonSerializable
|
||||
{
|
||||
public function jsonSerialize()
|
||||
{
|
||||
return '{}';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @covers GuzzleHttp\Promise\RejectionException
|
||||
*/
|
||||
class RejectionExceptionTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testCanGetReasonFromException()
|
||||
{
|
||||
$thing = new Thing1('foo');
|
||||
$e = new RejectionException($thing);
|
||||
|
||||
$this->assertSame($thing, $e->getReason());
|
||||
$this->assertEquals('The promise was rejected with reason: foo', $e->getMessage());
|
||||
}
|
||||
|
||||
public function testCanGetReasonMessageFromJson()
|
||||
{
|
||||
$reason = new Thing2();
|
||||
$e = new RejectionException($reason);
|
||||
$this->assertContains("{}", $e->getMessage());
|
||||
}
|
||||
}
|
31
server/vendor/guzzlehttp/promises/tests/TaskQueueTest.php
vendored
Normal file
31
server/vendor/guzzlehttp/promises/tests/TaskQueueTest.php
vendored
Normal file
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
namespace GuzzleHttp\Promise\Test;
|
||||
|
||||
use GuzzleHttp\Promise\TaskQueue;
|
||||
|
||||
class TaskQueueTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testKnowsIfEmpty()
|
||||
{
|
||||
$tq = new TaskQueue(false);
|
||||
$this->assertTrue($tq->isEmpty());
|
||||
}
|
||||
|
||||
public function testKnowsIfFull()
|
||||
{
|
||||
$tq = new TaskQueue(false);
|
||||
$tq->add(function () {});
|
||||
$this->assertFalse($tq->isEmpty());
|
||||
}
|
||||
|
||||
public function testExecutesTasksInOrder()
|
||||
{
|
||||
$tq = new TaskQueue(false);
|
||||
$called = [];
|
||||
$tq->add(function () use (&$called) { $called[] = 'a'; });
|
||||
$tq->add(function () use (&$called) { $called[] = 'b'; });
|
||||
$tq->add(function () use (&$called) { $called[] = 'c'; });
|
||||
$tq->run();
|
||||
$this->assertEquals(['a', 'b', 'c'], $called);
|
||||
}
|
||||
}
|
24
server/vendor/guzzlehttp/promises/tests/Thennable.php
vendored
Normal file
24
server/vendor/guzzlehttp/promises/tests/Thennable.php
vendored
Normal file
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
namespace GuzzleHttp\Promise\Tests;
|
||||
|
||||
use GuzzleHttp\Promise\Promise;
|
||||
|
||||
class Thennable
|
||||
{
|
||||
private $nextPromise = null;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->nextPromise = new Promise();
|
||||
}
|
||||
|
||||
public function then(callable $res = null, callable $rej = null)
|
||||
{
|
||||
return $this->nextPromise->then($res, $rej);
|
||||
}
|
||||
|
||||
public function resolve($value)
|
||||
{
|
||||
$this->nextPromise->resolve($value);
|
||||
}
|
||||
}
|
4
server/vendor/guzzlehttp/promises/tests/bootstrap.php
vendored
Normal file
4
server/vendor/guzzlehttp/promises/tests/bootstrap.php
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
<?php
|
||||
require __DIR__ . '/../vendor/autoload.php';
|
||||
require __DIR__ . '/Thennable.php';
|
||||
require __DIR__ . '/NotPromiseInstance.php';
|
694
server/vendor/guzzlehttp/promises/tests/functionsTest.php
vendored
Normal file
694
server/vendor/guzzlehttp/promises/tests/functionsTest.php
vendored
Normal file
|
@ -0,0 +1,694 @@
|
|||
<?php
|
||||
namespace GuzzleHttp\Promise\Tests;
|
||||
|
||||
use GuzzleHttp\Promise as P;
|
||||
use GuzzleHttp\Promise\FulfilledPromise;
|
||||
use GuzzleHttp\Promise\Promise;
|
||||
use GuzzleHttp\Promise\RejectedPromise;
|
||||
|
||||
class FunctionsTest extends \PHPUnit_Framework_TestCase
|
||||
{
|
||||
public function testCreatesPromiseForValue()
|
||||
{
|
||||
$p = \GuzzleHttp\Promise\promise_for('foo');
|
||||
$this->assertInstanceOf('GuzzleHttp\Promise\FulfilledPromise', $p);
|
||||
}
|
||||
|
||||
public function testReturnsPromiseForPromise()
|
||||
{
|
||||
$p = new Promise();
|
||||
$this->assertSame($p, \GuzzleHttp\Promise\promise_for($p));
|
||||
}
|
||||
|
||||
public function testReturnsPromiseForThennable()
|
||||
{
|
||||
$p = new Thennable();
|
||||
$wrapped = \GuzzleHttp\Promise\promise_for($p);
|
||||
$this->assertNotSame($p, $wrapped);
|
||||
$this->assertInstanceOf('GuzzleHttp\Promise\PromiseInterface', $wrapped);
|
||||
$p->resolve('foo');
|
||||
P\queue()->run();
|
||||
$this->assertEquals('foo', $wrapped->wait());
|
||||
}
|
||||
|
||||
public function testReturnsRejection()
|
||||
{
|
||||
$p = \GuzzleHttp\Promise\rejection_for('fail');
|
||||
$this->assertInstanceOf('GuzzleHttp\Promise\RejectedPromise', $p);
|
||||
$this->assertEquals('fail', $this->readAttribute($p, 'reason'));
|
||||
}
|
||||
|
||||
public function testReturnsPromisesAsIsInRejectionFor()
|
||||
{
|
||||
$a = new Promise();
|
||||
$b = \GuzzleHttp\Promise\rejection_for($a);
|
||||
$this->assertSame($a, $b);
|
||||
}
|
||||
|
||||
public function testWaitsOnAllPromisesIntoArray()
|
||||
{
|
||||
$e = new \Exception();
|
||||
$a = new Promise(function () use (&$a) { $a->resolve('a'); });
|
||||
$b = new Promise(function () use (&$b) { $b->reject('b'); });
|
||||
$c = new Promise(function () use (&$c, $e) { $c->reject($e); });
|
||||
$results = \GuzzleHttp\Promise\inspect_all([$a, $b, $c]);
|
||||
$this->assertEquals([
|
||||
['state' => 'fulfilled', 'value' => 'a'],
|
||||
['state' => 'rejected', 'reason' => 'b'],
|
||||
['state' => 'rejected', 'reason' => $e]
|
||||
], $results);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \GuzzleHttp\Promise\RejectionException
|
||||
*/
|
||||
public function testUnwrapsPromisesWithNoDefaultAndFailure()
|
||||
{
|
||||
$promises = [new FulfilledPromise('a'), new Promise()];
|
||||
\GuzzleHttp\Promise\unwrap($promises);
|
||||
}
|
||||
|
||||
public function testUnwrapsPromisesWithNoDefault()
|
||||
{
|
||||
$promises = [new FulfilledPromise('a')];
|
||||
$this->assertEquals(['a'], \GuzzleHttp\Promise\unwrap($promises));
|
||||
}
|
||||
|
||||
public function testUnwrapsPromisesWithKeys()
|
||||
{
|
||||
$promises = [
|
||||
'foo' => new FulfilledPromise('a'),
|
||||
'bar' => new FulfilledPromise('b'),
|
||||
];
|
||||
$this->assertEquals([
|
||||
'foo' => 'a',
|
||||
'bar' => 'b'
|
||||
], \GuzzleHttp\Promise\unwrap($promises));
|
||||
}
|
||||
|
||||
public function testAllAggregatesSortedArray()
|
||||
{
|
||||
$a = new Promise();
|
||||
$b = new Promise();
|
||||
$c = new Promise();
|
||||
$d = \GuzzleHttp\Promise\all([$a, $b, $c]);
|
||||
$b->resolve('b');
|
||||
$a->resolve('a');
|
||||
$c->resolve('c');
|
||||
$d->then(
|
||||
function ($value) use (&$result) { $result = $value; },
|
||||
function ($reason) use (&$result) { $result = $reason; }
|
||||
);
|
||||
P\queue()->run();
|
||||
$this->assertEquals(['a', 'b', 'c'], $result);
|
||||
}
|
||||
|
||||
public function testAllThrowsWhenAnyRejected()
|
||||
{
|
||||
$a = new Promise();
|
||||
$b = new Promise();
|
||||
$c = new Promise();
|
||||
$d = \GuzzleHttp\Promise\all([$a, $b, $c]);
|
||||
$b->resolve('b');
|
||||
$a->reject('fail');
|
||||
$c->resolve('c');
|
||||
$d->then(
|
||||
function ($value) use (&$result) { $result = $value; },
|
||||
function ($reason) use (&$result) { $result = $reason; }
|
||||
);
|
||||
P\queue()->run();
|
||||
$this->assertEquals('fail', $result);
|
||||
}
|
||||
|
||||
public function testSomeAggregatesSortedArrayWithMax()
|
||||
{
|
||||
$a = new Promise();
|
||||
$b = new Promise();
|
||||
$c = new Promise();
|
||||
$d = \GuzzleHttp\Promise\some(2, [$a, $b, $c]);
|
||||
$b->resolve('b');
|
||||
$c->resolve('c');
|
||||
$a->resolve('a');
|
||||
$d->then(function ($value) use (&$result) { $result = $value; });
|
||||
P\queue()->run();
|
||||
$this->assertEquals(['b', 'c'], $result);
|
||||
}
|
||||
|
||||
public function testSomeRejectsWhenTooManyRejections()
|
||||
{
|
||||
$a = new Promise();
|
||||
$b = new Promise();
|
||||
$d = \GuzzleHttp\Promise\some(2, [$a, $b]);
|
||||
$a->reject('bad');
|
||||
$b->resolve('good');
|
||||
P\queue()->run();
|
||||
$this->assertEquals($a::REJECTED, $d->getState());
|
||||
$d->then(null, function ($reason) use (&$called) {
|
||||
$called = $reason;
|
||||
});
|
||||
P\queue()->run();
|
||||
$this->assertInstanceOf('GuzzleHttp\Promise\AggregateException', $called);
|
||||
$this->assertContains('bad', $called->getReason());
|
||||
}
|
||||
|
||||
public function testCanWaitUntilSomeCountIsSatisfied()
|
||||
{
|
||||
$a = new Promise(function () use (&$a) { $a->resolve('a'); });
|
||||
$b = new Promise(function () use (&$b) { $b->resolve('b'); });
|
||||
$c = new Promise(function () use (&$c) { $c->resolve('c'); });
|
||||
$d = \GuzzleHttp\Promise\some(2, [$a, $b, $c]);
|
||||
$this->assertEquals(['a', 'b'], $d->wait());
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \GuzzleHttp\Promise\AggregateException
|
||||
* @expectedExceptionMessage Not enough promises to fulfill count
|
||||
*/
|
||||
public function testThrowsIfImpossibleToWaitForSomeCount()
|
||||
{
|
||||
$a = new Promise(function () use (&$a) { $a->resolve('a'); });
|
||||
$d = \GuzzleHttp\Promise\some(2, [$a]);
|
||||
$d->wait();
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \GuzzleHttp\Promise\AggregateException
|
||||
* @expectedExceptionMessage Not enough promises to fulfill count
|
||||
*/
|
||||
public function testThrowsIfResolvedWithoutCountTotalResults()
|
||||
{
|
||||
$a = new Promise();
|
||||
$b = new Promise();
|
||||
$d = \GuzzleHttp\Promise\some(3, [$a, $b]);
|
||||
$a->resolve('a');
|
||||
$b->resolve('b');
|
||||
$d->wait();
|
||||
}
|
||||
|
||||
public function testAnyReturnsFirstMatch()
|
||||
{
|
||||
$a = new Promise();
|
||||
$b = new Promise();
|
||||
$c = \GuzzleHttp\Promise\any([$a, $b]);
|
||||
$b->resolve('b');
|
||||
$a->resolve('a');
|
||||
//P\queue()->run();
|
||||
//$this->assertEquals('fulfilled', $c->getState());
|
||||
$c->then(function ($value) use (&$result) { $result = $value; });
|
||||
P\queue()->run();
|
||||
$this->assertEquals('b', $result);
|
||||
}
|
||||
|
||||
public function testSettleFulfillsWithFulfilledAndRejected()
|
||||
{
|
||||
$a = new Promise();
|
||||
$b = new Promise();
|
||||
$c = new Promise();
|
||||
$d = \GuzzleHttp\Promise\settle([$a, $b, $c]);
|
||||
$b->resolve('b');
|
||||
$c->resolve('c');
|
||||
$a->reject('a');
|
||||
P\queue()->run();
|
||||
$this->assertEquals('fulfilled', $d->getState());
|
||||
$d->then(function ($value) use (&$result) { $result = $value; });
|
||||
P\queue()->run();
|
||||
$this->assertEquals([
|
||||
['state' => 'rejected', 'reason' => 'a'],
|
||||
['state' => 'fulfilled', 'value' => 'b'],
|
||||
['state' => 'fulfilled', 'value' => 'c']
|
||||
], $result);
|
||||
}
|
||||
|
||||
public function testCanInspectFulfilledPromise()
|
||||
{
|
||||
$p = new FulfilledPromise('foo');
|
||||
$this->assertEquals([
|
||||
'state' => 'fulfilled',
|
||||
'value' => 'foo'
|
||||
], \GuzzleHttp\Promise\inspect($p));
|
||||
}
|
||||
|
||||
public function testCanInspectRejectedPromise()
|
||||
{
|
||||
$p = new RejectedPromise('foo');
|
||||
$this->assertEquals([
|
||||
'state' => 'rejected',
|
||||
'reason' => 'foo'
|
||||
], \GuzzleHttp\Promise\inspect($p));
|
||||
}
|
||||
|
||||
public function testCanInspectRejectedPromiseWithNormalException()
|
||||
{
|
||||
$e = new \Exception('foo');
|
||||
$p = new RejectedPromise($e);
|
||||
$this->assertEquals([
|
||||
'state' => 'rejected',
|
||||
'reason' => $e
|
||||
], \GuzzleHttp\Promise\inspect($p));
|
||||
}
|
||||
|
||||
public function testCallsEachLimit()
|
||||
{
|
||||
$p = new Promise();
|
||||
$aggregate = \GuzzleHttp\Promise\each_limit($p, 2);
|
||||
$p->resolve('a');
|
||||
P\queue()->run();
|
||||
$this->assertEquals($p::FULFILLED, $aggregate->getState());
|
||||
}
|
||||
|
||||
public function testEachLimitAllRejectsOnFailure()
|
||||
{
|
||||
$p = [new FulfilledPromise('a'), new RejectedPromise('b')];
|
||||
$aggregate = \GuzzleHttp\Promise\each_limit_all($p, 2);
|
||||
P\queue()->run();
|
||||
$this->assertEquals(P\PromiseInterface::REJECTED, $aggregate->getState());
|
||||
$result = \GuzzleHttp\Promise\inspect($aggregate);
|
||||
$this->assertEquals('b', $result['reason']);
|
||||
}
|
||||
|
||||
public function testIterForReturnsIterator()
|
||||
{
|
||||
$iter = new \ArrayIterator();
|
||||
$this->assertSame($iter, \GuzzleHttp\Promise\iter_for($iter));
|
||||
}
|
||||
|
||||
public function testKnowsIfFulfilled()
|
||||
{
|
||||
$p = new FulfilledPromise(null);
|
||||
$this->assertTrue(P\is_fulfilled($p));
|
||||
$this->assertFalse(P\is_rejected($p));
|
||||
}
|
||||
|
||||
public function testKnowsIfRejected()
|
||||
{
|
||||
$p = new RejectedPromise(null);
|
||||
$this->assertTrue(P\is_rejected($p));
|
||||
$this->assertFalse(P\is_fulfilled($p));
|
||||
}
|
||||
|
||||
public function testKnowsIfSettled()
|
||||
{
|
||||
$p = new RejectedPromise(null);
|
||||
$this->assertTrue(P\is_settled($p));
|
||||
$p = new Promise();
|
||||
$this->assertFalse(P\is_settled($p));
|
||||
}
|
||||
|
||||
public function testReturnsTrampoline()
|
||||
{
|
||||
$this->assertInstanceOf('GuzzleHttp\Promise\TaskQueue', P\queue());
|
||||
$this->assertSame(P\queue(), P\queue());
|
||||
}
|
||||
|
||||
public function testCanScheduleThunk()
|
||||
{
|
||||
$tramp = P\queue();
|
||||
$promise = P\task(function () { return 'Hi!'; });
|
||||
$c = null;
|
||||
$promise->then(function ($v) use (&$c) { $c = $v; });
|
||||
$this->assertNull($c);
|
||||
$tramp->run();
|
||||
$this->assertEquals('Hi!', $c);
|
||||
}
|
||||
|
||||
public function testCanScheduleThunkWithRejection()
|
||||
{
|
||||
$tramp = P\queue();
|
||||
$promise = P\task(function () { throw new \Exception('Hi!'); });
|
||||
$c = null;
|
||||
$promise->otherwise(function ($v) use (&$c) { $c = $v; });
|
||||
$this->assertNull($c);
|
||||
$tramp->run();
|
||||
$this->assertEquals('Hi!', $c->getMessage());
|
||||
}
|
||||
|
||||
public function testCanScheduleThunkWithWait()
|
||||
{
|
||||
$tramp = P\queue();
|
||||
$promise = P\task(function () { return 'a'; });
|
||||
$this->assertEquals('a', $promise->wait());
|
||||
$tramp->run();
|
||||
}
|
||||
|
||||
public function testYieldsFromCoroutine()
|
||||
{
|
||||
$promise = P\coroutine(function () {
|
||||
$value = (yield new P\FulfilledPromise('a'));
|
||||
yield $value . 'b';
|
||||
});
|
||||
$promise->then(function ($value) use (&$result) { $result = $value; });
|
||||
P\queue()->run();
|
||||
$this->assertEquals('ab', $result);
|
||||
}
|
||||
|
||||
public function testCanCatchExceptionsInCoroutine()
|
||||
{
|
||||
$promise = P\coroutine(function () {
|
||||
try {
|
||||
yield new P\RejectedPromise('a');
|
||||
$this->fail('Should have thrown into the coroutine!');
|
||||
} catch (P\RejectionException $e) {
|
||||
$value = (yield new P\FulfilledPromise($e->getReason()));
|
||||
yield $value . 'b';
|
||||
}
|
||||
});
|
||||
$promise->then(function ($value) use (&$result) { $result = $value; });
|
||||
P\queue()->run();
|
||||
$this->assertEquals(P\PromiseInterface::FULFILLED, $promise->getState());
|
||||
$this->assertEquals('ab', $result);
|
||||
}
|
||||
|
||||
public function testRejectsParentExceptionWhenException()
|
||||
{
|
||||
$promise = P\coroutine(function () {
|
||||
yield new P\FulfilledPromise(0);
|
||||
throw new \Exception('a');
|
||||
});
|
||||
$promise->then(
|
||||
function () { $this->fail(); },
|
||||
function ($reason) use (&$result) { $result = $reason; }
|
||||
);
|
||||
P\queue()->run();
|
||||
$this->assertInstanceOf('Exception', $result);
|
||||
$this->assertEquals('a', $result->getMessage());
|
||||
}
|
||||
|
||||
public function testCanRejectFromRejectionCallback()
|
||||
{
|
||||
$promise = P\coroutine(function () {
|
||||
yield new P\FulfilledPromise(0);
|
||||
yield new P\RejectedPromise('no!');
|
||||
});
|
||||
$promise->then(
|
||||
function () { $this->fail(); },
|
||||
function ($reason) use (&$result) { $result = $reason; }
|
||||
);
|
||||
P\queue()->run();
|
||||
$this->assertInstanceOf('GuzzleHttp\Promise\RejectionException', $result);
|
||||
$this->assertEquals('no!', $result->getReason());
|
||||
}
|
||||
|
||||
public function testCanAsyncReject()
|
||||
{
|
||||
$rej = new P\Promise();
|
||||
$promise = P\coroutine(function () use ($rej) {
|
||||
yield new P\FulfilledPromise(0);
|
||||
yield $rej;
|
||||
});
|
||||
$promise->then(
|
||||
function () { $this->fail(); },
|
||||
function ($reason) use (&$result) { $result = $reason; }
|
||||
);
|
||||
$rej->reject('no!');
|
||||
P\queue()->run();
|
||||
$this->assertInstanceOf('GuzzleHttp\Promise\RejectionException', $result);
|
||||
$this->assertEquals('no!', $result->getReason());
|
||||
}
|
||||
|
||||
public function testCanCatchAndThrowOtherException()
|
||||
{
|
||||
$promise = P\coroutine(function () {
|
||||
try {
|
||||
yield new P\RejectedPromise('a');
|
||||
$this->fail('Should have thrown into the coroutine!');
|
||||
} catch (P\RejectionException $e) {
|
||||
throw new \Exception('foo');
|
||||
}
|
||||
});
|
||||
$promise->otherwise(function ($value) use (&$result) { $result = $value; });
|
||||
P\queue()->run();
|
||||
$this->assertEquals(P\PromiseInterface::REJECTED, $promise->getState());
|
||||
$this->assertContains('foo', $result->getMessage());
|
||||
}
|
||||
|
||||
public function testCanCatchAndYieldOtherException()
|
||||
{
|
||||
$promise = P\coroutine(function () {
|
||||
try {
|
||||
yield new P\RejectedPromise('a');
|
||||
$this->fail('Should have thrown into the coroutine!');
|
||||
} catch (P\RejectionException $e) {
|
||||
yield new P\RejectedPromise('foo');
|
||||
}
|
||||
});
|
||||
$promise->otherwise(function ($value) use (&$result) { $result = $value; });
|
||||
P\queue()->run();
|
||||
$this->assertEquals(P\PromiseInterface::REJECTED, $promise->getState());
|
||||
$this->assertContains('foo', $result->getMessage());
|
||||
}
|
||||
|
||||
public function createLotsOfSynchronousPromise()
|
||||
{
|
||||
return P\coroutine(function () {
|
||||
$value = 0;
|
||||
for ($i = 0; $i < 1000; $i++) {
|
||||
$value = (yield new P\FulfilledPromise($i));
|
||||
}
|
||||
yield $value;
|
||||
});
|
||||
}
|
||||
|
||||
public function testLotsOfSynchronousDoesNotBlowStack()
|
||||
{
|
||||
$promise = $this->createLotsOfSynchronousPromise();
|
||||
$promise->then(function ($v) use (&$r) { $r = $v; });
|
||||
P\queue()->run();
|
||||
$this->assertEquals(999, $r);
|
||||
}
|
||||
|
||||
public function testLotsOfSynchronousWaitDoesNotBlowStack()
|
||||
{
|
||||
$promise = $this->createLotsOfSynchronousPromise();
|
||||
$promise->then(function ($v) use (&$r) { $r = $v; });
|
||||
$this->assertEquals(999, $promise->wait());
|
||||
$this->assertEquals(999, $r);
|
||||
}
|
||||
|
||||
private function createLotsOfFlappingPromise()
|
||||
{
|
||||
return P\coroutine(function () {
|
||||
$value = 0;
|
||||
for ($i = 0; $i < 1000; $i++) {
|
||||
try {
|
||||
if ($i % 2) {
|
||||
$value = (yield new P\FulfilledPromise($i));
|
||||
} else {
|
||||
$value = (yield new P\RejectedPromise($i));
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
$value = (yield new P\FulfilledPromise($i));
|
||||
}
|
||||
}
|
||||
yield $value;
|
||||
});
|
||||
}
|
||||
|
||||
public function testLotsOfTryCatchingDoesNotBlowStack()
|
||||
{
|
||||
$promise = $this->createLotsOfFlappingPromise();
|
||||
$promise->then(function ($v) use (&$r) { $r = $v; });
|
||||
P\queue()->run();
|
||||
$this->assertEquals(999, $r);
|
||||
}
|
||||
|
||||
public function testLotsOfTryCatchingWaitingDoesNotBlowStack()
|
||||
{
|
||||
$promise = $this->createLotsOfFlappingPromise();
|
||||
$promise->then(function ($v) use (&$r) { $r = $v; });
|
||||
$this->assertEquals(999, $promise->wait());
|
||||
$this->assertEquals(999, $r);
|
||||
}
|
||||
|
||||
public function testAsyncPromisesWithCorrectlyYieldedValues()
|
||||
{
|
||||
$promises = [
|
||||
new P\Promise(),
|
||||
new P\Promise(),
|
||||
new P\Promise()
|
||||
];
|
||||
|
||||
$promise = P\coroutine(function () use ($promises) {
|
||||
$value = null;
|
||||
$this->assertEquals('skip', (yield new P\FulfilledPromise('skip')));
|
||||
foreach ($promises as $idx => $p) {
|
||||
$value = (yield $p);
|
||||
$this->assertEquals($value, $idx);
|
||||
$this->assertEquals('skip', (yield new P\FulfilledPromise('skip')));
|
||||
}
|
||||
$this->assertEquals('skip', (yield new P\FulfilledPromise('skip')));
|
||||
yield $value;
|
||||
});
|
||||
|
||||
$promises[0]->resolve(0);
|
||||
$promises[1]->resolve(1);
|
||||
$promises[2]->resolve(2);
|
||||
|
||||
$promise->then(function ($v) use (&$r) { $r = $v; });
|
||||
P\queue()->run();
|
||||
$this->assertEquals(2, $r);
|
||||
}
|
||||
|
||||
public function testYieldFinalWaitablePromise()
|
||||
{
|
||||
$p1 = new P\Promise(function () use (&$p1) {
|
||||
$p1->resolve('skip me');
|
||||
});
|
||||
$p2 = new P\Promise(function () use (&$p2) {
|
||||
$p2->resolve('hello!');
|
||||
});
|
||||
$co = P\coroutine(function() use ($p1, $p2) {
|
||||
yield $p1;
|
||||
yield $p2;
|
||||
});
|
||||
P\queue()->run();
|
||||
$this->assertEquals('hello!', $co->wait());
|
||||
}
|
||||
|
||||
public function testCanYieldFinalPendingPromise()
|
||||
{
|
||||
$p1 = new P\Promise();
|
||||
$p2 = new P\Promise();
|
||||
$co = P\coroutine(function() use ($p1, $p2) {
|
||||
yield $p1;
|
||||
yield $p2;
|
||||
});
|
||||
$p1->resolve('a');
|
||||
$p2->resolve('b');
|
||||
$co->then(function ($value) use (&$result) { $result = $value; });
|
||||
P\queue()->run();
|
||||
$this->assertEquals('b', $result);
|
||||
}
|
||||
|
||||
public function testCanNestYieldsAndFailures()
|
||||
{
|
||||
$p1 = new P\Promise();
|
||||
$p2 = new P\Promise();
|
||||
$p3 = new P\Promise();
|
||||
$p4 = new P\Promise();
|
||||
$p5 = new P\Promise();
|
||||
$co = P\coroutine(function() use ($p1, $p2, $p3, $p4, $p5) {
|
||||
try {
|
||||
yield $p1;
|
||||
} catch (\Exception $e) {
|
||||
yield $p2;
|
||||
try {
|
||||
yield $p3;
|
||||
yield $p4;
|
||||
} catch (\Exception $e) {
|
||||
yield $p5;
|
||||
}
|
||||
}
|
||||
});
|
||||
$p1->reject('a');
|
||||
$p2->resolve('b');
|
||||
$p3->resolve('c');
|
||||
$p4->reject('d');
|
||||
$p5->resolve('e');
|
||||
$co->then(function ($value) use (&$result) { $result = $value; });
|
||||
P\queue()->run();
|
||||
$this->assertEquals('e', $result);
|
||||
}
|
||||
|
||||
public function testCanYieldErrorsAndSuccessesWithoutRecursion()
|
||||
{
|
||||
$promises = [];
|
||||
for ($i = 0; $i < 20; $i++) {
|
||||
$promises[] = new P\Promise();
|
||||
}
|
||||
|
||||
$co = P\coroutine(function() use ($promises) {
|
||||
for ($i = 0; $i < 20; $i += 4) {
|
||||
try {
|
||||
yield $promises[$i];
|
||||
yield $promises[$i + 1];
|
||||
} catch (\Exception $e) {
|
||||
yield $promises[$i + 2];
|
||||
yield $promises[$i + 3];
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
for ($i = 0; $i < 20; $i += 4) {
|
||||
$promises[$i]->resolve($i);
|
||||
$promises[$i + 1]->reject($i + 1);
|
||||
$promises[$i + 2]->resolve($i + 2);
|
||||
$promises[$i + 3]->resolve($i + 3);
|
||||
}
|
||||
|
||||
$co->then(function ($value) use (&$result) { $result = $value; });
|
||||
P\queue()->run();
|
||||
$this->assertEquals('19', $result);
|
||||
}
|
||||
|
||||
public function testCanWaitOnPromiseAfterFulfilled()
|
||||
{
|
||||
$f = function () {
|
||||
static $i = 0;
|
||||
$i++;
|
||||
return $p = new P\Promise(function () use (&$p, $i) {
|
||||
$p->resolve($i . '-bar');
|
||||
});
|
||||
};
|
||||
|
||||
$promises = [];
|
||||
for ($i = 0; $i < 20; $i++) {
|
||||
$promises[] = $f();
|
||||
}
|
||||
|
||||
$p = P\coroutine(function () use ($promises) {
|
||||
yield new P\FulfilledPromise('foo!');
|
||||
foreach ($promises as $promise) {
|
||||
yield $promise;
|
||||
}
|
||||
});
|
||||
|
||||
$this->assertEquals('20-bar', $p->wait());
|
||||
}
|
||||
|
||||
public function testCanWaitOnErroredPromises()
|
||||
{
|
||||
$p1 = new P\Promise(function () use (&$p1) { $p1->reject('a'); });
|
||||
$p2 = new P\Promise(function () use (&$p2) { $p2->resolve('b'); });
|
||||
$p3 = new P\Promise(function () use (&$p3) { $p3->resolve('c'); });
|
||||
$p4 = new P\Promise(function () use (&$p4) { $p4->reject('d'); });
|
||||
$p5 = new P\Promise(function () use (&$p5) { $p5->resolve('e'); });
|
||||
$p6 = new P\Promise(function () use (&$p6) { $p6->reject('f'); });
|
||||
|
||||
$co = P\coroutine(function() use ($p1, $p2, $p3, $p4, $p5, $p6) {
|
||||
try {
|
||||
yield $p1;
|
||||
} catch (\Exception $e) {
|
||||
yield $p2;
|
||||
try {
|
||||
yield $p3;
|
||||
yield $p4;
|
||||
} catch (\Exception $e) {
|
||||
yield $p5;
|
||||
yield $p6;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
$res = P\inspect($co);
|
||||
$this->assertEquals('f', $res['reason']);
|
||||
}
|
||||
|
||||
public function testCoroutineOtherwiseIntegrationTest()
|
||||
{
|
||||
$a = new P\Promise();
|
||||
$b = new P\Promise();
|
||||
$promise = P\coroutine(function () use ($a, $b) {
|
||||
// Execute the pool of commands concurrently, and process errors.
|
||||
yield $a;
|
||||
yield $b;
|
||||
})->otherwise(function (\Exception $e) {
|
||||
// Throw errors from the operations as a specific Multipart error.
|
||||
throw new \OutOfBoundsException('a', 0, $e);
|
||||
});
|
||||
$a->resolve('a');
|
||||
$b->reject('b');
|
||||
$reason = P\inspect($promise)['reason'];
|
||||
$this->assertInstanceOf('OutOfBoundsException', $reason);
|
||||
$this->assertInstanceOf('GuzzleHttp\Promise\RejectionException', $reason->getPrevious());
|
||||
}
|
||||
}
|
11
server/vendor/guzzlehttp/psr7/.gitignore
vendored
Normal file
11
server/vendor/guzzlehttp/psr7/.gitignore
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
phpunit.xml
|
||||
composer.phar
|
||||
composer.lock
|
||||
composer-test.lock
|
||||
vendor/
|
||||
build/artifacts/
|
||||
artifacts/
|
||||
docs/_build
|
||||
docs/*.pyc
|
||||
.idea
|
||||
.DS_STORE
|
20
server/vendor/guzzlehttp/psr7/.travis.yml
vendored
Normal file
20
server/vendor/guzzlehttp/psr7/.travis.yml
vendored
Normal file
|
@ -0,0 +1,20 @@
|
|||
language: php
|
||||
|
||||
php:
|
||||
- 5.4
|
||||
- 5.5
|
||||
- 5.6
|
||||
- 7.0
|
||||
- hhvm
|
||||
|
||||
sudo: false
|
||||
|
||||
install:
|
||||
- travis_retry composer install --no-interaction --prefer-source
|
||||
|
||||
script: make test
|
||||
|
||||
matrix:
|
||||
allow_failures:
|
||||
- php: hhvm
|
||||
fast_finish: true
|
32
server/vendor/guzzlehttp/psr7/CHANGELOG.md
vendored
Normal file
32
server/vendor/guzzlehttp/psr7/CHANGELOG.md
vendored
Normal file
|
@ -0,0 +1,32 @@
|
|||
# CHANGELOG
|
||||
|
||||
## 1.2.1 - 2015-11-02
|
||||
|
||||
* Now supporting negative offsets when seeking to SEEK_END.
|
||||
|
||||
## 1.2.0 - 2015-08-15
|
||||
|
||||
* Body as `"0"` is now properly added to a response.
|
||||
* Now allowing forward seeking in CachingStream.
|
||||
* Now properly parsing HTTP requests that contain proxy targets in
|
||||
`parse_request`.
|
||||
* functions.php is now conditionally required.
|
||||
* user-info is no longer dropped when resolving URIs.
|
||||
|
||||
## 1.1.0 - 2015-06-24
|
||||
|
||||
* URIs can now be relative.
|
||||
* `multipart/form-data` headers are now overridden case-insensitively.
|
||||
* URI paths no longer encode the following characters because they are allowed
|
||||
in URIs: "(", ")", "*", "!", "'"
|
||||
* A port is no longer added to a URI when the scheme is missing and no port is
|
||||
present.
|
||||
|
||||
## 1.0.0 - 2015-05-19
|
||||
|
||||
Initial release.
|
||||
|
||||
Currently unsupported:
|
||||
|
||||
- `Psr\Http\Message\ServerRequestInterface`
|
||||
- `Psr\Http\Message\UploadedFileInterface`
|
19
server/vendor/guzzlehttp/psr7/LICENSE
vendored
Normal file
19
server/vendor/guzzlehttp/psr7/LICENSE
vendored
Normal file
|
@ -0,0 +1,19 @@
|
|||
Copyright (c) 2015 Michael Dowling, https://github.com/mtdowling <mtdowling@gmail.com>
|
||||
|
||||
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.
|
13
server/vendor/guzzlehttp/psr7/Makefile
vendored
Normal file
13
server/vendor/guzzlehttp/psr7/Makefile
vendored
Normal file
|
@ -0,0 +1,13 @@
|
|||
all: clean test
|
||||
|
||||
test:
|
||||
vendor/bin/phpunit $(TEST)
|
||||
|
||||
coverage:
|
||||
vendor/bin/phpunit --coverage-html=artifacts/coverage $(TEST)
|
||||
|
||||
view-coverage:
|
||||
open artifacts/coverage/index.html
|
||||
|
||||
clean:
|
||||
rm -rf artifacts/*
|
580
server/vendor/guzzlehttp/psr7/README.md
vendored
Normal file
580
server/vendor/guzzlehttp/psr7/README.md
vendored
Normal file
|
@ -0,0 +1,580 @@
|
|||
# PSR-7 Message Implementation
|
||||
|
||||
This repository contains a partial [PSR-7](http://www.php-fig.org/psr/psr-7/)
|
||||
message implementation, several stream decorators, and some helpful
|
||||
functionality like query string parsing. Currently missing
|
||||
ServerRequestInterface and UploadedFileInterface; a pull request for these features is welcome.
|
||||
|
||||
|
||||
# Stream implementation
|
||||
|
||||
This package comes with a number of stream implementations and stream
|
||||
decorators.
|
||||
|
||||
|
||||
## AppendStream
|
||||
|
||||
`GuzzleHttp\Psr7\AppendStream`
|
||||
|
||||
Reads from multiple streams, one after the other.
|
||||
|
||||
```php
|
||||
use GuzzleHttp\Psr7;
|
||||
|
||||
$a = Psr7\stream_for('abc, ');
|
||||
$b = Psr7\stream_for('123.');
|
||||
$composed = new Psr7\AppendStream([$a, $b]);
|
||||
|
||||
$composed->addStream(Psr7\stream_for(' Above all listen to me').
|
||||
|
||||
echo $composed(); // abc, 123. Above all listen to me.
|
||||
```
|
||||
|
||||
|
||||
## BufferStream
|
||||
|
||||
`GuzzleHttp\Psr7\BufferStream`
|
||||
|
||||
Provides a buffer stream that can be written to to fill a buffer, and read
|
||||
from to remove bytes from the buffer.
|
||||
|
||||
This stream returns a "hwm" metadata value that tells upstream consumers
|
||||
what the configured high water mark of the stream is, or the maximum
|
||||
preferred size of the buffer.
|
||||
|
||||
```php
|
||||
use GuzzleHttp\Psr7;
|
||||
|
||||
// When more than 1024 bytes are in the buffer, it will begin returning
|
||||
// false to writes. This is an indication that writers should slow down.
|
||||
$buffer = new Psr7\BufferStream(1024);
|
||||
```
|
||||
|
||||
|
||||
## CachingStream
|
||||
|
||||
The CachingStream is used to allow seeking over previously read bytes on
|
||||
non-seekable streams. This can be useful when transferring a non-seekable
|
||||
entity body fails due to needing to rewind the stream (for example, resulting
|
||||
from a redirect). Data that is read from the remote stream will be buffered in
|
||||
a PHP temp stream so that previously read bytes are cached first in memory,
|
||||
then on disk.
|
||||
|
||||
```php
|
||||
use GuzzleHttp\Psr7;
|
||||
|
||||
$original = Psr7\stream_for(fopen('http://www.google.com', 'r'));
|
||||
$stream = new Psr7\CachingStream($original);
|
||||
|
||||
$stream->read(1024);
|
||||
echo $stream->tell();
|
||||
// 1024
|
||||
|
||||
$stream->seek(0);
|
||||
echo $stream->tell();
|
||||
// 0
|
||||
```
|
||||
|
||||
|
||||
## DroppingStream
|
||||
|
||||
`GuzzleHttp\Psr7\DroppingStream`
|
||||
|
||||
Stream decorator that begins dropping data once the size of the underlying
|
||||
stream becomes too full.
|
||||
|
||||
```php
|
||||
use GuzzleHttp\Psr7;
|
||||
|
||||
// Create an empty stream
|
||||
$stream = Psr7\stream_for();
|
||||
|
||||
// Start dropping data when the stream has more than 10 bytes
|
||||
$dropping = new Psr7\DroppingStream($stream, 10);
|
||||
|
||||
$stream->write('01234567890123456789');
|
||||
echo $stream; // 0123456789
|
||||
```
|
||||
|
||||
|
||||
## FnStream
|
||||
|
||||
`GuzzleHttp\Psr7\FnStream`
|
||||
|
||||
Compose stream implementations based on a hash of functions.
|
||||
|
||||
Allows for easy testing and extension of a provided stream without needing to
|
||||
to create a concrete class for a simple extension point.
|
||||
|
||||
```php
|
||||
|
||||
use GuzzleHttp\Psr7;
|
||||
|
||||
$stream = Psr7\stream_for('hi');
|
||||
$fnStream = Psr7\FnStream::decorate($stream, [
|
||||
'rewind' => function () use ($stream) {
|
||||
echo 'About to rewind - ';
|
||||
$stream->rewind();
|
||||
echo 'rewound!';
|
||||
}
|
||||
]);
|
||||
|
||||
$fnStream->rewind();
|
||||
// Outputs: About to rewind - rewound!
|
||||
```
|
||||
|
||||
|
||||
## InflateStream
|
||||
|
||||
`GuzzleHttp\Psr7\InflateStream`
|
||||
|
||||
Uses PHP's zlib.inflate filter to inflate deflate or gzipped content.
|
||||
|
||||
This stream decorator skips the first 10 bytes of the given stream to remove
|
||||
the gzip header, converts the provided stream to a PHP stream resource,
|
||||
then appends the zlib.inflate filter. The stream is then converted back
|
||||
to a Guzzle stream resource to be used as a Guzzle stream.
|
||||
|
||||
|
||||
## LazyOpenStream
|
||||
|
||||
`GuzzleHttp\Psr7\LazyOpenStream`
|
||||
|
||||
Lazily reads or writes to a file that is opened only after an IO operation
|
||||
take place on the stream.
|
||||
|
||||
```php
|
||||
use GuzzleHttp\Psr7;
|
||||
|
||||
$stream = new Psr7\LazyOpenStream('/path/to/file', 'r');
|
||||
// The file has not yet been opened...
|
||||
|
||||
echo $stream->read(10);
|
||||
// The file is opened and read from only when needed.
|
||||
```
|
||||
|
||||
|
||||
## LimitStream
|
||||
|
||||
`GuzzleHttp\Psr7\LimitStream`
|
||||
|
||||
LimitStream can be used to read a subset or slice of an existing stream object.
|
||||
This can be useful for breaking a large file into smaller pieces to be sent in
|
||||
chunks (e.g. Amazon S3's multipart upload API).
|
||||
|
||||
```php
|
||||
use GuzzleHttp\Psr7;
|
||||
|
||||
$original = Psr7\stream_for(fopen('/tmp/test.txt', 'r+'));
|
||||
echo $original->getSize();
|
||||
// >>> 1048576
|
||||
|
||||
// Limit the size of the body to 1024 bytes and start reading from byte 2048
|
||||
$stream = new Psr7\LimitStream($original, 1024, 2048);
|
||||
echo $stream->getSize();
|
||||
// >>> 1024
|
||||
echo $stream->tell();
|
||||
// >>> 0
|
||||
```
|
||||
|
||||
|
||||
## MultipartStream
|
||||
|
||||
`GuzzleHttp\Psr7\MultipartStream`
|
||||
|
||||
Stream that when read returns bytes for a streaming multipart or
|
||||
multipart/form-data stream.
|
||||
|
||||
|
||||
## NoSeekStream
|
||||
|
||||
`GuzzleHttp\Psr7\NoSeekStream`
|
||||
|
||||
NoSeekStream wraps a stream and does not allow seeking.
|
||||
|
||||
```php
|
||||
use GuzzleHttp\Psr7;
|
||||
|
||||
$original = Psr7\stream_for('foo');
|
||||
$noSeek = new Psr7\NoSeekStream($original);
|
||||
|
||||
echo $noSeek->read(3);
|
||||
// foo
|
||||
var_export($noSeek->isSeekable());
|
||||
// false
|
||||
$noSeek->seek(0);
|
||||
var_export($noSeek->read(3));
|
||||
// NULL
|
||||
```
|
||||
|
||||
|
||||
## PumpStream
|
||||
|
||||
`GuzzleHttp\Psr7\PumpStream`
|
||||
|
||||
Provides a read only stream that pumps data from a PHP callable.
|
||||
|
||||
When invoking the provided callable, the PumpStream will pass the amount of
|
||||
data requested to read to the callable. The callable can choose to ignore
|
||||
this value and return fewer or more bytes than requested. Any extra data
|
||||
returned by the provided callable is buffered internally until drained using
|
||||
the read() function of the PumpStream. The provided callable MUST return
|
||||
false when there is no more data to read.
|
||||
|
||||
|
||||
## Implementing stream decorators
|
||||
|
||||
Creating a stream decorator is very easy thanks to the
|
||||
`GuzzleHttp\Psr7\StreamDecoratorTrait`. This trait provides methods that
|
||||
implement `Psr\Http\Message\StreamInterface` by proxying to an underlying
|
||||
stream. Just `use` the `StreamDecoratorTrait` and implement your custom
|
||||
methods.
|
||||
|
||||
For example, let's say we wanted to call a specific function each time the last
|
||||
byte is read from a stream. This could be implemented by overriding the
|
||||
`read()` method.
|
||||
|
||||
```php
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
use GuzzleHttp\Psr7\StreamDecoratorTrait;
|
||||
|
||||
class EofCallbackStream implements StreamInterface
|
||||
{
|
||||
use StreamDecoratorTrait;
|
||||
|
||||
private $callback;
|
||||
|
||||
public function __construct(StreamInterface $stream, callable $cb)
|
||||
{
|
||||
$this->stream = $stream;
|
||||
$this->callback = $cb;
|
||||
}
|
||||
|
||||
public function read($length)
|
||||
{
|
||||
$result = $this->stream->read($length);
|
||||
|
||||
// Invoke the callback when EOF is hit.
|
||||
if ($this->eof()) {
|
||||
call_user_func($this->callback);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
This decorator could be added to any existing stream and used like so:
|
||||
|
||||
```php
|
||||
use GuzzleHttp\Psr7;
|
||||
|
||||
$original = Psr7\stream_for('foo');
|
||||
|
||||
$eofStream = new EofCallbackStream($original, function () {
|
||||
echo 'EOF!';
|
||||
});
|
||||
|
||||
$eofStream->read(2);
|
||||
$eofStream->read(1);
|
||||
// echoes "EOF!"
|
||||
$eofStream->seek(0);
|
||||
$eofStream->read(3);
|
||||
// echoes "EOF!"
|
||||
```
|
||||
|
||||
|
||||
## PHP StreamWrapper
|
||||
|
||||
You can use the `GuzzleHttp\Psr7\StreamWrapper` class if you need to use a
|
||||
PSR-7 stream as a PHP stream resource.
|
||||
|
||||
Use the `GuzzleHttp\Psr7\StreamWrapper::getResource()` method to create a PHP
|
||||
stream from a PSR-7 stream.
|
||||
|
||||
```php
|
||||
use GuzzleHttp\Psr7\StreamWrapper;
|
||||
|
||||
$stream = GuzzleHttp\Psr7\stream_for('hello!');
|
||||
$resource = StreamWrapper::getResource($stream);
|
||||
echo fread($resource, 6); // outputs hello!
|
||||
```
|
||||
|
||||
|
||||
# Function API
|
||||
|
||||
There are various functions available under the `GuzzleHttp\Psr7` namespace.
|
||||
|
||||
|
||||
## `function str`
|
||||
|
||||
`function str(MessageInterface $message)`
|
||||
|
||||
Returns the string representation of an HTTP message.
|
||||
|
||||
```php
|
||||
$request = new GuzzleHttp\Psr7\Request('GET', 'http://example.com');
|
||||
echo GuzzleHttp\Psr7\str($request);
|
||||
```
|
||||
|
||||
|
||||
## `function uri_for`
|
||||
|
||||
`function uri_for($uri)`
|
||||
|
||||
This function accepts a string or `Psr\Http\Message\UriInterface` and returns a
|
||||
UriInterface for the given value. If the value is already a `UriInterface`, it
|
||||
is returned as-is.
|
||||
|
||||
```php
|
||||
$uri = GuzzleHttp\Psr7\uri_for('http://example.com');
|
||||
assert($uri === GuzzleHttp\Psr7\uri_for($uri));
|
||||
```
|
||||
|
||||
|
||||
## `function stream_for`
|
||||
|
||||
`function stream_for($resource = '', array $options = [])`
|
||||
|
||||
Create a new stream based on the input type.
|
||||
|
||||
Options is an associative array that can contain the following keys:
|
||||
|
||||
* - metadata: Array of custom metadata.
|
||||
* - size: Size of the stream.
|
||||
|
||||
This method accepts the following `$resource` types:
|
||||
|
||||
- `Psr\Http\Message\StreamInterface`: Returns the value as-is.
|
||||
- `string`: Creates a stream object that uses the given string as the contents.
|
||||
- `resource`: Creates a stream object that wraps the given PHP stream resource.
|
||||
- `Iterator`: If the provided value implements `Iterator`, then a read-only
|
||||
stream object will be created that wraps the given iterable. Each time the
|
||||
stream is read from, data from the iterator will fill a buffer and will be
|
||||
continuously called until the buffer is equal to the requested read size.
|
||||
Subsequent read calls will first read from the buffer and then call `next`
|
||||
on the underlying iterator until it is exhausted.
|
||||
- `object` with `__toString()`: If the object has the `__toString()` method,
|
||||
the object will be cast to a string and then a stream will be returned that
|
||||
uses the string value.
|
||||
- `NULL`: When `null` is passed, an empty stream object is returned.
|
||||
- `callable` When a callable is passed, a read-only stream object will be
|
||||
created that invokes the given callable. The callable is invoked with the
|
||||
number of suggested bytes to read. The callable can return any number of
|
||||
bytes, but MUST return `false` when there is no more data to return. The
|
||||
stream object that wraps the callable will invoke the callable until the
|
||||
number of requested bytes are available. Any additional bytes will be
|
||||
buffered and used in subsequent reads.
|
||||
|
||||
```php
|
||||
$stream = GuzzleHttp\Psr7\stream_for('foo');
|
||||
$stream = GuzzleHttp\Psr7\stream_for(fopen('/path/to/file', 'r'));
|
||||
|
||||
$generator function ($bytes) {
|
||||
for ($i = 0; $i < $bytes; $i++) {
|
||||
yield ' ';
|
||||
}
|
||||
}
|
||||
|
||||
$stream = GuzzleHttp\Psr7\stream_for($generator(100));
|
||||
```
|
||||
|
||||
|
||||
## `function parse_header`
|
||||
|
||||
`function parse_header($header)`
|
||||
|
||||
Parse an array of header values containing ";" separated data into an array of
|
||||
associative arrays representing the header key value pair data of the header.
|
||||
When a parameter does not contain a value, but just contains a key, this
|
||||
function will inject a key with a '' string value.
|
||||
|
||||
|
||||
## `function normalize_header`
|
||||
|
||||
`function normalize_header($header)`
|
||||
|
||||
Converts an array of header values that may contain comma separated headers
|
||||
into an array of headers with no comma separated values.
|
||||
|
||||
|
||||
## `function modify_request`
|
||||
|
||||
`function modify_request(RequestInterface $request, array $changes)`
|
||||
|
||||
Clone and modify a request with the given changes. This method is useful for
|
||||
reducing the number of clones needed to mutate a message.
|
||||
|
||||
The changes can be one of:
|
||||
|
||||
- method: (string) Changes the HTTP method.
|
||||
- set_headers: (array) Sets the given headers.
|
||||
- remove_headers: (array) Remove the given headers.
|
||||
- body: (mixed) Sets the given body.
|
||||
- uri: (UriInterface) Set the URI.
|
||||
- query: (string) Set the query string value of the URI.
|
||||
- version: (string) Set the protocol version.
|
||||
|
||||
|
||||
## `function rewind_body`
|
||||
|
||||
`function rewind_body(MessageInterface $message)`
|
||||
|
||||
Attempts to rewind a message body and throws an exception on failure. The body
|
||||
of the message will only be rewound if a call to `tell()` returns a value other
|
||||
than `0`.
|
||||
|
||||
|
||||
## `function try_fopen`
|
||||
|
||||
`function try_fopen($filename, $mode)`
|
||||
|
||||
Safely opens a PHP stream resource using a filename.
|
||||
|
||||
When fopen fails, PHP normally raises a warning. This function adds an error
|
||||
handler that checks for errors and throws an exception instead.
|
||||
|
||||
|
||||
## `function copy_to_string`
|
||||
|
||||
`function copy_to_string(StreamInterface $stream, $maxLen = -1)`
|
||||
|
||||
Copy the contents of a stream into a string until the given number of bytes
|
||||
have been read.
|
||||
|
||||
|
||||
## `function copy_to_stream`
|
||||
|
||||
`function copy_to_stream(StreamInterface $source, StreamInterface $dest, $maxLen = -1)`
|
||||
|
||||
Copy the contents of a stream into another stream until the given number of
|
||||
bytes have been read.
|
||||
|
||||
|
||||
## `function hash`
|
||||
|
||||
`function hash(StreamInterface $stream, $algo, $rawOutput = false)`
|
||||
|
||||
Calculate a hash of a Stream. This method reads the entire stream to calculate
|
||||
a rolling hash (based on PHP's hash_init functions).
|
||||
|
||||
|
||||
## `function readline`
|
||||
|
||||
`function readline(StreamInterface $stream, $maxLength = null)`
|
||||
|
||||
Read a line from the stream up to the maximum allowed buffer length.
|
||||
|
||||
|
||||
## `function parse_request`
|
||||
|
||||
`function parse_request($message)`
|
||||
|
||||
Parses a request message string into a request object.
|
||||
|
||||
|
||||
## `function parse_response`
|
||||
|
||||
`function parse_response($message)`
|
||||
|
||||
Parses a response message string into a response object.
|
||||
|
||||
|
||||
## `function parse_query`
|
||||
|
||||
`function parse_query($str, $urlEncoding = true)`
|
||||
|
||||
Parse a query string into an associative array.
|
||||
|
||||
If multiple values are found for the same key, the value of that key value pair
|
||||
will become an array. This function does not parse nested PHP style arrays into
|
||||
an associative array (e.g., `foo[a]=1&foo[b]=2` will be parsed into
|
||||
`['foo[a]' => '1', 'foo[b]' => '2']`).
|
||||
|
||||
|
||||
## `function build_query`
|
||||
|
||||
`function build_query(array $params, $encoding = PHP_QUERY_RFC3986)`
|
||||
|
||||
Build a query string from an array of key value pairs.
|
||||
|
||||
This function can use the return value of parseQuery() to build a query string.
|
||||
This function does not modify the provided keys when an array is encountered
|
||||
(like http_build_query would).
|
||||
|
||||
|
||||
## `function mimetype_from_filename`
|
||||
|
||||
`function mimetype_from_filename($filename)`
|
||||
|
||||
Determines the mimetype of a file by looking at its extension.
|
||||
|
||||
|
||||
## `function mimetype_from_extension`
|
||||
|
||||
`function mimetype_from_extension($extension)`
|
||||
|
||||
Maps a file extensions to a mimetype.
|
||||
|
||||
|
||||
# Static URI methods
|
||||
|
||||
The `GuzzleHttp\Psr7\Uri` class has several static methods to manipulate URIs.
|
||||
|
||||
|
||||
## `GuzzleHttp\Psr7\Uri::removeDotSegments`
|
||||
|
||||
`public static function removeDotSegments($path) -> UriInterface`
|
||||
|
||||
Removes dot segments from a path and returns the new path.
|
||||
|
||||
See http://tools.ietf.org/html/rfc3986#section-5.2.4
|
||||
|
||||
|
||||
## `GuzzleHttp\Psr7\Uri::resolve`
|
||||
|
||||
`public static function resolve(UriInterface $base, $rel) -> UriInterface`
|
||||
|
||||
Resolve a base URI with a relative URI and return a new URI.
|
||||
|
||||
See http://tools.ietf.org/html/rfc3986#section-5
|
||||
|
||||
|
||||
## `GuzzleHttp\Psr7\Uri::withQueryValue`
|
||||
|
||||
`public static function withQueryValue(UriInterface $uri, $key, $value) -> UriInterface`
|
||||
|
||||
Create a new URI with a specific query string value.
|
||||
|
||||
Any existing query string values that exactly match the provided key are
|
||||
removed and replaced with the given key value pair.
|
||||
|
||||
Note: this function will convert "=" to "%3D" and "&" to "%26".
|
||||
|
||||
|
||||
## `GuzzleHttp\Psr7\Uri::withoutQueryValue`
|
||||
|
||||
`public static function withoutQueryValue(UriInterface $uri, $key, $value) -> UriInterface`
|
||||
|
||||
Create a new URI with a specific query string value removed.
|
||||
|
||||
Any existing query string values that exactly match the provided key are
|
||||
removed.
|
||||
|
||||
Note: this function will convert "=" to "%3D" and "&" to "%26".
|
||||
|
||||
|
||||
## `GuzzleHttp\Psr7\Uri::fromParts`
|
||||
|
||||
`public static function fromParts(array $parts) -> UriInterface`
|
||||
|
||||
Create a `GuzzleHttp\Psr7\Uri` object from a hash of `parse_url` parts.
|
||||
|
||||
|
||||
# Not Implemented
|
||||
|
||||
A few aspects of PSR-7 are not implemented in this project. A pull request for
|
||||
any of these features is welcome:
|
||||
|
||||
- `Psr\Http\Message\ServerRequestInterface`
|
||||
- `Psr\Http\Message\UploadedFileInterface`
|
35
server/vendor/guzzlehttp/psr7/composer.json
vendored
Normal file
35
server/vendor/guzzlehttp/psr7/composer.json
vendored
Normal file
|
@ -0,0 +1,35 @@
|
|||
{
|
||||
"name": "guzzlehttp/psr7",
|
||||
"type": "library",
|
||||
"description": "PSR-7 message implementation",
|
||||
"keywords": ["message", "stream", "http", "uri"],
|
||||
"license": "MIT",
|
||||
"authors": [
|
||||
{
|
||||
"name": "Michael Dowling",
|
||||
"email": "mtdowling@gmail.com",
|
||||
"homepage": "https://github.com/mtdowling"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=5.4.0",
|
||||
"psr/http-message": "~1.0"
|
||||
},
|
||||
"require-dev": {
|
||||
"phpunit/phpunit": "~4.0"
|
||||
},
|
||||
"provide": {
|
||||
"psr/http-message-implementation": "1.0"
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"GuzzleHttp\\Psr7\\": "src/"
|
||||
},
|
||||
"files": ["src/functions_include.php"]
|
||||
},
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "1.0-dev"
|
||||
}
|
||||
}
|
||||
}
|
17
server/vendor/guzzlehttp/psr7/phpunit.xml.dist
vendored
Normal file
17
server/vendor/guzzlehttp/psr7/phpunit.xml.dist
vendored
Normal file
|
@ -0,0 +1,17 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phpunit bootstrap="./tests/bootstrap.php"
|
||||
colors="true">
|
||||
<testsuites>
|
||||
<testsuite>
|
||||
<directory>tests</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
<filter>
|
||||
<whitelist>
|
||||
<directory suffix=".php">src</directory>
|
||||
<exclude>
|
||||
<directory suffix="Interface.php">src/</directory>
|
||||
</exclude>
|
||||
</whitelist>
|
||||
</filter>
|
||||
</phpunit>
|
233
server/vendor/guzzlehttp/psr7/src/AppendStream.php
vendored
Normal file
233
server/vendor/guzzlehttp/psr7/src/AppendStream.php
vendored
Normal file
|
@ -0,0 +1,233 @@
|
|||
<?php
|
||||
namespace GuzzleHttp\Psr7;
|
||||
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
|
||||
/**
|
||||
* Reads from multiple streams, one after the other.
|
||||
*
|
||||
* This is a read-only stream decorator.
|
||||
*/
|
||||
class AppendStream implements StreamInterface
|
||||
{
|
||||
/** @var StreamInterface[] Streams being decorated */
|
||||
private $streams = [];
|
||||
|
||||
private $seekable = true;
|
||||
private $current = 0;
|
||||
private $pos = 0;
|
||||
private $detached = false;
|
||||
|
||||
/**
|
||||
* @param StreamInterface[] $streams Streams to decorate. Each stream must
|
||||
* be readable.
|
||||
*/
|
||||
public function __construct(array $streams = [])
|
||||
{
|
||||
foreach ($streams as $stream) {
|
||||
$this->addStream($stream);
|
||||
}
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
try {
|
||||
$this->rewind();
|
||||
return $this->getContents();
|
||||
} catch (\Exception $e) {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a stream to the AppendStream
|
||||
*
|
||||
* @param StreamInterface $stream Stream to append. Must be readable.
|
||||
*
|
||||
* @throws \InvalidArgumentException if the stream is not readable
|
||||
*/
|
||||
public function addStream(StreamInterface $stream)
|
||||
{
|
||||
if (!$stream->isReadable()) {
|
||||
throw new \InvalidArgumentException('Each stream must be readable');
|
||||
}
|
||||
|
||||
// The stream is only seekable if all streams are seekable
|
||||
if (!$stream->isSeekable()) {
|
||||
$this->seekable = false;
|
||||
}
|
||||
|
||||
$this->streams[] = $stream;
|
||||
}
|
||||
|
||||
public function getContents()
|
||||
{
|
||||
return copy_to_string($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes each attached stream.
|
||||
*
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function close()
|
||||
{
|
||||
$this->pos = $this->current = 0;
|
||||
|
||||
foreach ($this->streams as $stream) {
|
||||
$stream->close();
|
||||
}
|
||||
|
||||
$this->streams = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Detaches each attached stream
|
||||
*
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function detach()
|
||||
{
|
||||
$this->close();
|
||||
$this->detached = true;
|
||||
}
|
||||
|
||||
public function tell()
|
||||
{
|
||||
return $this->pos;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to calculate the size by adding the size of each stream.
|
||||
*
|
||||
* If any of the streams do not return a valid number, then the size of the
|
||||
* append stream cannot be determined and null is returned.
|
||||
*
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getSize()
|
||||
{
|
||||
$size = 0;
|
||||
|
||||
foreach ($this->streams as $stream) {
|
||||
$s = $stream->getSize();
|
||||
if ($s === null) {
|
||||
return null;
|
||||
}
|
||||
$size += $s;
|
||||
}
|
||||
|
||||
return $size;
|
||||
}
|
||||
|
||||
public function eof()
|
||||
{
|
||||
return !$this->streams ||
|
||||
($this->current >= count($this->streams) - 1 &&
|
||||
$this->streams[$this->current]->eof());
|
||||
}
|
||||
|
||||
public function rewind()
|
||||
{
|
||||
$this->seek(0);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to seek to the given position. Only supports SEEK_SET.
|
||||
*
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function seek($offset, $whence = SEEK_SET)
|
||||
{
|
||||
if (!$this->seekable) {
|
||||
throw new \RuntimeException('This AppendStream is not seekable');
|
||||
} elseif ($whence !== SEEK_SET) {
|
||||
throw new \RuntimeException('The AppendStream can only seek with SEEK_SET');
|
||||
}
|
||||
|
||||
$this->pos = $this->current = 0;
|
||||
|
||||
// Rewind each stream
|
||||
foreach ($this->streams as $i => $stream) {
|
||||
try {
|
||||
$stream->rewind();
|
||||
} catch (\Exception $e) {
|
||||
throw new \RuntimeException('Unable to seek stream '
|
||||
. $i . ' of the AppendStream', 0, $e);
|
||||
}
|
||||
}
|
||||
|
||||
// Seek to the actual position by reading from each stream
|
||||
while ($this->pos < $offset && !$this->eof()) {
|
||||
$result = $this->read(min(8096, $offset - $this->pos));
|
||||
if ($result === '') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads from all of the appended streams until the length is met or EOF.
|
||||
*
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function read($length)
|
||||
{
|
||||
$buffer = '';
|
||||
$total = count($this->streams) - 1;
|
||||
$remaining = $length;
|
||||
$progressToNext = false;
|
||||
|
||||
while ($remaining > 0) {
|
||||
|
||||
// Progress to the next stream if needed.
|
||||
if ($progressToNext || $this->streams[$this->current]->eof()) {
|
||||
$progressToNext = false;
|
||||
if ($this->current === $total) {
|
||||
break;
|
||||
}
|
||||
$this->current++;
|
||||
}
|
||||
|
||||
$result = $this->streams[$this->current]->read($remaining);
|
||||
|
||||
// Using a loose comparison here to match on '', false, and null
|
||||
if ($result == null) {
|
||||
$progressToNext = true;
|
||||
continue;
|
||||
}
|
||||
|
||||
$buffer .= $result;
|
||||
$remaining = $length - strlen($buffer);
|
||||
}
|
||||
|
||||
$this->pos += strlen($buffer);
|
||||
|
||||
return $buffer;
|
||||
}
|
||||
|
||||
public function isReadable()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function isWritable()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function isSeekable()
|
||||
{
|
||||
return $this->seekable;
|
||||
}
|
||||
|
||||
public function write($string)
|
||||
{
|
||||
throw new \RuntimeException('Cannot write to an AppendStream');
|
||||
}
|
||||
|
||||
public function getMetadata($key = null)
|
||||
{
|
||||
return $key ? null : [];
|
||||
}
|
||||
}
|
137
server/vendor/guzzlehttp/psr7/src/BufferStream.php
vendored
Normal file
137
server/vendor/guzzlehttp/psr7/src/BufferStream.php
vendored
Normal file
|
@ -0,0 +1,137 @@
|
|||
<?php
|
||||
namespace GuzzleHttp\Psr7;
|
||||
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
|
||||
/**
|
||||
* Provides a buffer stream that can be written to to fill a buffer, and read
|
||||
* from to remove bytes from the buffer.
|
||||
*
|
||||
* This stream returns a "hwm" metadata value that tells upstream consumers
|
||||
* what the configured high water mark of the stream is, or the maximum
|
||||
* preferred size of the buffer.
|
||||
*/
|
||||
class BufferStream implements StreamInterface
|
||||
{
|
||||
private $hwm;
|
||||
private $buffer = '';
|
||||
|
||||
/**
|
||||
* @param int $hwm High water mark, representing the preferred maximum
|
||||
* buffer size. If the size of the buffer exceeds the high
|
||||
* water mark, then calls to write will continue to succeed
|
||||
* but will return false to inform writers to slow down
|
||||
* until the buffer has been drained by reading from it.
|
||||
*/
|
||||
public function __construct($hwm = 16384)
|
||||
{
|
||||
$this->hwm = $hwm;
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
return $this->getContents();
|
||||
}
|
||||
|
||||
public function getContents()
|
||||
{
|
||||
$buffer = $this->buffer;
|
||||
$this->buffer = '';
|
||||
|
||||
return $buffer;
|
||||
}
|
||||
|
||||
public function close()
|
||||
{
|
||||
$this->buffer = '';
|
||||
}
|
||||
|
||||
public function detach()
|
||||
{
|
||||
$this->close();
|
||||
}
|
||||
|
||||
public function getSize()
|
||||
{
|
||||
return strlen($this->buffer);
|
||||
}
|
||||
|
||||
public function isReadable()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function isWritable()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function isSeekable()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function rewind()
|
||||
{
|
||||
$this->seek(0);
|
||||
}
|
||||
|
||||
public function seek($offset, $whence = SEEK_SET)
|
||||
{
|
||||
throw new \RuntimeException('Cannot seek a BufferStream');
|
||||
}
|
||||
|
||||
public function eof()
|
||||
{
|
||||
return strlen($this->buffer) === 0;
|
||||
}
|
||||
|
||||
public function tell()
|
||||
{
|
||||
throw new \RuntimeException('Cannot determine the position of a BufferStream');
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads data from the buffer.
|
||||
*/
|
||||
public function read($length)
|
||||
{
|
||||
$currentLength = strlen($this->buffer);
|
||||
|
||||
if ($length >= $currentLength) {
|
||||
// No need to slice the buffer because we don't have enough data.
|
||||
$result = $this->buffer;
|
||||
$this->buffer = '';
|
||||
} else {
|
||||
// Slice up the result to provide a subset of the buffer.
|
||||
$result = substr($this->buffer, 0, $length);
|
||||
$this->buffer = substr($this->buffer, $length);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes data to the buffer.
|
||||
*/
|
||||
public function write($string)
|
||||
{
|
||||
$this->buffer .= $string;
|
||||
|
||||
// TODO: What should happen here?
|
||||
if (strlen($this->buffer) >= $this->hwm) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return strlen($string);
|
||||
}
|
||||
|
||||
public function getMetadata($key = null)
|
||||
{
|
||||
if ($key == 'hwm') {
|
||||
return $this->hwm;
|
||||
}
|
||||
|
||||
return $key ? null : [];
|
||||
}
|
||||
}
|
135
server/vendor/guzzlehttp/psr7/src/CachingStream.php
vendored
Normal file
135
server/vendor/guzzlehttp/psr7/src/CachingStream.php
vendored
Normal file
|
@ -0,0 +1,135 @@
|
|||
<?php
|
||||
namespace GuzzleHttp\Psr7;
|
||||
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
|
||||
/**
|
||||
* Stream decorator that can cache previously read bytes from a sequentially
|
||||
* read stream.
|
||||
*/
|
||||
class CachingStream implements StreamInterface
|
||||
{
|
||||
use StreamDecoratorTrait;
|
||||
|
||||
/** @var StreamInterface Stream being wrapped */
|
||||
private $remoteStream;
|
||||
|
||||
/** @var int Number of bytes to skip reading due to a write on the buffer */
|
||||
private $skipReadBytes = 0;
|
||||
|
||||
/**
|
||||
* We will treat the buffer object as the body of the stream
|
||||
*
|
||||
* @param StreamInterface $stream Stream to cache
|
||||
* @param StreamInterface $target Optionally specify where data is cached
|
||||
*/
|
||||
public function __construct(
|
||||
StreamInterface $stream,
|
||||
StreamInterface $target = null
|
||||
) {
|
||||
$this->remoteStream = $stream;
|
||||
$this->stream = $target ?: new Stream(fopen('php://temp', 'r+'));
|
||||
}
|
||||
|
||||
public function getSize()
|
||||
{
|
||||
return max($this->stream->getSize(), $this->remoteStream->getSize());
|
||||
}
|
||||
|
||||
public function rewind()
|
||||
{
|
||||
$this->seek(0);
|
||||
}
|
||||
|
||||
public function seek($offset, $whence = SEEK_SET)
|
||||
{
|
||||
if ($whence == SEEK_SET) {
|
||||
$byte = $offset;
|
||||
} elseif ($whence == SEEK_CUR) {
|
||||
$byte = $offset + $this->tell();
|
||||
} elseif ($whence == SEEK_END) {
|
||||
$size = $this->remoteStream->getSize();
|
||||
if ($size === null) {
|
||||
$size = $this->cacheEntireStream();
|
||||
}
|
||||
$byte = $size + $offset;
|
||||
} else {
|
||||
throw new \InvalidArgumentException('Invalid whence');
|
||||
}
|
||||
|
||||
$diff = $byte - $this->stream->getSize();
|
||||
|
||||
if ($diff > 0) {
|
||||
// If the seek byte is greater the number of read bytes, then read
|
||||
// the difference of bytes to cache the bytes and inherently seek.
|
||||
$this->read($diff);
|
||||
} else {
|
||||
// We can just do a normal seek since we've already seen this byte.
|
||||
$this->stream->seek($byte);
|
||||
}
|
||||
}
|
||||
|
||||
public function read($length)
|
||||
{
|
||||
// Perform a regular read on any previously read data from the buffer
|
||||
$data = $this->stream->read($length);
|
||||
$remaining = $length - strlen($data);
|
||||
|
||||
// More data was requested so read from the remote stream
|
||||
if ($remaining) {
|
||||
// If data was written to the buffer in a position that would have
|
||||
// been filled from the remote stream, then we must skip bytes on
|
||||
// the remote stream to emulate overwriting bytes from that
|
||||
// position. This mimics the behavior of other PHP stream wrappers.
|
||||
$remoteData = $this->remoteStream->read(
|
||||
$remaining + $this->skipReadBytes
|
||||
);
|
||||
|
||||
if ($this->skipReadBytes) {
|
||||
$len = strlen($remoteData);
|
||||
$remoteData = substr($remoteData, $this->skipReadBytes);
|
||||
$this->skipReadBytes = max(0, $this->skipReadBytes - $len);
|
||||
}
|
||||
|
||||
$data .= $remoteData;
|
||||
$this->stream->write($remoteData);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function write($string)
|
||||
{
|
||||
// When appending to the end of the currently read stream, you'll want
|
||||
// to skip bytes from being read from the remote stream to emulate
|
||||
// other stream wrappers. Basically replacing bytes of data of a fixed
|
||||
// length.
|
||||
$overflow = (strlen($string) + $this->tell()) - $this->remoteStream->tell();
|
||||
if ($overflow > 0) {
|
||||
$this->skipReadBytes += $overflow;
|
||||
}
|
||||
|
||||
return $this->stream->write($string);
|
||||
}
|
||||
|
||||
public function eof()
|
||||
{
|
||||
return $this->stream->eof() && $this->remoteStream->eof();
|
||||
}
|
||||
|
||||
/**
|
||||
* Close both the remote stream and buffer stream
|
||||
*/
|
||||
public function close()
|
||||
{
|
||||
$this->remoteStream->close() && $this->stream->close();
|
||||
}
|
||||
|
||||
private function cacheEntireStream()
|
||||
{
|
||||
$target = new FnStream(['write' => 'strlen']);
|
||||
copy_to_stream($this, $target);
|
||||
|
||||
return $this->tell();
|
||||
}
|
||||
}
|
42
server/vendor/guzzlehttp/psr7/src/DroppingStream.php
vendored
Normal file
42
server/vendor/guzzlehttp/psr7/src/DroppingStream.php
vendored
Normal file
|
@ -0,0 +1,42 @@
|
|||
<?php
|
||||
namespace GuzzleHttp\Psr7;
|
||||
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
|
||||
/**
|
||||
* Stream decorator that begins dropping data once the size of the underlying
|
||||
* stream becomes too full.
|
||||
*/
|
||||
class DroppingStream implements StreamInterface
|
||||
{
|
||||
use StreamDecoratorTrait;
|
||||
|
||||
private $maxLength;
|
||||
|
||||
/**
|
||||
* @param StreamInterface $stream Underlying stream to decorate.
|
||||
* @param int $maxLength Maximum size before dropping data.
|
||||
*/
|
||||
public function __construct(StreamInterface $stream, $maxLength)
|
||||
{
|
||||
$this->stream = $stream;
|
||||
$this->maxLength = $maxLength;
|
||||
}
|
||||
|
||||
public function write($string)
|
||||
{
|
||||
$diff = $this->maxLength - $this->stream->getSize();
|
||||
|
||||
// Begin returning 0 when the underlying stream is too large.
|
||||
if ($diff <= 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
// Write the stream or a subset of the stream if needed.
|
||||
if (strlen($string) < $diff) {
|
||||
return $this->stream->write($string);
|
||||
}
|
||||
|
||||
return $this->stream->write(substr($string, 0, $diff));
|
||||
}
|
||||
}
|
149
server/vendor/guzzlehttp/psr7/src/FnStream.php
vendored
Normal file
149
server/vendor/guzzlehttp/psr7/src/FnStream.php
vendored
Normal file
|
@ -0,0 +1,149 @@
|
|||
<?php
|
||||
namespace GuzzleHttp\Psr7;
|
||||
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
|
||||
/**
|
||||
* Compose stream implementations based on a hash of functions.
|
||||
*
|
||||
* Allows for easy testing and extension of a provided stream without needing
|
||||
* to create a concrete class for a simple extension point.
|
||||
*/
|
||||
class FnStream implements StreamInterface
|
||||
{
|
||||
/** @var array */
|
||||
private $methods;
|
||||
|
||||
/** @var array Methods that must be implemented in the given array */
|
||||
private static $slots = ['__toString', 'close', 'detach', 'rewind',
|
||||
'getSize', 'tell', 'eof', 'isSeekable', 'seek', 'isWritable', 'write',
|
||||
'isReadable', 'read', 'getContents', 'getMetadata'];
|
||||
|
||||
/**
|
||||
* @param array $methods Hash of method name to a callable.
|
||||
*/
|
||||
public function __construct(array $methods)
|
||||
{
|
||||
$this->methods = $methods;
|
||||
|
||||
// Create the functions on the class
|
||||
foreach ($methods as $name => $fn) {
|
||||
$this->{'_fn_' . $name} = $fn;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Lazily determine which methods are not implemented.
|
||||
* @throws \BadMethodCallException
|
||||
*/
|
||||
public function __get($name)
|
||||
{
|
||||
throw new \BadMethodCallException(str_replace('_fn_', '', $name)
|
||||
. '() is not implemented in the FnStream');
|
||||
}
|
||||
|
||||
/**
|
||||
* The close method is called on the underlying stream only if possible.
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
if (isset($this->_fn_close)) {
|
||||
call_user_func($this->_fn_close);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds custom functionality to an underlying stream by intercepting
|
||||
* specific method calls.
|
||||
*
|
||||
* @param StreamInterface $stream Stream to decorate
|
||||
* @param array $methods Hash of method name to a closure
|
||||
*
|
||||
* @return FnStream
|
||||
*/
|
||||
public static function decorate(StreamInterface $stream, array $methods)
|
||||
{
|
||||
// If any of the required methods were not provided, then simply
|
||||
// proxy to the decorated stream.
|
||||
foreach (array_diff(self::$slots, array_keys($methods)) as $diff) {
|
||||
$methods[$diff] = [$stream, $diff];
|
||||
}
|
||||
|
||||
return new self($methods);
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
return call_user_func($this->_fn___toString);
|
||||
}
|
||||
|
||||
public function close()
|
||||
{
|
||||
return call_user_func($this->_fn_close);
|
||||
}
|
||||
|
||||
public function detach()
|
||||
{
|
||||
return call_user_func($this->_fn_detach);
|
||||
}
|
||||
|
||||
public function getSize()
|
||||
{
|
||||
return call_user_func($this->_fn_getSize);
|
||||
}
|
||||
|
||||
public function tell()
|
||||
{
|
||||
return call_user_func($this->_fn_tell);
|
||||
}
|
||||
|
||||
public function eof()
|
||||
{
|
||||
return call_user_func($this->_fn_eof);
|
||||
}
|
||||
|
||||
public function isSeekable()
|
||||
{
|
||||
return call_user_func($this->_fn_isSeekable);
|
||||
}
|
||||
|
||||
public function rewind()
|
||||
{
|
||||
call_user_func($this->_fn_rewind);
|
||||
}
|
||||
|
||||
public function seek($offset, $whence = SEEK_SET)
|
||||
{
|
||||
call_user_func($this->_fn_seek, $offset, $whence);
|
||||
}
|
||||
|
||||
public function isWritable()
|
||||
{
|
||||
return call_user_func($this->_fn_isWritable);
|
||||
}
|
||||
|
||||
public function write($string)
|
||||
{
|
||||
return call_user_func($this->_fn_write, $string);
|
||||
}
|
||||
|
||||
public function isReadable()
|
||||
{
|
||||
return call_user_func($this->_fn_isReadable);
|
||||
}
|
||||
|
||||
public function read($length)
|
||||
{
|
||||
return call_user_func($this->_fn_read, $length);
|
||||
}
|
||||
|
||||
public function getContents()
|
||||
{
|
||||
return call_user_func($this->_fn_getContents);
|
||||
}
|
||||
|
||||
public function getMetadata($key = null)
|
||||
{
|
||||
return call_user_func($this->_fn_getMetadata, $key);
|
||||
}
|
||||
}
|
29
server/vendor/guzzlehttp/psr7/src/InflateStream.php
vendored
Normal file
29
server/vendor/guzzlehttp/psr7/src/InflateStream.php
vendored
Normal file
|
@ -0,0 +1,29 @@
|
|||
<?php
|
||||
namespace GuzzleHttp\Psr7;
|
||||
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
|
||||
/**
|
||||
* Uses PHP's zlib.inflate filter to inflate deflate or gzipped content.
|
||||
*
|
||||
* This stream decorator skips the first 10 bytes of the given stream to remove
|
||||
* the gzip header, converts the provided stream to a PHP stream resource,
|
||||
* then appends the zlib.inflate filter. The stream is then converted back
|
||||
* to a Guzzle stream resource to be used as a Guzzle stream.
|
||||
*
|
||||
* @link http://tools.ietf.org/html/rfc1952
|
||||
* @link http://php.net/manual/en/filters.compression.php
|
||||
*/
|
||||
class InflateStream implements StreamInterface
|
||||
{
|
||||
use StreamDecoratorTrait;
|
||||
|
||||
public function __construct(StreamInterface $stream)
|
||||
{
|
||||
// Skip the first 10 bytes
|
||||
$stream = new LimitStream($stream, -1, 10);
|
||||
$resource = StreamWrapper::getResource($stream);
|
||||
stream_filter_append($resource, 'zlib.inflate', STREAM_FILTER_READ);
|
||||
$this->stream = new Stream($resource);
|
||||
}
|
||||
}
|
39
server/vendor/guzzlehttp/psr7/src/LazyOpenStream.php
vendored
Normal file
39
server/vendor/guzzlehttp/psr7/src/LazyOpenStream.php
vendored
Normal file
|
@ -0,0 +1,39 @@
|
|||
<?php
|
||||
namespace GuzzleHttp\Psr7;
|
||||
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
|
||||
/**
|
||||
* Lazily reads or writes to a file that is opened only after an IO operation
|
||||
* take place on the stream.
|
||||
*/
|
||||
class LazyOpenStream implements StreamInterface
|
||||
{
|
||||
use StreamDecoratorTrait;
|
||||
|
||||
/** @var string File to open */
|
||||
private $filename;
|
||||
|
||||
/** @var string $mode */
|
||||
private $mode;
|
||||
|
||||
/**
|
||||
* @param string $filename File to lazily open
|
||||
* @param string $mode fopen mode to use when opening the stream
|
||||
*/
|
||||
public function __construct($filename, $mode)
|
||||
{
|
||||
$this->filename = $filename;
|
||||
$this->mode = $mode;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates the underlying stream lazily when required.
|
||||
*
|
||||
* @return StreamInterface
|
||||
*/
|
||||
protected function createStream()
|
||||
{
|
||||
return stream_for(try_fopen($this->filename, $this->mode));
|
||||
}
|
||||
}
|
155
server/vendor/guzzlehttp/psr7/src/LimitStream.php
vendored
Normal file
155
server/vendor/guzzlehttp/psr7/src/LimitStream.php
vendored
Normal file
|
@ -0,0 +1,155 @@
|
|||
<?php
|
||||
namespace GuzzleHttp\Psr7;
|
||||
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
|
||||
|
||||
/**
|
||||
* Decorator used to return only a subset of a stream
|
||||
*/
|
||||
class LimitStream implements StreamInterface
|
||||
{
|
||||
use StreamDecoratorTrait;
|
||||
|
||||
/** @var int Offset to start reading from */
|
||||
private $offset;
|
||||
|
||||
/** @var int Limit the number of bytes that can be read */
|
||||
private $limit;
|
||||
|
||||
/**
|
||||
* @param StreamInterface $stream Stream to wrap
|
||||
* @param int $limit Total number of bytes to allow to be read
|
||||
* from the stream. Pass -1 for no limit.
|
||||
* @param int|null $offset Position to seek to before reading (only
|
||||
* works on seekable streams).
|
||||
*/
|
||||
public function __construct(
|
||||
StreamInterface $stream,
|
||||
$limit = -1,
|
||||
$offset = 0
|
||||
) {
|
||||
$this->stream = $stream;
|
||||
$this->setLimit($limit);
|
||||
$this->setOffset($offset);
|
||||
}
|
||||
|
||||
public function eof()
|
||||
{
|
||||
// Always return true if the underlying stream is EOF
|
||||
if ($this->stream->eof()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// No limit and the underlying stream is not at EOF
|
||||
if ($this->limit == -1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $this->stream->tell() >= $this->offset + $this->limit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the size of the limited subset of data
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getSize()
|
||||
{
|
||||
if (null === ($length = $this->stream->getSize())) {
|
||||
return null;
|
||||
} elseif ($this->limit == -1) {
|
||||
return $length - $this->offset;
|
||||
} else {
|
||||
return min($this->limit, $length - $this->offset);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow for a bounded seek on the read limited stream
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function seek($offset, $whence = SEEK_SET)
|
||||
{
|
||||
if ($whence !== SEEK_SET || $offset < 0) {
|
||||
throw new \RuntimeException(sprintf(
|
||||
'Cannot seek to offset % with whence %s',
|
||||
$offset,
|
||||
$whence
|
||||
));
|
||||
}
|
||||
|
||||
$offset += $this->offset;
|
||||
|
||||
if ($this->limit !== -1) {
|
||||
if ($offset > $this->offset + $this->limit) {
|
||||
$offset = $this->offset + $this->limit;
|
||||
}
|
||||
}
|
||||
|
||||
$this->stream->seek($offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Give a relative tell()
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function tell()
|
||||
{
|
||||
return $this->stream->tell() - $this->offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the offset to start limiting from
|
||||
*
|
||||
* @param int $offset Offset to seek to and begin byte limiting from
|
||||
*
|
||||
* @throws \RuntimeException if the stream cannot be seeked.
|
||||
*/
|
||||
public function setOffset($offset)
|
||||
{
|
||||
$current = $this->stream->tell();
|
||||
|
||||
if ($current !== $offset) {
|
||||
// If the stream cannot seek to the offset position, then read to it
|
||||
if ($this->stream->isSeekable()) {
|
||||
$this->stream->seek($offset);
|
||||
} elseif ($current > $offset) {
|
||||
throw new \RuntimeException("Could not seek to stream offset $offset");
|
||||
} else {
|
||||
$this->stream->read($offset - $current);
|
||||
}
|
||||
}
|
||||
|
||||
$this->offset = $offset;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the limit of bytes that the decorator allows to be read from the
|
||||
* stream.
|
||||
*
|
||||
* @param int $limit Number of bytes to allow to be read from the stream.
|
||||
* Use -1 for no limit.
|
||||
*/
|
||||
public function setLimit($limit)
|
||||
{
|
||||
$this->limit = $limit;
|
||||
}
|
||||
|
||||
public function read($length)
|
||||
{
|
||||
if ($this->limit == -1) {
|
||||
return $this->stream->read($length);
|
||||
}
|
||||
|
||||
// Check if the current position is less than the total allowed
|
||||
// bytes + original offset
|
||||
$remaining = ($this->offset + $this->limit) - $this->stream->tell();
|
||||
if ($remaining > 0) {
|
||||
// Only return the amount of requested data, ensuring that the byte
|
||||
// limit is not exceeded
|
||||
return $this->stream->read(min($remaining, $length));
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
}
|
158
server/vendor/guzzlehttp/psr7/src/MessageTrait.php
vendored
Normal file
158
server/vendor/guzzlehttp/psr7/src/MessageTrait.php
vendored
Normal file
|
@ -0,0 +1,158 @@
|
|||
<?php
|
||||
namespace GuzzleHttp\Psr7;
|
||||
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
|
||||
/**
|
||||
* Trait implementing functionality common to requests and responses.
|
||||
*/
|
||||
trait MessageTrait
|
||||
{
|
||||
/** @var array Cached HTTP header collection with lowercase key to values */
|
||||
private $headers = [];
|
||||
|
||||
/** @var array Actual key to list of values per header. */
|
||||
private $headerLines = [];
|
||||
|
||||
/** @var string */
|
||||
private $protocol = '1.1';
|
||||
|
||||
/** @var StreamInterface */
|
||||
private $stream;
|
||||
|
||||
public function getProtocolVersion()
|
||||
{
|
||||
return $this->protocol;
|
||||
}
|
||||
|
||||
public function withProtocolVersion($version)
|
||||
{
|
||||
if ($this->protocol === $version) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
$new = clone $this;
|
||||
$new->protocol = $version;
|
||||
return $new;
|
||||
}
|
||||
|
||||
public function getHeaders()
|
||||
{
|
||||
return $this->headerLines;
|
||||
}
|
||||
|
||||
public function hasHeader($header)
|
||||
{
|
||||
return isset($this->headers[strtolower($header)]);
|
||||
}
|
||||
|
||||
public function getHeader($header)
|
||||
{
|
||||
$name = strtolower($header);
|
||||
return isset($this->headers[$name]) ? $this->headers[$name] : [];
|
||||
}
|
||||
|
||||
public function getHeaderLine($header)
|
||||
{
|
||||
return implode(', ', $this->getHeader($header));
|
||||
}
|
||||
|
||||
public function withHeader($header, $value)
|
||||
{
|
||||
$new = clone $this;
|
||||
$header = trim($header);
|
||||
$name = strtolower($header);
|
||||
|
||||
if (!is_array($value)) {
|
||||
$new->headers[$name] = [trim($value)];
|
||||
} else {
|
||||
$new->headers[$name] = $value;
|
||||
foreach ($new->headers[$name] as &$v) {
|
||||
$v = trim($v);
|
||||
}
|
||||
}
|
||||
|
||||
// Remove the header lines.
|
||||
foreach (array_keys($new->headerLines) as $key) {
|
||||
if (strtolower($key) === $name) {
|
||||
unset($new->headerLines[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
// Add the header line.
|
||||
$new->headerLines[$header] = $new->headers[$name];
|
||||
|
||||
return $new;
|
||||
}
|
||||
|
||||
public function withAddedHeader($header, $value)
|
||||
{
|
||||
if (!$this->hasHeader($header)) {
|
||||
return $this->withHeader($header, $value);
|
||||
}
|
||||
|
||||
$new = clone $this;
|
||||
$new->headers[strtolower($header)][] = $value;
|
||||
$new->headerLines[$header][] = $value;
|
||||
return $new;
|
||||
}
|
||||
|
||||
public function withoutHeader($header)
|
||||
{
|
||||
if (!$this->hasHeader($header)) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
$new = clone $this;
|
||||
$name = strtolower($header);
|
||||
unset($new->headers[$name]);
|
||||
|
||||
foreach (array_keys($new->headerLines) as $key) {
|
||||
if (strtolower($key) === $name) {
|
||||
unset($new->headerLines[$key]);
|
||||
}
|
||||
}
|
||||
|
||||
return $new;
|
||||
}
|
||||
|
||||
public function getBody()
|
||||
{
|
||||
if (!$this->stream) {
|
||||
$this->stream = stream_for('');
|
||||
}
|
||||
|
||||
return $this->stream;
|
||||
}
|
||||
|
||||
public function withBody(StreamInterface $body)
|
||||
{
|
||||
if ($body === $this->stream) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
$new = clone $this;
|
||||
$new->stream = $body;
|
||||
return $new;
|
||||
}
|
||||
|
||||
private function setHeaders(array $headers)
|
||||
{
|
||||
$this->headerLines = $this->headers = [];
|
||||
foreach ($headers as $header => $value) {
|
||||
$header = trim($header);
|
||||
$name = strtolower($header);
|
||||
if (!is_array($value)) {
|
||||
$value = trim($value);
|
||||
$this->headers[$name][] = $value;
|
||||
$this->headerLines[$header][] = $value;
|
||||
} else {
|
||||
foreach ($value as $v) {
|
||||
$v = trim($v);
|
||||
$this->headers[$name][] = $v;
|
||||
$this->headerLines[$header][] = $v;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
153
server/vendor/guzzlehttp/psr7/src/MultipartStream.php
vendored
Normal file
153
server/vendor/guzzlehttp/psr7/src/MultipartStream.php
vendored
Normal file
|
@ -0,0 +1,153 @@
|
|||
<?php
|
||||
namespace GuzzleHttp\Psr7;
|
||||
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
|
||||
/**
|
||||
* Stream that when read returns bytes for a streaming multipart or
|
||||
* multipart/form-data stream.
|
||||
*/
|
||||
class MultipartStream implements StreamInterface
|
||||
{
|
||||
use StreamDecoratorTrait;
|
||||
|
||||
private $boundary;
|
||||
|
||||
/**
|
||||
* @param array $elements Array of associative arrays, each containing a
|
||||
* required "name" key mapping to the form field,
|
||||
* name, a required "contents" key mapping to a
|
||||
* StreamInterface/resource/string, an optional
|
||||
* "headers" associative array of custom headers,
|
||||
* and an optional "filename" key mapping to a
|
||||
* string to send as the filename in the part.
|
||||
* @param string $boundary You can optionally provide a specific boundary
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
public function __construct(array $elements = [], $boundary = null)
|
||||
{
|
||||
$this->boundary = $boundary ?: uniqid();
|
||||
$this->stream = $this->createStream($elements);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the boundary
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function getBoundary()
|
||||
{
|
||||
return $this->boundary;
|
||||
}
|
||||
|
||||
public function isWritable()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the headers needed before transferring the content of a POST file
|
||||
*/
|
||||
private function getHeaders(array $headers)
|
||||
{
|
||||
$str = '';
|
||||
foreach ($headers as $key => $value) {
|
||||
$str .= "{$key}: {$value}\r\n";
|
||||
}
|
||||
|
||||
return "--{$this->boundary}\r\n" . trim($str) . "\r\n\r\n";
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the aggregate stream that will be used to upload the POST data
|
||||
*/
|
||||
protected function createStream(array $elements)
|
||||
{
|
||||
$stream = new AppendStream();
|
||||
|
||||
foreach ($elements as $element) {
|
||||
$this->addElement($stream, $element);
|
||||
}
|
||||
|
||||
// Add the trailing boundary with CRLF
|
||||
$stream->addStream(stream_for("--{$this->boundary}--\r\n"));
|
||||
|
||||
return $stream;
|
||||
}
|
||||
|
||||
private function addElement(AppendStream $stream, array $element)
|
||||
{
|
||||
foreach (['contents', 'name'] as $key) {
|
||||
if (!array_key_exists($key, $element)) {
|
||||
throw new \InvalidArgumentException("A '{$key}' key is required");
|
||||
}
|
||||
}
|
||||
|
||||
$element['contents'] = stream_for($element['contents']);
|
||||
|
||||
if (empty($element['filename'])) {
|
||||
$uri = $element['contents']->getMetadata('uri');
|
||||
if (substr($uri, 0, 6) !== 'php://') {
|
||||
$element['filename'] = $uri;
|
||||
}
|
||||
}
|
||||
|
||||
list($body, $headers) = $this->createElement(
|
||||
$element['name'],
|
||||
$element['contents'],
|
||||
isset($element['filename']) ? $element['filename'] : null,
|
||||
isset($element['headers']) ? $element['headers'] : []
|
||||
);
|
||||
|
||||
$stream->addStream(stream_for($this->getHeaders($headers)));
|
||||
$stream->addStream($body);
|
||||
$stream->addStream(stream_for("\r\n"));
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
private function createElement($name, $stream, $filename, array $headers)
|
||||
{
|
||||
// Set a default content-disposition header if one was no provided
|
||||
$disposition = $this->getHeader($headers, 'content-disposition');
|
||||
if (!$disposition) {
|
||||
$headers['Content-Disposition'] = $filename
|
||||
? sprintf('form-data; name="%s"; filename="%s"',
|
||||
$name,
|
||||
basename($filename))
|
||||
: "form-data; name=\"{$name}\"";
|
||||
}
|
||||
|
||||
// Set a default content-length header if one was no provided
|
||||
$length = $this->getHeader($headers, 'content-length');
|
||||
if (!$length) {
|
||||
if ($length = $stream->getSize()) {
|
||||
$headers['Content-Length'] = (string) $length;
|
||||
}
|
||||
}
|
||||
|
||||
// Set a default Content-Type if one was not supplied
|
||||
$type = $this->getHeader($headers, 'content-type');
|
||||
if (!$type && $filename) {
|
||||
if ($type = mimetype_from_filename($filename)) {
|
||||
$headers['Content-Type'] = $type;
|
||||
}
|
||||
}
|
||||
|
||||
return [$stream, $headers];
|
||||
}
|
||||
|
||||
private function getHeader(array $headers, $key)
|
||||
{
|
||||
$lowercaseHeader = strtolower($key);
|
||||
foreach ($headers as $k => $v) {
|
||||
if (strtolower($k) === $lowercaseHeader) {
|
||||
return $v;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
22
server/vendor/guzzlehttp/psr7/src/NoSeekStream.php
vendored
Normal file
22
server/vendor/guzzlehttp/psr7/src/NoSeekStream.php
vendored
Normal file
|
@ -0,0 +1,22 @@
|
|||
<?php
|
||||
namespace GuzzleHttp\Psr7;
|
||||
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
|
||||
/**
|
||||
* Stream decorator that prevents a stream from being seeked
|
||||
*/
|
||||
class NoSeekStream implements StreamInterface
|
||||
{
|
||||
use StreamDecoratorTrait;
|
||||
|
||||
public function seek($offset, $whence = SEEK_SET)
|
||||
{
|
||||
throw new \RuntimeException('Cannot seek a NoSeekStream');
|
||||
}
|
||||
|
||||
public function isSeekable()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
165
server/vendor/guzzlehttp/psr7/src/PumpStream.php
vendored
Normal file
165
server/vendor/guzzlehttp/psr7/src/PumpStream.php
vendored
Normal file
|
@ -0,0 +1,165 @@
|
|||
<?php
|
||||
namespace GuzzleHttp\Psr7;
|
||||
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
|
||||
/**
|
||||
* Provides a read only stream that pumps data from a PHP callable.
|
||||
*
|
||||
* When invoking the provided callable, the PumpStream will pass the amount of
|
||||
* data requested to read to the callable. The callable can choose to ignore
|
||||
* this value and return fewer or more bytes than requested. Any extra data
|
||||
* returned by the provided callable is buffered internally until drained using
|
||||
* the read() function of the PumpStream. The provided callable MUST return
|
||||
* false when there is no more data to read.
|
||||
*/
|
||||
class PumpStream implements StreamInterface
|
||||
{
|
||||
/** @var callable */
|
||||
private $source;
|
||||
|
||||
/** @var int */
|
||||
private $size;
|
||||
|
||||
/** @var int */
|
||||
private $tellPos = 0;
|
||||
|
||||
/** @var array */
|
||||
private $metadata;
|
||||
|
||||
/** @var BufferStream */
|
||||
private $buffer;
|
||||
|
||||
/**
|
||||
* @param callable $source Source of the stream data. The callable MAY
|
||||
* accept an integer argument used to control the
|
||||
* amount of data to return. The callable MUST
|
||||
* return a string when called, or false on error
|
||||
* or EOF.
|
||||
* @param array $options Stream options:
|
||||
* - metadata: Hash of metadata to use with stream.
|
||||
* - size: Size of the stream, if known.
|
||||
*/
|
||||
public function __construct(callable $source, array $options = [])
|
||||
{
|
||||
$this->source = $source;
|
||||
$this->size = isset($options['size']) ? $options['size'] : null;
|
||||
$this->metadata = isset($options['metadata']) ? $options['metadata'] : [];
|
||||
$this->buffer = new BufferStream();
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
try {
|
||||
return copy_to_string($this);
|
||||
} catch (\Exception $e) {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
public function close()
|
||||
{
|
||||
$this->detach();
|
||||
}
|
||||
|
||||
public function detach()
|
||||
{
|
||||
$this->tellPos = false;
|
||||
$this->source = null;
|
||||
}
|
||||
|
||||
public function getSize()
|
||||
{
|
||||
return $this->size;
|
||||
}
|
||||
|
||||
public function tell()
|
||||
{
|
||||
return $this->tellPos;
|
||||
}
|
||||
|
||||
public function eof()
|
||||
{
|
||||
return !$this->source;
|
||||
}
|
||||
|
||||
public function isSeekable()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function rewind()
|
||||
{
|
||||
$this->seek(0);
|
||||
}
|
||||
|
||||
public function seek($offset, $whence = SEEK_SET)
|
||||
{
|
||||
throw new \RuntimeException('Cannot seek a PumpStream');
|
||||
}
|
||||
|
||||
public function isWritable()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public function write($string)
|
||||
{
|
||||
throw new \RuntimeException('Cannot write to a PumpStream');
|
||||
}
|
||||
|
||||
public function isReadable()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function read($length)
|
||||
{
|
||||
$data = $this->buffer->read($length);
|
||||
$readLen = strlen($data);
|
||||
$this->tellPos += $readLen;
|
||||
$remaining = $length - $readLen;
|
||||
|
||||
if ($remaining) {
|
||||
$this->pump($remaining);
|
||||
$data .= $this->buffer->read($remaining);
|
||||
$this->tellPos += strlen($data) - $readLen;
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
public function getContents()
|
||||
{
|
||||
$result = '';
|
||||
while (!$this->eof()) {
|
||||
$result .= $this->read(1000000);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function getMetadata($key = null)
|
||||
{
|
||||
if (!$key) {
|
||||
return $this->metadata;
|
||||
}
|
||||
|
||||
return isset($this->metadata[$key]) ? $this->metadata[$key] : null;
|
||||
}
|
||||
|
||||
private function pump($length)
|
||||
{
|
||||
if ($this->source) {
|
||||
do {
|
||||
$data = call_user_func($this->source, $length);
|
||||
if ($data === false || $data === null) {
|
||||
$this->source = null;
|
||||
return;
|
||||
}
|
||||
$this->buffer->write($data);
|
||||
$length -= strlen($data);
|
||||
} while ($length > 0);
|
||||
}
|
||||
}
|
||||
}
|
149
server/vendor/guzzlehttp/psr7/src/Request.php
vendored
Normal file
149
server/vendor/guzzlehttp/psr7/src/Request.php
vendored
Normal file
|
@ -0,0 +1,149 @@
|
|||
<?php
|
||||
namespace GuzzleHttp\Psr7;
|
||||
|
||||
use InvalidArgumentException;
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
use Psr\Http\Message\UriInterface;
|
||||
|
||||
/**
|
||||
* PSR-7 request implementation.
|
||||
*/
|
||||
class Request implements RequestInterface
|
||||
{
|
||||
use MessageTrait {
|
||||
withHeader as protected withParentHeader;
|
||||
}
|
||||
|
||||
/** @var string */
|
||||
private $method;
|
||||
|
||||
/** @var null|string */
|
||||
private $requestTarget;
|
||||
|
||||
/** @var null|UriInterface */
|
||||
private $uri;
|
||||
|
||||
/**
|
||||
* @param null|string $method HTTP method for the request.
|
||||
* @param null|string|UriInterface $uri URI for the request.
|
||||
* @param array $headers Headers for the message.
|
||||
* @param string|resource|StreamInterface $body Message body.
|
||||
* @param string $protocolVersion HTTP protocol version.
|
||||
*
|
||||
* @throws InvalidArgumentException for an invalid URI
|
||||
*/
|
||||
public function __construct(
|
||||
$method,
|
||||
$uri,
|
||||
array $headers = [],
|
||||
$body = null,
|
||||
$protocolVersion = '1.1'
|
||||
) {
|
||||
if (is_string($uri)) {
|
||||
$uri = new Uri($uri);
|
||||
} elseif (!($uri instanceof UriInterface)) {
|
||||
throw new \InvalidArgumentException(
|
||||
'URI must be a string or Psr\Http\Message\UriInterface'
|
||||
);
|
||||
}
|
||||
|
||||
$this->method = strtoupper($method);
|
||||
$this->uri = $uri;
|
||||
$this->setHeaders($headers);
|
||||
$this->protocol = $protocolVersion;
|
||||
|
||||
$host = $uri->getHost();
|
||||
if ($host && !$this->hasHeader('Host')) {
|
||||
$this->updateHostFromUri($host);
|
||||
}
|
||||
|
||||
if ($body) {
|
||||
$this->stream = stream_for($body);
|
||||
}
|
||||
}
|
||||
|
||||
public function getRequestTarget()
|
||||
{
|
||||
if ($this->requestTarget !== null) {
|
||||
return $this->requestTarget;
|
||||
}
|
||||
|
||||
$target = $this->uri->getPath();
|
||||
if ($target == null) {
|
||||
$target = '/';
|
||||
}
|
||||
if ($this->uri->getQuery()) {
|
||||
$target .= '?' . $this->uri->getQuery();
|
||||
}
|
||||
|
||||
return $target;
|
||||
}
|
||||
|
||||
public function withRequestTarget($requestTarget)
|
||||
{
|
||||
if (preg_match('#\s#', $requestTarget)) {
|
||||
throw new InvalidArgumentException(
|
||||
'Invalid request target provided; cannot contain whitespace'
|
||||
);
|
||||
}
|
||||
|
||||
$new = clone $this;
|
||||
$new->requestTarget = $requestTarget;
|
||||
return $new;
|
||||
}
|
||||
|
||||
public function getMethod()
|
||||
{
|
||||
return $this->method;
|
||||
}
|
||||
|
||||
public function withMethod($method)
|
||||
{
|
||||
$new = clone $this;
|
||||
$new->method = strtoupper($method);
|
||||
return $new;
|
||||
}
|
||||
|
||||
public function getUri()
|
||||
{
|
||||
return $this->uri;
|
||||
}
|
||||
|
||||
public function withUri(UriInterface $uri, $preserveHost = false)
|
||||
{
|
||||
if ($uri === $this->uri) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
$new = clone $this;
|
||||
$new->uri = $uri;
|
||||
|
||||
if (!$preserveHost) {
|
||||
if ($host = $uri->getHost()) {
|
||||
$new->updateHostFromUri($host);
|
||||
}
|
||||
}
|
||||
|
||||
return $new;
|
||||
}
|
||||
|
||||
public function withHeader($header, $value)
|
||||
{
|
||||
/** @var Request $newInstance */
|
||||
$newInstance = $this->withParentHeader($header, $value);
|
||||
return $newInstance;
|
||||
}
|
||||
|
||||
private function updateHostFromUri($host)
|
||||
{
|
||||
// Ensure Host is the first header.
|
||||
// See: http://tools.ietf.org/html/rfc7230#section-5.4
|
||||
if ($port = $this->uri->getPort()) {
|
||||
$host .= ':' . $port;
|
||||
}
|
||||
|
||||
$this->headerLines = ['Host' => [$host]] + $this->headerLines;
|
||||
$this->headers = ['host' => [$host]] + $this->headers;
|
||||
}
|
||||
}
|
130
server/vendor/guzzlehttp/psr7/src/Response.php
vendored
Normal file
130
server/vendor/guzzlehttp/psr7/src/Response.php
vendored
Normal file
|
@ -0,0 +1,130 @@
|
|||
<?php
|
||||
namespace GuzzleHttp\Psr7;
|
||||
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
/**
|
||||
* PSR-7 response implementation.
|
||||
*/
|
||||
class Response implements ResponseInterface
|
||||
{
|
||||
use MessageTrait;
|
||||
|
||||
/** @var array Map of standard HTTP status code/reason phrases */
|
||||
private static $phrases = [
|
||||
100 => 'Continue',
|
||||
101 => 'Switching Protocols',
|
||||
102 => 'Processing',
|
||||
200 => 'OK',
|
||||
201 => 'Created',
|
||||
202 => 'Accepted',
|
||||
203 => 'Non-Authoritative Information',
|
||||
204 => 'No Content',
|
||||
205 => 'Reset Content',
|
||||
206 => 'Partial Content',
|
||||
207 => 'Multi-status',
|
||||
208 => 'Already Reported',
|
||||
300 => 'Multiple Choices',
|
||||
301 => 'Moved Permanently',
|
||||
302 => 'Found',
|
||||
303 => 'See Other',
|
||||
304 => 'Not Modified',
|
||||
305 => 'Use Proxy',
|
||||
306 => 'Switch Proxy',
|
||||
307 => 'Temporary Redirect',
|
||||
400 => 'Bad Request',
|
||||
401 => 'Unauthorized',
|
||||
402 => 'Payment Required',
|
||||
403 => 'Forbidden',
|
||||
404 => 'Not Found',
|
||||
405 => 'Method Not Allowed',
|
||||
406 => 'Not Acceptable',
|
||||
407 => 'Proxy Authentication Required',
|
||||
408 => 'Request Time-out',
|
||||
409 => 'Conflict',
|
||||
410 => 'Gone',
|
||||
411 => 'Length Required',
|
||||
412 => 'Precondition Failed',
|
||||
413 => 'Request Entity Too Large',
|
||||
414 => 'Request-URI Too Large',
|
||||
415 => 'Unsupported Media Type',
|
||||
416 => 'Requested range not satisfiable',
|
||||
417 => 'Expectation Failed',
|
||||
418 => 'I\'m a teapot',
|
||||
422 => 'Unprocessable Entity',
|
||||
423 => 'Locked',
|
||||
424 => 'Failed Dependency',
|
||||
425 => 'Unordered Collection',
|
||||
426 => 'Upgrade Required',
|
||||
428 => 'Precondition Required',
|
||||
429 => 'Too Many Requests',
|
||||
431 => 'Request Header Fields Too Large',
|
||||
500 => 'Internal Server Error',
|
||||
501 => 'Not Implemented',
|
||||
502 => 'Bad Gateway',
|
||||
503 => 'Service Unavailable',
|
||||
504 => 'Gateway Time-out',
|
||||
505 => 'HTTP Version not supported',
|
||||
506 => 'Variant Also Negotiates',
|
||||
507 => 'Insufficient Storage',
|
||||
508 => 'Loop Detected',
|
||||
511 => 'Network Authentication Required',
|
||||
];
|
||||
|
||||
/** @var null|string */
|
||||
private $reasonPhrase = '';
|
||||
|
||||
/** @var int */
|
||||
private $statusCode = 200;
|
||||
|
||||
/**
|
||||
* @param int $status Status code for the response, if any.
|
||||
* @param array $headers Headers for the response, if any.
|
||||
* @param mixed $body Stream body.
|
||||
* @param string $version Protocol version.
|
||||
* @param string $reason Reason phrase (a default will be used if possible).
|
||||
*/
|
||||
public function __construct(
|
||||
$status = 200,
|
||||
array $headers = [],
|
||||
$body = null,
|
||||
$version = '1.1',
|
||||
$reason = null
|
||||
) {
|
||||
$this->statusCode = (int) $status;
|
||||
|
||||
if ($body !== null) {
|
||||
$this->stream = stream_for($body);
|
||||
}
|
||||
|
||||
$this->setHeaders($headers);
|
||||
if (!$reason && isset(self::$phrases[$this->statusCode])) {
|
||||
$this->reasonPhrase = self::$phrases[$status];
|
||||
} else {
|
||||
$this->reasonPhrase = (string) $reason;
|
||||
}
|
||||
|
||||
$this->protocol = $version;
|
||||
}
|
||||
|
||||
public function getStatusCode()
|
||||
{
|
||||
return $this->statusCode;
|
||||
}
|
||||
|
||||
public function getReasonPhrase()
|
||||
{
|
||||
return $this->reasonPhrase;
|
||||
}
|
||||
|
||||
public function withStatus($code, $reasonPhrase = '')
|
||||
{
|
||||
$new = clone $this;
|
||||
$new->statusCode = (int) $code;
|
||||
if (!$reasonPhrase && isset(self::$phrases[$new->statusCode])) {
|
||||
$reasonPhrase = self::$phrases[$new->statusCode];
|
||||
}
|
||||
$new->reasonPhrase = $reasonPhrase;
|
||||
return $new;
|
||||
}
|
||||
}
|
245
server/vendor/guzzlehttp/psr7/src/Stream.php
vendored
Normal file
245
server/vendor/guzzlehttp/psr7/src/Stream.php
vendored
Normal file
|
@ -0,0 +1,245 @@
|
|||
<?php
|
||||
namespace GuzzleHttp\Psr7;
|
||||
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
|
||||
/**
|
||||
* PHP stream implementation.
|
||||
*
|
||||
* @var $stream
|
||||
*/
|
||||
class Stream implements StreamInterface
|
||||
{
|
||||
private $stream;
|
||||
private $size;
|
||||
private $seekable;
|
||||
private $readable;
|
||||
private $writable;
|
||||
private $uri;
|
||||
private $customMetadata;
|
||||
|
||||
/** @var array Hash of readable and writable stream types */
|
||||
private static $readWriteHash = [
|
||||
'read' => [
|
||||
'r' => true, 'w+' => true, 'r+' => true, 'x+' => true, 'c+' => true,
|
||||
'rb' => true, 'w+b' => true, 'r+b' => true, 'x+b' => true,
|
||||
'c+b' => true, 'rt' => true, 'w+t' => true, 'r+t' => true,
|
||||
'x+t' => true, 'c+t' => true, 'a+' => true
|
||||
],
|
||||
'write' => [
|
||||
'w' => true, 'w+' => true, 'rw' => true, 'r+' => true, 'x+' => true,
|
||||
'c+' => true, 'wb' => true, 'w+b' => true, 'r+b' => true,
|
||||
'x+b' => true, 'c+b' => true, 'w+t' => true, 'r+t' => true,
|
||||
'x+t' => true, 'c+t' => true, 'a' => true, 'a+' => true
|
||||
]
|
||||
];
|
||||
|
||||
/**
|
||||
* This constructor accepts an associative array of options.
|
||||
*
|
||||
* - size: (int) If a read stream would otherwise have an indeterminate
|
||||
* size, but the size is known due to foreknownledge, then you can
|
||||
* provide that size, in bytes.
|
||||
* - metadata: (array) Any additional metadata to return when the metadata
|
||||
* of the stream is accessed.
|
||||
*
|
||||
* @param resource $stream Stream resource to wrap.
|
||||
* @param array $options Associative array of options.
|
||||
*
|
||||
* @throws \InvalidArgumentException if the stream is not a stream resource
|
||||
*/
|
||||
public function __construct($stream, $options = [])
|
||||
{
|
||||
if (!is_resource($stream)) {
|
||||
throw new \InvalidArgumentException('Stream must be a resource');
|
||||
}
|
||||
|
||||
if (isset($options['size'])) {
|
||||
$this->size = $options['size'];
|
||||
}
|
||||
|
||||
$this->customMetadata = isset($options['metadata'])
|
||||
? $options['metadata']
|
||||
: [];
|
||||
|
||||
$this->stream = $stream;
|
||||
$meta = stream_get_meta_data($this->stream);
|
||||
$this->seekable = $meta['seekable'];
|
||||
$this->readable = isset(self::$readWriteHash['read'][$meta['mode']]);
|
||||
$this->writable = isset(self::$readWriteHash['write'][$meta['mode']]);
|
||||
$this->uri = $this->getMetadata('uri');
|
||||
}
|
||||
|
||||
public function __get($name)
|
||||
{
|
||||
if ($name == 'stream') {
|
||||
throw new \RuntimeException('The stream is detached');
|
||||
}
|
||||
|
||||
throw new \BadMethodCallException('No value for ' . $name);
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes the stream when the destructed
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
$this->close();
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
try {
|
||||
$this->seek(0);
|
||||
return (string) stream_get_contents($this->stream);
|
||||
} catch (\Exception $e) {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
public function getContents()
|
||||
{
|
||||
$contents = stream_get_contents($this->stream);
|
||||
|
||||
if ($contents === false) {
|
||||
throw new \RuntimeException('Unable to read stream contents');
|
||||
}
|
||||
|
||||
return $contents;
|
||||
}
|
||||
|
||||
public function close()
|
||||
{
|
||||
if (isset($this->stream)) {
|
||||
if (is_resource($this->stream)) {
|
||||
fclose($this->stream);
|
||||
}
|
||||
$this->detach();
|
||||
}
|
||||
}
|
||||
|
||||
public function detach()
|
||||
{
|
||||
if (!isset($this->stream)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$result = $this->stream;
|
||||
unset($this->stream);
|
||||
$this->size = $this->uri = null;
|
||||
$this->readable = $this->writable = $this->seekable = false;
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function getSize()
|
||||
{
|
||||
if ($this->size !== null) {
|
||||
return $this->size;
|
||||
}
|
||||
|
||||
if (!isset($this->stream)) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Clear the stat cache if the stream has a URI
|
||||
if ($this->uri) {
|
||||
clearstatcache(true, $this->uri);
|
||||
}
|
||||
|
||||
$stats = fstat($this->stream);
|
||||
if (isset($stats['size'])) {
|
||||
$this->size = $stats['size'];
|
||||
return $this->size;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
public function isReadable()
|
||||
{
|
||||
return $this->readable;
|
||||
}
|
||||
|
||||
public function isWritable()
|
||||
{
|
||||
return $this->writable;
|
||||
}
|
||||
|
||||
public function isSeekable()
|
||||
{
|
||||
return $this->seekable;
|
||||
}
|
||||
|
||||
public function eof()
|
||||
{
|
||||
return !$this->stream || feof($this->stream);
|
||||
}
|
||||
|
||||
public function tell()
|
||||
{
|
||||
$result = ftell($this->stream);
|
||||
|
||||
if ($result === false) {
|
||||
throw new \RuntimeException('Unable to determine stream position');
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function rewind()
|
||||
{
|
||||
$this->seek(0);
|
||||
}
|
||||
|
||||
public function seek($offset, $whence = SEEK_SET)
|
||||
{
|
||||
if (!$this->seekable) {
|
||||
throw new \RuntimeException('Stream is not seekable');
|
||||
} elseif (fseek($this->stream, $offset, $whence) === -1) {
|
||||
throw new \RuntimeException('Unable to seek to stream position '
|
||||
. $offset . ' with whence ' . var_export($whence, true));
|
||||
}
|
||||
}
|
||||
|
||||
public function read($length)
|
||||
{
|
||||
if (!$this->readable) {
|
||||
throw new \RuntimeException('Cannot read from non-readable stream');
|
||||
}
|
||||
|
||||
return fread($this->stream, $length);
|
||||
}
|
||||
|
||||
public function write($string)
|
||||
{
|
||||
if (!$this->writable) {
|
||||
throw new \RuntimeException('Cannot write to a non-writable stream');
|
||||
}
|
||||
|
||||
// We can't know the size after writing anything
|
||||
$this->size = null;
|
||||
$result = fwrite($this->stream, $string);
|
||||
|
||||
if ($result === false) {
|
||||
throw new \RuntimeException('Unable to write to stream');
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function getMetadata($key = null)
|
||||
{
|
||||
if (!isset($this->stream)) {
|
||||
return $key ? null : [];
|
||||
} elseif (!$key) {
|
||||
return $this->customMetadata + stream_get_meta_data($this->stream);
|
||||
} elseif (isset($this->customMetadata[$key])) {
|
||||
return $this->customMetadata[$key];
|
||||
}
|
||||
|
||||
$meta = stream_get_meta_data($this->stream);
|
||||
|
||||
return isset($meta[$key]) ? $meta[$key] : null;
|
||||
}
|
||||
}
|
149
server/vendor/guzzlehttp/psr7/src/StreamDecoratorTrait.php
vendored
Normal file
149
server/vendor/guzzlehttp/psr7/src/StreamDecoratorTrait.php
vendored
Normal file
|
@ -0,0 +1,149 @@
|
|||
<?php
|
||||
namespace GuzzleHttp\Psr7;
|
||||
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
|
||||
/**
|
||||
* Stream decorator trait
|
||||
* @property StreamInterface stream
|
||||
*/
|
||||
trait StreamDecoratorTrait
|
||||
{
|
||||
/**
|
||||
* @param StreamInterface $stream Stream to decorate
|
||||
*/
|
||||
public function __construct(StreamInterface $stream)
|
||||
{
|
||||
$this->stream = $stream;
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic method used to create a new stream if streams are not added in
|
||||
* the constructor of a decorator (e.g., LazyOpenStream).
|
||||
*
|
||||
* @param string $name Name of the property (allows "stream" only).
|
||||
*
|
||||
* @return StreamInterface
|
||||
*/
|
||||
public function __get($name)
|
||||
{
|
||||
if ($name == 'stream') {
|
||||
$this->stream = $this->createStream();
|
||||
return $this->stream;
|
||||
}
|
||||
|
||||
throw new \UnexpectedValueException("$name not found on class");
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
try {
|
||||
if ($this->isSeekable()) {
|
||||
$this->seek(0);
|
||||
}
|
||||
return $this->getContents();
|
||||
} catch (\Exception $e) {
|
||||
// Really, PHP? https://bugs.php.net/bug.php?id=53648
|
||||
trigger_error('StreamDecorator::__toString exception: '
|
||||
. (string) $e, E_USER_ERROR);
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
public function getContents()
|
||||
{
|
||||
return copy_to_string($this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow decorators to implement custom methods
|
||||
*
|
||||
* @param string $method Missing method name
|
||||
* @param array $args Method arguments
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function __call($method, array $args)
|
||||
{
|
||||
$result = call_user_func_array([$this->stream, $method], $args);
|
||||
|
||||
// Always return the wrapped object if the result is a return $this
|
||||
return $result === $this->stream ? $this : $result;
|
||||
}
|
||||
|
||||
public function close()
|
||||
{
|
||||
$this->stream->close();
|
||||
}
|
||||
|
||||
public function getMetadata($key = null)
|
||||
{
|
||||
return $this->stream->getMetadata($key);
|
||||
}
|
||||
|
||||
public function detach()
|
||||
{
|
||||
return $this->stream->detach();
|
||||
}
|
||||
|
||||
public function getSize()
|
||||
{
|
||||
return $this->stream->getSize();
|
||||
}
|
||||
|
||||
public function eof()
|
||||
{
|
||||
return $this->stream->eof();
|
||||
}
|
||||
|
||||
public function tell()
|
||||
{
|
||||
return $this->stream->tell();
|
||||
}
|
||||
|
||||
public function isReadable()
|
||||
{
|
||||
return $this->stream->isReadable();
|
||||
}
|
||||
|
||||
public function isWritable()
|
||||
{
|
||||
return $this->stream->isWritable();
|
||||
}
|
||||
|
||||
public function isSeekable()
|
||||
{
|
||||
return $this->stream->isSeekable();
|
||||
}
|
||||
|
||||
public function rewind()
|
||||
{
|
||||
$this->seek(0);
|
||||
}
|
||||
|
||||
public function seek($offset, $whence = SEEK_SET)
|
||||
{
|
||||
$this->stream->seek($offset, $whence);
|
||||
}
|
||||
|
||||
public function read($length)
|
||||
{
|
||||
return $this->stream->read($length);
|
||||
}
|
||||
|
||||
public function write($string)
|
||||
{
|
||||
return $this->stream->write($string);
|
||||
}
|
||||
|
||||
/**
|
||||
* Implement in subclasses to dynamically create streams when requested.
|
||||
*
|
||||
* @return StreamInterface
|
||||
* @throws \BadMethodCallException
|
||||
*/
|
||||
protected function createStream()
|
||||
{
|
||||
throw new \BadMethodCallException('Not implemented');
|
||||
}
|
||||
}
|
121
server/vendor/guzzlehttp/psr7/src/StreamWrapper.php
vendored
Normal file
121
server/vendor/guzzlehttp/psr7/src/StreamWrapper.php
vendored
Normal file
|
@ -0,0 +1,121 @@
|
|||
<?php
|
||||
namespace GuzzleHttp\Psr7;
|
||||
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
|
||||
/**
|
||||
* Converts Guzzle streams into PHP stream resources.
|
||||
*/
|
||||
class StreamWrapper
|
||||
{
|
||||
/** @var resource */
|
||||
public $context;
|
||||
|
||||
/** @var StreamInterface */
|
||||
private $stream;
|
||||
|
||||
/** @var string r, r+, or w */
|
||||
private $mode;
|
||||
|
||||
/**
|
||||
* Returns a resource representing the stream.
|
||||
*
|
||||
* @param StreamInterface $stream The stream to get a resource for
|
||||
*
|
||||
* @return resource
|
||||
* @throws \InvalidArgumentException if stream is not readable or writable
|
||||
*/
|
||||
public static function getResource(StreamInterface $stream)
|
||||
{
|
||||
self::register();
|
||||
|
||||
if ($stream->isReadable()) {
|
||||
$mode = $stream->isWritable() ? 'r+' : 'r';
|
||||
} elseif ($stream->isWritable()) {
|
||||
$mode = 'w';
|
||||
} else {
|
||||
throw new \InvalidArgumentException('The stream must be readable, '
|
||||
. 'writable, or both.');
|
||||
}
|
||||
|
||||
return fopen('guzzle://stream', $mode, null, stream_context_create([
|
||||
'guzzle' => ['stream' => $stream]
|
||||
]));
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the stream wrapper if needed
|
||||
*/
|
||||
public static function register()
|
||||
{
|
||||
if (!in_array('guzzle', stream_get_wrappers())) {
|
||||
stream_wrapper_register('guzzle', __CLASS__);
|
||||
}
|
||||
}
|
||||
|
||||
public function stream_open($path, $mode, $options, &$opened_path)
|
||||
{
|
||||
$options = stream_context_get_options($this->context);
|
||||
|
||||
if (!isset($options['guzzle']['stream'])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$this->mode = $mode;
|
||||
$this->stream = $options['guzzle']['stream'];
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function stream_read($count)
|
||||
{
|
||||
return $this->stream->read($count);
|
||||
}
|
||||
|
||||
public function stream_write($data)
|
||||
{
|
||||
return (int) $this->stream->write($data);
|
||||
}
|
||||
|
||||
public function stream_tell()
|
||||
{
|
||||
return $this->stream->tell();
|
||||
}
|
||||
|
||||
public function stream_eof()
|
||||
{
|
||||
return $this->stream->eof();
|
||||
}
|
||||
|
||||
public function stream_seek($offset, $whence)
|
||||
{
|
||||
$this->stream->seek($offset, $whence);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public function stream_stat()
|
||||
{
|
||||
static $modeMap = [
|
||||
'r' => 33060,
|
||||
'r+' => 33206,
|
||||
'w' => 33188
|
||||
];
|
||||
|
||||
return [
|
||||
'dev' => 0,
|
||||
'ino' => 0,
|
||||
'mode' => $modeMap[$this->mode],
|
||||
'nlink' => 0,
|
||||
'uid' => 0,
|
||||
'gid' => 0,
|
||||
'rdev' => 0,
|
||||
'size' => $this->stream->getSize() ?: 0,
|
||||
'atime' => 0,
|
||||
'mtime' => 0,
|
||||
'ctime' => 0,
|
||||
'blksize' => 0,
|
||||
'blocks' => 0
|
||||
];
|
||||
}
|
||||
}
|
599
server/vendor/guzzlehttp/psr7/src/Uri.php
vendored
Normal file
599
server/vendor/guzzlehttp/psr7/src/Uri.php
vendored
Normal file
|
@ -0,0 +1,599 @@
|
|||
<?php
|
||||
namespace GuzzleHttp\Psr7;
|
||||
|
||||
use Psr\Http\Message\UriInterface;
|
||||
|
||||
/**
|
||||
* Basic PSR-7 URI implementation.
|
||||
*
|
||||
* @link https://github.com/phly/http This class is based upon
|
||||
* Matthew Weier O'Phinney's URI implementation in phly/http.
|
||||
*/
|
||||
class Uri implements UriInterface
|
||||
{
|
||||
private static $schemes = [
|
||||
'http' => 80,
|
||||
'https' => 443,
|
||||
];
|
||||
|
||||
private static $charUnreserved = 'a-zA-Z0-9_\-\.~';
|
||||
private static $charSubDelims = '!\$&\'\(\)\*\+,;=';
|
||||
private static $replaceQuery = ['=' => '%3D', '&' => '%26'];
|
||||
|
||||
/** @var string Uri scheme. */
|
||||
private $scheme = '';
|
||||
|
||||
/** @var string Uri user info. */
|
||||
private $userInfo = '';
|
||||
|
||||
/** @var string Uri host. */
|
||||
private $host = '';
|
||||
|
||||
/** @var int|null Uri port. */
|
||||
private $port;
|
||||
|
||||
/** @var string Uri path. */
|
||||
private $path = '';
|
||||
|
||||
/** @var string Uri query string. */
|
||||
private $query = '';
|
||||
|
||||
/** @var string Uri fragment. */
|
||||
private $fragment = '';
|
||||
|
||||
/**
|
||||
* @param string $uri URI to parse and wrap.
|
||||
*/
|
||||
public function __construct($uri = '')
|
||||
{
|
||||
if ($uri != null) {
|
||||
$parts = parse_url($uri);
|
||||
if ($parts === false) {
|
||||
throw new \InvalidArgumentException("Unable to parse URI: $uri");
|
||||
}
|
||||
$this->applyParts($parts);
|
||||
}
|
||||
}
|
||||
|
||||
public function __toString()
|
||||
{
|
||||
return self::createUriString(
|
||||
$this->scheme,
|
||||
$this->getAuthority(),
|
||||
$this->getPath(),
|
||||
$this->query,
|
||||
$this->fragment
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes dot segments from a path and returns the new path.
|
||||
*
|
||||
* @param string $path
|
||||
*
|
||||
* @return string
|
||||
* @link http://tools.ietf.org/html/rfc3986#section-5.2.4
|
||||
*/
|
||||
public static function removeDotSegments($path)
|
||||
{
|
||||
static $noopPaths = ['' => true, '/' => true, '*' => true];
|
||||
static $ignoreSegments = ['.' => true, '..' => true];
|
||||
|
||||
if (isset($noopPaths[$path])) {
|
||||
return $path;
|
||||
}
|
||||
|
||||
$results = [];
|
||||
$segments = explode('/', $path);
|
||||
foreach ($segments as $segment) {
|
||||
if ($segment == '..') {
|
||||
array_pop($results);
|
||||
} elseif (!isset($ignoreSegments[$segment])) {
|
||||
$results[] = $segment;
|
||||
}
|
||||
}
|
||||
|
||||
$newPath = implode('/', $results);
|
||||
// Add the leading slash if necessary
|
||||
if (substr($path, 0, 1) === '/' &&
|
||||
substr($newPath, 0, 1) !== '/'
|
||||
) {
|
||||
$newPath = '/' . $newPath;
|
||||
}
|
||||
|
||||
// Add the trailing slash if necessary
|
||||
if ($newPath != '/' && isset($ignoreSegments[end($segments)])) {
|
||||
$newPath .= '/';
|
||||
}
|
||||
|
||||
return $newPath;
|
||||
}
|
||||
|
||||
/**
|
||||
* Resolve a base URI with a relative URI and return a new URI.
|
||||
*
|
||||
* @param UriInterface $base Base URI
|
||||
* @param string $rel Relative URI
|
||||
*
|
||||
* @return UriInterface
|
||||
*/
|
||||
public static function resolve(UriInterface $base, $rel)
|
||||
{
|
||||
if ($rel === null || $rel === '') {
|
||||
return $base;
|
||||
}
|
||||
|
||||
if (!($rel instanceof UriInterface)) {
|
||||
$rel = new self($rel);
|
||||
}
|
||||
|
||||
// Return the relative uri as-is if it has a scheme.
|
||||
if ($rel->getScheme()) {
|
||||
return $rel->withPath(static::removeDotSegments($rel->getPath()));
|
||||
}
|
||||
|
||||
$relParts = [
|
||||
'scheme' => $rel->getScheme(),
|
||||
'authority' => $rel->getAuthority(),
|
||||
'path' => $rel->getPath(),
|
||||
'query' => $rel->getQuery(),
|
||||
'fragment' => $rel->getFragment()
|
||||
];
|
||||
|
||||
$parts = [
|
||||
'scheme' => $base->getScheme(),
|
||||
'authority' => $base->getAuthority(),
|
||||
'path' => $base->getPath(),
|
||||
'query' => $base->getQuery(),
|
||||
'fragment' => $base->getFragment()
|
||||
];
|
||||
|
||||
if (!empty($relParts['authority'])) {
|
||||
$parts['authority'] = $relParts['authority'];
|
||||
$parts['path'] = self::removeDotSegments($relParts['path']);
|
||||
$parts['query'] = $relParts['query'];
|
||||
$parts['fragment'] = $relParts['fragment'];
|
||||
} elseif (!empty($relParts['path'])) {
|
||||
if (substr($relParts['path'], 0, 1) == '/') {
|
||||
$parts['path'] = self::removeDotSegments($relParts['path']);
|
||||
$parts['query'] = $relParts['query'];
|
||||
$parts['fragment'] = $relParts['fragment'];
|
||||
} else {
|
||||
if (!empty($parts['authority']) && empty($parts['path'])) {
|
||||
$mergedPath = '/';
|
||||
} else {
|
||||
$mergedPath = substr($parts['path'], 0, strrpos($parts['path'], '/') + 1);
|
||||
}
|
||||
$parts['path'] = self::removeDotSegments($mergedPath . $relParts['path']);
|
||||
$parts['query'] = $relParts['query'];
|
||||
$parts['fragment'] = $relParts['fragment'];
|
||||
}
|
||||
} elseif (!empty($relParts['query'])) {
|
||||
$parts['query'] = $relParts['query'];
|
||||
} elseif ($relParts['fragment'] != null) {
|
||||
$parts['fragment'] = $relParts['fragment'];
|
||||
}
|
||||
|
||||
return new self(static::createUriString(
|
||||
$parts['scheme'],
|
||||
$parts['authority'],
|
||||
$parts['path'],
|
||||
$parts['query'],
|
||||
$parts['fragment']
|
||||
));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new URI with a specific query string value removed.
|
||||
*
|
||||
* Any existing query string values that exactly match the provided key are
|
||||
* removed.
|
||||
*
|
||||
* Note: this function will convert "=" to "%3D" and "&" to "%26".
|
||||
*
|
||||
* @param UriInterface $uri URI to use as a base.
|
||||
* @param string $key Query string key value pair to remove.
|
||||
*
|
||||
* @return UriInterface
|
||||
*/
|
||||
public static function withoutQueryValue(UriInterface $uri, $key)
|
||||
{
|
||||
$current = $uri->getQuery();
|
||||
if (!$current) {
|
||||
return $uri;
|
||||
}
|
||||
|
||||
$result = [];
|
||||
foreach (explode('&', $current) as $part) {
|
||||
if (explode('=', $part)[0] !== $key) {
|
||||
$result[] = $part;
|
||||
};
|
||||
}
|
||||
|
||||
return $uri->withQuery(implode('&', $result));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new URI with a specific query string value.
|
||||
*
|
||||
* Any existing query string values that exactly match the provided key are
|
||||
* removed and replaced with the given key value pair.
|
||||
*
|
||||
* Note: this function will convert "=" to "%3D" and "&" to "%26".
|
||||
*
|
||||
* @param UriInterface $uri URI to use as a base.
|
||||
* @param string $key Key to set.
|
||||
* @param string $value Value to set.
|
||||
*
|
||||
* @return UriInterface
|
||||
*/
|
||||
public static function withQueryValue(UriInterface $uri, $key, $value)
|
||||
{
|
||||
$current = $uri->getQuery();
|
||||
$key = strtr($key, self::$replaceQuery);
|
||||
|
||||
if (!$current) {
|
||||
$result = [];
|
||||
} else {
|
||||
$result = [];
|
||||
foreach (explode('&', $current) as $part) {
|
||||
if (explode('=', $part)[0] !== $key) {
|
||||
$result[] = $part;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
if ($value !== null) {
|
||||
$result[] = $key . '=' . strtr($value, self::$replaceQuery);
|
||||
} else {
|
||||
$result[] = $key;
|
||||
}
|
||||
|
||||
return $uri->withQuery(implode('&', $result));
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a URI from a hash of parse_url parts.
|
||||
*
|
||||
* @param array $parts
|
||||
*
|
||||
* @return self
|
||||
*/
|
||||
public static function fromParts(array $parts)
|
||||
{
|
||||
$uri = new self();
|
||||
$uri->applyParts($parts);
|
||||
return $uri;
|
||||
}
|
||||
|
||||
public function getScheme()
|
||||
{
|
||||
return $this->scheme;
|
||||
}
|
||||
|
||||
public function getAuthority()
|
||||
{
|
||||
if (empty($this->host)) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$authority = $this->host;
|
||||
if (!empty($this->userInfo)) {
|
||||
$authority = $this->userInfo . '@' . $authority;
|
||||
}
|
||||
|
||||
if ($this->isNonStandardPort($this->scheme, $this->host, $this->port)) {
|
||||
$authority .= ':' . $this->port;
|
||||
}
|
||||
|
||||
return $authority;
|
||||
}
|
||||
|
||||
public function getUserInfo()
|
||||
{
|
||||
return $this->userInfo;
|
||||
}
|
||||
|
||||
public function getHost()
|
||||
{
|
||||
return $this->host;
|
||||
}
|
||||
|
||||
public function getPort()
|
||||
{
|
||||
return $this->port;
|
||||
}
|
||||
|
||||
public function getPath()
|
||||
{
|
||||
return $this->path == null ? '' : $this->path;
|
||||
}
|
||||
|
||||
public function getQuery()
|
||||
{
|
||||
return $this->query;
|
||||
}
|
||||
|
||||
public function getFragment()
|
||||
{
|
||||
return $this->fragment;
|
||||
}
|
||||
|
||||
public function withScheme($scheme)
|
||||
{
|
||||
$scheme = $this->filterScheme($scheme);
|
||||
|
||||
if ($this->scheme === $scheme) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
$new = clone $this;
|
||||
$new->scheme = $scheme;
|
||||
$new->port = $new->filterPort($new->scheme, $new->host, $new->port);
|
||||
return $new;
|
||||
}
|
||||
|
||||
public function withUserInfo($user, $password = null)
|
||||
{
|
||||
$info = $user;
|
||||
if ($password) {
|
||||
$info .= ':' . $password;
|
||||
}
|
||||
|
||||
if ($this->userInfo === $info) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
$new = clone $this;
|
||||
$new->userInfo = $info;
|
||||
return $new;
|
||||
}
|
||||
|
||||
public function withHost($host)
|
||||
{
|
||||
if ($this->host === $host) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
$new = clone $this;
|
||||
$new->host = $host;
|
||||
return $new;
|
||||
}
|
||||
|
||||
public function withPort($port)
|
||||
{
|
||||
$port = $this->filterPort($this->scheme, $this->host, $port);
|
||||
|
||||
if ($this->port === $port) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
$new = clone $this;
|
||||
$new->port = $port;
|
||||
return $new;
|
||||
}
|
||||
|
||||
public function withPath($path)
|
||||
{
|
||||
if (!is_string($path)) {
|
||||
throw new \InvalidArgumentException(
|
||||
'Invalid path provided; must be a string'
|
||||
);
|
||||
}
|
||||
|
||||
$path = $this->filterPath($path);
|
||||
|
||||
if ($this->path === $path) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
$new = clone $this;
|
||||
$new->path = $path;
|
||||
return $new;
|
||||
}
|
||||
|
||||
public function withQuery($query)
|
||||
{
|
||||
if (!is_string($query) && !method_exists($query, '__toString')) {
|
||||
throw new \InvalidArgumentException(
|
||||
'Query string must be a string'
|
||||
);
|
||||
}
|
||||
|
||||
$query = (string) $query;
|
||||
if (substr($query, 0, 1) === '?') {
|
||||
$query = substr($query, 1);
|
||||
}
|
||||
|
||||
$query = $this->filterQueryAndFragment($query);
|
||||
|
||||
if ($this->query === $query) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
$new = clone $this;
|
||||
$new->query = $query;
|
||||
return $new;
|
||||
}
|
||||
|
||||
public function withFragment($fragment)
|
||||
{
|
||||
if (substr($fragment, 0, 1) === '#') {
|
||||
$fragment = substr($fragment, 1);
|
||||
}
|
||||
|
||||
$fragment = $this->filterQueryAndFragment($fragment);
|
||||
|
||||
if ($this->fragment === $fragment) {
|
||||
return $this;
|
||||
}
|
||||
|
||||
$new = clone $this;
|
||||
$new->fragment = $fragment;
|
||||
return $new;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply parse_url parts to a URI.
|
||||
*
|
||||
* @param $parts Array of parse_url parts to apply.
|
||||
*/
|
||||
private function applyParts(array $parts)
|
||||
{
|
||||
$this->scheme = isset($parts['scheme'])
|
||||
? $this->filterScheme($parts['scheme'])
|
||||
: '';
|
||||
$this->userInfo = isset($parts['user']) ? $parts['user'] : '';
|
||||
$this->host = isset($parts['host']) ? $parts['host'] : '';
|
||||
$this->port = !empty($parts['port'])
|
||||
? $this->filterPort($this->scheme, $this->host, $parts['port'])
|
||||
: null;
|
||||
$this->path = isset($parts['path'])
|
||||
? $this->filterPath($parts['path'])
|
||||
: '';
|
||||
$this->query = isset($parts['query'])
|
||||
? $this->filterQueryAndFragment($parts['query'])
|
||||
: '';
|
||||
$this->fragment = isset($parts['fragment'])
|
||||
? $this->filterQueryAndFragment($parts['fragment'])
|
||||
: '';
|
||||
if (isset($parts['pass'])) {
|
||||
$this->userInfo .= ':' . $parts['pass'];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a URI string from its various parts
|
||||
*
|
||||
* @param string $scheme
|
||||
* @param string $authority
|
||||
* @param string $path
|
||||
* @param string $query
|
||||
* @param string $fragment
|
||||
* @return string
|
||||
*/
|
||||
private static function createUriString($scheme, $authority, $path, $query, $fragment)
|
||||
{
|
||||
$uri = '';
|
||||
|
||||
if (!empty($scheme)) {
|
||||
$uri .= $scheme . '://';
|
||||
}
|
||||
|
||||
if (!empty($authority)) {
|
||||
$uri .= $authority;
|
||||
}
|
||||
|
||||
if ($path != null) {
|
||||
// Add a leading slash if necessary.
|
||||
if ($uri && substr($path, 0, 1) !== '/') {
|
||||
$uri .= '/';
|
||||
}
|
||||
$uri .= $path;
|
||||
}
|
||||
|
||||
if ($query != null) {
|
||||
$uri .= '?' . $query;
|
||||
}
|
||||
|
||||
if ($fragment != null) {
|
||||
$uri .= '#' . $fragment;
|
||||
}
|
||||
|
||||
return $uri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Is a given port non-standard for the current scheme?
|
||||
*
|
||||
* @param string $scheme
|
||||
* @param string $host
|
||||
* @param int $port
|
||||
* @return bool
|
||||
*/
|
||||
private static function isNonStandardPort($scheme, $host, $port)
|
||||
{
|
||||
if (!$scheme && $port) {
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!$host || !$port) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return !isset(static::$schemes[$scheme]) || $port !== static::$schemes[$scheme];
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $scheme
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function filterScheme($scheme)
|
||||
{
|
||||
$scheme = strtolower($scheme);
|
||||
$scheme = rtrim($scheme, ':/');
|
||||
|
||||
return $scheme;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $scheme
|
||||
* @param string $host
|
||||
* @param int $port
|
||||
*
|
||||
* @return int|null
|
||||
*
|
||||
* @throws \InvalidArgumentException If the port is invalid.
|
||||
*/
|
||||
private function filterPort($scheme, $host, $port)
|
||||
{
|
||||
if (null !== $port) {
|
||||
$port = (int) $port;
|
||||
if (1 > $port || 0xffff < $port) {
|
||||
throw new \InvalidArgumentException(
|
||||
sprintf('Invalid port: %d. Must be between 1 and 65535', $port)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return $this->isNonStandardPort($scheme, $host, $port) ? $port : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the path of a URI
|
||||
*
|
||||
* @param $path
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function filterPath($path)
|
||||
{
|
||||
return preg_replace_callback(
|
||||
'/(?:[^' . self::$charUnreserved . self::$charSubDelims . ':@\/%]+|%(?![A-Fa-f0-9]{2}))/',
|
||||
[$this, 'rawurlencodeMatchZero'],
|
||||
$path
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the query string or fragment of a URI.
|
||||
*
|
||||
* @param $str
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function filterQueryAndFragment($str)
|
||||
{
|
||||
return preg_replace_callback(
|
||||
'/(?:[^' . self::$charUnreserved . self::$charSubDelims . '%:@\/\?]+|%(?![A-Fa-f0-9]{2}))/',
|
||||
[$this, 'rawurlencodeMatchZero'],
|
||||
$str
|
||||
);
|
||||
}
|
||||
|
||||
private function rawurlencodeMatchZero(array $match)
|
||||
{
|
||||
return rawurlencode($match[0]);
|
||||
}
|
||||
}
|
802
server/vendor/guzzlehttp/psr7/src/functions.php
vendored
Normal file
802
server/vendor/guzzlehttp/psr7/src/functions.php
vendored
Normal file
|
@ -0,0 +1,802 @@
|
|||
<?php
|
||||
namespace GuzzleHttp\Psr7;
|
||||
|
||||
use Psr\Http\Message\MessageInterface;
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\StreamInterface;
|
||||
use Psr\Http\Message\UriInterface;
|
||||
|
||||
/**
|
||||
* Returns the string representation of an HTTP message.
|
||||
*
|
||||
* @param MessageInterface $message Message to convert to a string.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
function str(MessageInterface $message)
|
||||
{
|
||||
if ($message instanceof RequestInterface) {
|
||||
$msg = trim($message->getMethod() . ' '
|
||||
. $message->getRequestTarget())
|
||||
. ' HTTP/' . $message->getProtocolVersion();
|
||||
if (!$message->hasHeader('host')) {
|
||||
$msg .= "\r\nHost: " . $message->getUri()->getHost();
|
||||
}
|
||||
} elseif ($message instanceof ResponseInterface) {
|
||||
$msg = 'HTTP/' . $message->getProtocolVersion() . ' '
|
||||
. $message->getStatusCode() . ' '
|
||||
. $message->getReasonPhrase();
|
||||
} else {
|
||||
throw new \InvalidArgumentException('Unknown message type');
|
||||
}
|
||||
|
||||
foreach ($message->getHeaders() as $name => $values) {
|
||||
$msg .= "\r\n{$name}: " . implode(', ', $values);
|
||||
}
|
||||
|
||||
return "{$msg}\r\n\r\n" . $message->getBody();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a UriInterface for the given value.
|
||||
*
|
||||
* This function accepts a string or {@see Psr\Http\Message\UriInterface} and
|
||||
* returns a UriInterface for the given value. If the value is already a
|
||||
* `UriInterface`, it is returned as-is.
|
||||
*
|
||||
* @param string|UriInterface $uri
|
||||
*
|
||||
* @return UriInterface
|
||||
* @throws \InvalidArgumentException
|
||||
*/
|
||||
function uri_for($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');
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new stream based on the input type.
|
||||
*
|
||||
* Options is an associative array that can contain the following keys:
|
||||
* - metadata: Array of custom metadata.
|
||||
* - size: Size of the stream.
|
||||
*
|
||||
* @param resource|string|StreamInterface $resource Entity body data
|
||||
* @param array $options Additional options
|
||||
*
|
||||
* @return Stream
|
||||
* @throws \InvalidArgumentException if the $resource arg is not valid.
|
||||
*/
|
||||
function stream_for($resource = '', array $options = [])
|
||||
{
|
||||
switch (gettype($resource)) {
|
||||
case 'string':
|
||||
$stream = fopen('php://temp', 'r+');
|
||||
if ($resource !== '') {
|
||||
fwrite($stream, $resource);
|
||||
fseek($stream, 0);
|
||||
}
|
||||
return new Stream($stream, $options);
|
||||
case 'resource':
|
||||
return new Stream($resource, $options);
|
||||
case 'object':
|
||||
if ($resource instanceof StreamInterface) {
|
||||
return $resource;
|
||||
} elseif ($resource instanceof \Iterator) {
|
||||
return new PumpStream(function () use ($resource) {
|
||||
if (!$resource->valid()) {
|
||||
return false;
|
||||
}
|
||||
$result = $resource->current();
|
||||
$resource->next();
|
||||
return $result;
|
||||
}, $options);
|
||||
} elseif (method_exists($resource, '__toString')) {
|
||||
return stream_for((string) $resource, $options);
|
||||
}
|
||||
break;
|
||||
case 'NULL':
|
||||
return new Stream(fopen('php://temp', 'r+'), $options);
|
||||
}
|
||||
|
||||
if (is_callable($resource)) {
|
||||
return new PumpStream($resource, $options);
|
||||
}
|
||||
|
||||
throw new \InvalidArgumentException('Invalid resource type: ' . gettype($resource));
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse an array of header values containing ";" separated data into an
|
||||
* array of associative arrays representing the header key value pair
|
||||
* data of the header. When a parameter does not contain a value, but just
|
||||
* contains a key, this function will inject a key with a '' string value.
|
||||
*
|
||||
* @param string|array $header Header to parse into components.
|
||||
*
|
||||
* @return array Returns the parsed header values.
|
||||
*/
|
||||
function parse_header($header)
|
||||
{
|
||||
static $trimmed = "\"' \n\t\r";
|
||||
$params = $matches = [];
|
||||
|
||||
foreach (normalize_header($header) as $val) {
|
||||
$part = [];
|
||||
foreach (preg_split('/;(?=([^"]*"[^"]*")*[^"]*$)/', $val) as $kvp) {
|
||||
if (preg_match_all('/<[^>]+>|[^=]+/', $kvp, $matches)) {
|
||||
$m = $matches[0];
|
||||
if (isset($m[1])) {
|
||||
$part[trim($m[0], $trimmed)] = trim($m[1], $trimmed);
|
||||
} else {
|
||||
$part[] = trim($m[0], $trimmed);
|
||||
}
|
||||
}
|
||||
}
|
||||
if ($part) {
|
||||
$params[] = $part;
|
||||
}
|
||||
}
|
||||
|
||||
return $params;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an array of header values that may contain comma separated
|
||||
* headers into an array of headers with no comma separated values.
|
||||
*
|
||||
* @param string|array $header Header to normalize.
|
||||
*
|
||||
* @return array Returns the normalized header field values.
|
||||
*/
|
||||
function normalize_header($header)
|
||||
{
|
||||
if (!is_array($header)) {
|
||||
return array_map('trim', explode(',', $header));
|
||||
}
|
||||
|
||||
$result = [];
|
||||
foreach ($header as $value) {
|
||||
foreach ((array) $value as $v) {
|
||||
if (strpos($v, ',') === false) {
|
||||
$result[] = $v;
|
||||
continue;
|
||||
}
|
||||
foreach (preg_split('/,(?=([^"]*"[^"]*")*[^"]*$)/', $v) as $vv) {
|
||||
$result[] = trim($vv);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clone and modify a request with the given changes.
|
||||
*
|
||||
* The changes can be one of:
|
||||
* - method: (string) Changes the HTTP method.
|
||||
* - set_headers: (array) Sets the given headers.
|
||||
* - remove_headers: (array) Remove the given headers.
|
||||
* - body: (mixed) Sets the given body.
|
||||
* - uri: (UriInterface) Set the URI.
|
||||
* - query: (string) Set the query string value of the URI.
|
||||
* - version: (string) Set the protocol version.
|
||||
*
|
||||
* @param RequestInterface $request Request to clone and modify.
|
||||
* @param array $changes Changes to apply.
|
||||
*
|
||||
* @return RequestInterface
|
||||
*/
|
||||
function modify_request(RequestInterface $request, array $changes)
|
||||
{
|
||||
if (!$changes) {
|
||||
return $request;
|
||||
}
|
||||
|
||||
$headers = $request->getHeaders();
|
||||
|
||||
if (!isset($changes['uri'])) {
|
||||
$uri = $request->getUri();
|
||||
} else {
|
||||
// Remove the host header if one is on the URI
|
||||
if ($host = $changes['uri']->getHost()) {
|
||||
$changes['set_headers']['Host'] = $host;
|
||||
}
|
||||
$uri = $changes['uri'];
|
||||
}
|
||||
|
||||
if (!empty($changes['remove_headers'])) {
|
||||
$headers = _caseless_remove($changes['remove_headers'], $headers);
|
||||
}
|
||||
|
||||
if (!empty($changes['set_headers'])) {
|
||||
$headers = _caseless_remove(array_keys($changes['set_headers']), $headers);
|
||||
$headers = $changes['set_headers'] + $headers;
|
||||
}
|
||||
|
||||
if (isset($changes['query'])) {
|
||||
$uri = $uri->withQuery($changes['query']);
|
||||
}
|
||||
|
||||
return new Request(
|
||||
isset($changes['method']) ? $changes['method'] : $request->getMethod(),
|
||||
$uri,
|
||||
$headers,
|
||||
isset($changes['body']) ? $changes['body'] : $request->getBody(),
|
||||
isset($changes['version'])
|
||||
? $changes['version']
|
||||
: $request->getProtocolVersion()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to rewind a message body and throws an exception on failure.
|
||||
*
|
||||
* The body of the message will only be rewound if a call to `tell()` returns a
|
||||
* value other than `0`.
|
||||
*
|
||||
* @param MessageInterface $message Message to rewind
|
||||
*
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
function rewind_body(MessageInterface $message)
|
||||
{
|
||||
$body = $message->getBody();
|
||||
|
||||
if ($body->tell()) {
|
||||
$body->rewind();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Safely opens a PHP stream resource using a filename.
|
||||
*
|
||||
* When fopen fails, PHP normally raises a warning. This function adds an
|
||||
* error handler that checks for errors and throws an exception instead.
|
||||
*
|
||||
* @param string $filename File to open
|
||||
* @param string $mode Mode used to open the file
|
||||
*
|
||||
* @return resource
|
||||
* @throws \RuntimeException if the file cannot be opened
|
||||
*/
|
||||
function try_fopen($filename, $mode)
|
||||
{
|
||||
$ex = null;
|
||||
set_error_handler(function () use ($filename, $mode, &$ex) {
|
||||
$ex = new \RuntimeException(sprintf(
|
||||
'Unable to open %s using mode %s: %s',
|
||||
$filename,
|
||||
$mode,
|
||||
func_get_args()[1]
|
||||
));
|
||||
});
|
||||
|
||||
$handle = fopen($filename, $mode);
|
||||
restore_error_handler();
|
||||
|
||||
if ($ex) {
|
||||
/** @var $ex \RuntimeException */
|
||||
throw $ex;
|
||||
}
|
||||
|
||||
return $handle;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy the contents of a stream into a string until the given number of
|
||||
* bytes have been read.
|
||||
*
|
||||
* @param StreamInterface $stream Stream to read
|
||||
* @param int $maxLen Maximum number of bytes to read. Pass -1
|
||||
* to read the entire stream.
|
||||
* @return string
|
||||
* @throws \RuntimeException on error.
|
||||
*/
|
||||
function copy_to_string(StreamInterface $stream, $maxLen = -1)
|
||||
{
|
||||
$buffer = '';
|
||||
|
||||
if ($maxLen === -1) {
|
||||
while (!$stream->eof()) {
|
||||
$buf = $stream->read(1048576);
|
||||
// Using a loose equality here to match on '' and false.
|
||||
if ($buf == null) {
|
||||
break;
|
||||
}
|
||||
$buffer .= $buf;
|
||||
}
|
||||
return $buffer;
|
||||
}
|
||||
|
||||
$len = 0;
|
||||
while (!$stream->eof() && $len < $maxLen) {
|
||||
$buf = $stream->read($maxLen - $len);
|
||||
// Using a loose equality here to match on '' and false.
|
||||
if ($buf == null) {
|
||||
break;
|
||||
}
|
||||
$buffer .= $buf;
|
||||
$len = strlen($buffer);
|
||||
}
|
||||
|
||||
return $buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy the contents of a stream into another stream until the given number
|
||||
* of bytes have been read.
|
||||
*
|
||||
* @param StreamInterface $source Stream to read from
|
||||
* @param StreamInterface $dest Stream to write to
|
||||
* @param int $maxLen Maximum number of bytes to read. Pass -1
|
||||
* to read the entire stream.
|
||||
*
|
||||
* @throws \RuntimeException on error.
|
||||
*/
|
||||
function copy_to_stream(
|
||||
StreamInterface $source,
|
||||
StreamInterface $dest,
|
||||
$maxLen = -1
|
||||
) {
|
||||
if ($maxLen === -1) {
|
||||
while (!$source->eof()) {
|
||||
if (!$dest->write($source->read(1048576))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
$bytes = 0;
|
||||
while (!$source->eof()) {
|
||||
$buf = $source->read($maxLen - $bytes);
|
||||
if (!($len = strlen($buf))) {
|
||||
break;
|
||||
}
|
||||
$bytes += $len;
|
||||
$dest->write($buf);
|
||||
if ($bytes == $maxLen) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculate a hash of a Stream
|
||||
*
|
||||
* @param StreamInterface $stream Stream to calculate the hash for
|
||||
* @param string $algo Hash algorithm (e.g. md5, crc32, etc)
|
||||
* @param bool $rawOutput Whether or not to use raw output
|
||||
*
|
||||
* @return string Returns the hash of the stream
|
||||
* @throws \RuntimeException on error.
|
||||
*/
|
||||
function hash(
|
||||
StreamInterface $stream,
|
||||
$algo,
|
||||
$rawOutput = false
|
||||
) {
|
||||
$pos = $stream->tell();
|
||||
|
||||
if ($pos > 0) {
|
||||
$stream->rewind();
|
||||
}
|
||||
|
||||
$ctx = hash_init($algo);
|
||||
while (!$stream->eof()) {
|
||||
hash_update($ctx, $stream->read(1048576));
|
||||
}
|
||||
|
||||
$out = hash_final($ctx, (bool) $rawOutput);
|
||||
$stream->seek($pos);
|
||||
|
||||
return $out;
|
||||
}
|
||||
|
||||
/**
|
||||
* Read a line from the stream up to the maximum allowed buffer length
|
||||
*
|
||||
* @param StreamInterface $stream Stream to read from
|
||||
* @param int $maxLength Maximum buffer length
|
||||
*
|
||||
* @return string|bool
|
||||
*/
|
||||
function readline(StreamInterface $stream, $maxLength = null)
|
||||
{
|
||||
$buffer = '';
|
||||
$size = 0;
|
||||
|
||||
while (!$stream->eof()) {
|
||||
// Using a loose equality here to match on '' and false.
|
||||
if (null == ($byte = $stream->read(1))) {
|
||||
return $buffer;
|
||||
}
|
||||
$buffer .= $byte;
|
||||
// Break when a new line is found or the max length - 1 is reached
|
||||
if ($byte == PHP_EOL || ++$size == $maxLength - 1) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return $buffer;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a request message string into a request object.
|
||||
*
|
||||
* @param string $message Request message string.
|
||||
*
|
||||
* @return Request
|
||||
*/
|
||||
function parse_request($message)
|
||||
{
|
||||
$data = _parse_message($message);
|
||||
$matches = [];
|
||||
if (!preg_match('/^[a-zA-Z]+\s+([a-zA-Z]+:\/\/|\/).*/', $data['start-line'], $matches)) {
|
||||
throw new \InvalidArgumentException('Invalid request string');
|
||||
}
|
||||
$parts = explode(' ', $data['start-line'], 3);
|
||||
$version = isset($parts[2]) ? explode('/', $parts[2])[1] : '1.1';
|
||||
|
||||
$request = new Request(
|
||||
$parts[0],
|
||||
$matches[1] === '/' ? _parse_request_uri($parts[1], $data['headers']) : $parts[1],
|
||||
$data['headers'],
|
||||
$data['body'],
|
||||
$version
|
||||
);
|
||||
|
||||
return $matches[1] === '/' ? $request : $request->withRequestTarget($parts[1]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses a response message string into a response object.
|
||||
*
|
||||
* @param string $message Response message string.
|
||||
*
|
||||
* @return Response
|
||||
*/
|
||||
function parse_response($message)
|
||||
{
|
||||
$data = _parse_message($message);
|
||||
if (!preg_match('/^HTTP\/.* [0-9]{3} .*/', $data['start-line'])) {
|
||||
throw new \InvalidArgumentException('Invalid response string');
|
||||
}
|
||||
$parts = explode(' ', $data['start-line'], 3);
|
||||
|
||||
return new Response(
|
||||
$parts[1],
|
||||
$data['headers'],
|
||||
$data['body'],
|
||||
explode('/', $parts[0])[1],
|
||||
isset($parts[2]) ? $parts[2] : null
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Parse a query string into an associative array.
|
||||
*
|
||||
* If multiple values are found for the same key, the value of that key
|
||||
* value pair will become an array. This function does not parse nested
|
||||
* PHP style arrays into an associative array (e.g., foo[a]=1&foo[b]=2 will
|
||||
* be parsed into ['foo[a]' => '1', 'foo[b]' => '2']).
|
||||
*
|
||||
* @param string $str Query string to parse
|
||||
* @param bool|string $urlEncoding How the query string is encoded
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function parse_query($str, $urlEncoding = true)
|
||||
{
|
||||
$result = [];
|
||||
|
||||
if ($str === '') {
|
||||
return $result;
|
||||
}
|
||||
|
||||
if ($urlEncoding === true) {
|
||||
$decoder = function ($value) {
|
||||
return rawurldecode(str_replace('+', ' ', $value));
|
||||
};
|
||||
} elseif ($urlEncoding == PHP_QUERY_RFC3986) {
|
||||
$decoder = 'rawurldecode';
|
||||
} elseif ($urlEncoding == PHP_QUERY_RFC1738) {
|
||||
$decoder = 'urldecode';
|
||||
} else {
|
||||
$decoder = function ($str) { return $str; };
|
||||
}
|
||||
|
||||
foreach (explode('&', $str) as $kvp) {
|
||||
$parts = explode('=', $kvp, 2);
|
||||
$key = $decoder($parts[0]);
|
||||
$value = isset($parts[1]) ? $decoder($parts[1]) : null;
|
||||
if (!isset($result[$key])) {
|
||||
$result[$key] = $value;
|
||||
} else {
|
||||
if (!is_array($result[$key])) {
|
||||
$result[$key] = [$result[$key]];
|
||||
}
|
||||
$result[$key][] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Build a query string from an array of key value pairs.
|
||||
*
|
||||
* This function can use the return value of parseQuery() to build a query
|
||||
* string. This function does not modify the provided keys when an array is
|
||||
* encountered (like http_build_query would).
|
||||
*
|
||||
* @param array $params Query string parameters.
|
||||
* @param int|false $encoding Set to false to not encode, PHP_QUERY_RFC3986
|
||||
* to encode using RFC3986, or PHP_QUERY_RFC1738
|
||||
* to encode using RFC1738.
|
||||
* @return string
|
||||
*/
|
||||
function build_query(array $params, $encoding = PHP_QUERY_RFC3986)
|
||||
{
|
||||
if (!$params) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if ($encoding === false) {
|
||||
$encoder = function ($str) { return $str; };
|
||||
} elseif ($encoding == PHP_QUERY_RFC3986) {
|
||||
$encoder = 'rawurlencode';
|
||||
} elseif ($encoding == PHP_QUERY_RFC1738) {
|
||||
$encoder = 'urlencode';
|
||||
} else {
|
||||
throw new \InvalidArgumentException('Invalid type');
|
||||
}
|
||||
|
||||
$qs = '';
|
||||
foreach ($params as $k => $v) {
|
||||
$k = $encoder($k);
|
||||
if (!is_array($v)) {
|
||||
$qs .= $k;
|
||||
if ($v !== null) {
|
||||
$qs .= '=' . $encoder($v);
|
||||
}
|
||||
$qs .= '&';
|
||||
} else {
|
||||
foreach ($v as $vv) {
|
||||
$qs .= $k;
|
||||
if ($vv !== null) {
|
||||
$qs .= '=' . $encoder($vv);
|
||||
}
|
||||
$qs .= '&';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $qs ? (string) substr($qs, 0, -1) : '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Determines the mimetype of a file by looking at its extension.
|
||||
*
|
||||
* @param $filename
|
||||
*
|
||||
* @return null|string
|
||||
*/
|
||||
function mimetype_from_filename($filename)
|
||||
{
|
||||
return mimetype_from_extension(pathinfo($filename, PATHINFO_EXTENSION));
|
||||
}
|
||||
|
||||
/**
|
||||
* Maps a file extensions to a mimetype.
|
||||
*
|
||||
* @param $extension string The file extension.
|
||||
*
|
||||
* @return string|null
|
||||
* @link http://svn.apache.org/repos/asf/httpd/httpd/branches/1.3.x/conf/mime.types
|
||||
*/
|
||||
function mimetype_from_extension($extension)
|
||||
{
|
||||
static $mimetypes = [
|
||||
'7z' => 'application/x-7z-compressed',
|
||||
'aac' => 'audio/x-aac',
|
||||
'ai' => 'application/postscript',
|
||||
'aif' => 'audio/x-aiff',
|
||||
'asc' => 'text/plain',
|
||||
'asf' => 'video/x-ms-asf',
|
||||
'atom' => 'application/atom+xml',
|
||||
'avi' => 'video/x-msvideo',
|
||||
'bmp' => 'image/bmp',
|
||||
'bz2' => 'application/x-bzip2',
|
||||
'cer' => 'application/pkix-cert',
|
||||
'crl' => 'application/pkix-crl',
|
||||
'crt' => 'application/x-x509-ca-cert',
|
||||
'css' => 'text/css',
|
||||
'csv' => 'text/csv',
|
||||
'cu' => 'application/cu-seeme',
|
||||
'deb' => 'application/x-debian-package',
|
||||
'doc' => 'application/msword',
|
||||
'docx' => 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
|
||||
'dvi' => 'application/x-dvi',
|
||||
'eot' => 'application/vnd.ms-fontobject',
|
||||
'eps' => 'application/postscript',
|
||||
'epub' => 'application/epub+zip',
|
||||
'etx' => 'text/x-setext',
|
||||
'flac' => 'audio/flac',
|
||||
'flv' => 'video/x-flv',
|
||||
'gif' => 'image/gif',
|
||||
'gz' => 'application/gzip',
|
||||
'htm' => 'text/html',
|
||||
'html' => 'text/html',
|
||||
'ico' => 'image/x-icon',
|
||||
'ics' => 'text/calendar',
|
||||
'ini' => 'text/plain',
|
||||
'iso' => 'application/x-iso9660-image',
|
||||
'jar' => 'application/java-archive',
|
||||
'jpe' => 'image/jpeg',
|
||||
'jpeg' => 'image/jpeg',
|
||||
'jpg' => 'image/jpeg',
|
||||
'js' => 'text/javascript',
|
||||
'json' => 'application/json',
|
||||
'latex' => 'application/x-latex',
|
||||
'log' => 'text/plain',
|
||||
'm4a' => 'audio/mp4',
|
||||
'm4v' => 'video/mp4',
|
||||
'mid' => 'audio/midi',
|
||||
'midi' => 'audio/midi',
|
||||
'mov' => 'video/quicktime',
|
||||
'mp3' => 'audio/mpeg',
|
||||
'mp4' => 'video/mp4',
|
||||
'mp4a' => 'audio/mp4',
|
||||
'mp4v' => 'video/mp4',
|
||||
'mpe' => 'video/mpeg',
|
||||
'mpeg' => 'video/mpeg',
|
||||
'mpg' => 'video/mpeg',
|
||||
'mpg4' => 'video/mp4',
|
||||
'oga' => 'audio/ogg',
|
||||
'ogg' => 'audio/ogg',
|
||||
'ogv' => 'video/ogg',
|
||||
'ogx' => 'application/ogg',
|
||||
'pbm' => 'image/x-portable-bitmap',
|
||||
'pdf' => 'application/pdf',
|
||||
'pgm' => 'image/x-portable-graymap',
|
||||
'png' => 'image/png',
|
||||
'pnm' => 'image/x-portable-anymap',
|
||||
'ppm' => 'image/x-portable-pixmap',
|
||||
'ppt' => 'application/vnd.ms-powerpoint',
|
||||
'pptx' => 'application/vnd.openxmlformats-officedocument.presentationml.presentation',
|
||||
'ps' => 'application/postscript',
|
||||
'qt' => 'video/quicktime',
|
||||
'rar' => 'application/x-rar-compressed',
|
||||
'ras' => 'image/x-cmu-raster',
|
||||
'rss' => 'application/rss+xml',
|
||||
'rtf' => 'application/rtf',
|
||||
'sgm' => 'text/sgml',
|
||||
'sgml' => 'text/sgml',
|
||||
'svg' => 'image/svg+xml',
|
||||
'swf' => 'application/x-shockwave-flash',
|
||||
'tar' => 'application/x-tar',
|
||||
'tif' => 'image/tiff',
|
||||
'tiff' => 'image/tiff',
|
||||
'torrent' => 'application/x-bittorrent',
|
||||
'ttf' => 'application/x-font-ttf',
|
||||
'txt' => 'text/plain',
|
||||
'wav' => 'audio/x-wav',
|
||||
'webm' => 'video/webm',
|
||||
'wma' => 'audio/x-ms-wma',
|
||||
'wmv' => 'video/x-ms-wmv',
|
||||
'woff' => 'application/x-font-woff',
|
||||
'wsdl' => 'application/wsdl+xml',
|
||||
'xbm' => 'image/x-xbitmap',
|
||||
'xls' => 'application/vnd.ms-excel',
|
||||
'xlsx' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet',
|
||||
'xml' => 'application/xml',
|
||||
'xpm' => 'image/x-xpixmap',
|
||||
'xwd' => 'image/x-xwindowdump',
|
||||
'yaml' => 'text/yaml',
|
||||
'yml' => 'text/yaml',
|
||||
'zip' => 'application/zip',
|
||||
];
|
||||
|
||||
$extension = strtolower($extension);
|
||||
|
||||
return isset($mimetypes[$extension])
|
||||
? $mimetypes[$extension]
|
||||
: null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses an HTTP message into an associative array.
|
||||
*
|
||||
* The array contains the "start-line" key containing the start line of
|
||||
* the message, "headers" key containing an associative array of header
|
||||
* array values, and a "body" key containing the body of the message.
|
||||
*
|
||||
* @param string $message HTTP request or response to parse.
|
||||
*
|
||||
* @return array
|
||||
* @internal
|
||||
*/
|
||||
function _parse_message($message)
|
||||
{
|
||||
if (!$message) {
|
||||
throw new \InvalidArgumentException('Invalid message');
|
||||
}
|
||||
|
||||
// Iterate over each line in the message, accounting for line endings
|
||||
$lines = preg_split('/(\\r?\\n)/', $message, -1, PREG_SPLIT_DELIM_CAPTURE);
|
||||
$result = ['start-line' => array_shift($lines), 'headers' => [], 'body' => ''];
|
||||
array_shift($lines);
|
||||
|
||||
for ($i = 0, $totalLines = count($lines); $i < $totalLines; $i += 2) {
|
||||
$line = $lines[$i];
|
||||
// If two line breaks were encountered, then this is the end of body
|
||||
if (empty($line)) {
|
||||
if ($i < $totalLines - 1) {
|
||||
$result['body'] = implode('', array_slice($lines, $i + 2));
|
||||
}
|
||||
break;
|
||||
}
|
||||
if (strpos($line, ':')) {
|
||||
$parts = explode(':', $line, 2);
|
||||
$key = trim($parts[0]);
|
||||
$value = isset($parts[1]) ? trim($parts[1]) : '';
|
||||
$result['headers'][$key][] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a URI for an HTTP request message.
|
||||
*
|
||||
* @param string $path Path from the start-line
|
||||
* @param array $headers Array of headers (each value an array).
|
||||
*
|
||||
* @return string
|
||||
* @internal
|
||||
*/
|
||||
function _parse_request_uri($path, array $headers)
|
||||
{
|
||||
$hostKey = array_filter(array_keys($headers), function ($k) {
|
||||
return strtolower($k) === 'host';
|
||||
});
|
||||
|
||||
// If no host is found, then a full URI cannot be constructed.
|
||||
if (!$hostKey) {
|
||||
return $path;
|
||||
}
|
||||
|
||||
$host = $headers[reset($hostKey)][0];
|
||||
$scheme = substr($host, -4) === ':443' ? 'https' : 'http';
|
||||
|
||||
return $scheme . '://' . $host . '/' . ltrim($path, '/');
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
function _caseless_remove($keys, array $data)
|
||||
{
|
||||
$result = [];
|
||||
|
||||
foreach ($keys as &$key) {
|
||||
$key = strtolower($key);
|
||||
}
|
||||
|
||||
foreach ($data as $k => $v) {
|
||||
if (!in_array(strtolower($k), $keys)) {
|
||||
$result[$k] = $v;
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Add table
Add a link
Reference in a new issue