modified file plugins
This commit is contained in:
11
wp-content/upgrade-temp-backup/plugins/w3-total-cache/vendor/guzzlehttp/guzzle/.editorconfig
vendored
Normal file
11
wp-content/upgrade-temp-backup/plugins/w3-total-cache/vendor/guzzlehttp/guzzle/.editorconfig
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
# EditorConfig is awesome: http://EditorConfig.org
|
||||
|
||||
# top-most EditorConfig file
|
||||
root = true
|
||||
|
||||
# Unix-style newlines with a newline ending for every file
|
||||
# Indent with 4 spaces
|
||||
[php]
|
||||
end_of_line = lf
|
||||
indent_style = space
|
||||
indent_size = 4
|
||||
11
wp-content/upgrade-temp-backup/plugins/w3-total-cache/vendor/guzzlehttp/guzzle/.gitattributes
vendored
Normal file
11
wp-content/upgrade-temp-backup/plugins/w3-total-cache/vendor/guzzlehttp/guzzle/.gitattributes
vendored
Normal file
@ -0,0 +1,11 @@
|
||||
.editorconfig export-ignore
|
||||
.gitattributes export-ignore
|
||||
/.github/ export-ignore
|
||||
.gitignore export-ignore
|
||||
/build/ export-ignore
|
||||
/docs/ export-ignore
|
||||
/Makefile export-ignore
|
||||
/phpstan-baseline.neon export-ignore
|
||||
/phpstan.neon.dist export-ignore
|
||||
/phpunit.xml.dist export-ignore
|
||||
/tests/ export-ignore
|
||||
@ -0,0 +1,3 @@
|
||||
# Contributing
|
||||
|
||||
Please see our [contributing guide](http://docs.guzzlephp.org/en/latest/overview.html#contributing).
|
||||
@ -0,0 +1 @@
|
||||
Please consider using one of the issue templates (bug report, feature request).
|
||||
@ -0,0 +1,18 @@
|
||||
---
|
||||
name: 🐛 Bug Report
|
||||
about: Report errors and problems
|
||||
---
|
||||
|
||||
**Guzzle version(s) affected**: x.y.z
|
||||
|
||||
**Description**
|
||||
<!-- A clear and concise description of the problem. -->
|
||||
|
||||
**How to reproduce**
|
||||
<!-- Code and/or config needed to reproduce the problem. -->
|
||||
|
||||
**Possible Solution**
|
||||
<!--- Optional: only if you have suggestions on a fix/reason for the bug -->
|
||||
|
||||
**Additional context**
|
||||
<!-- Optional: any other context about the problem: log messages, screenshots, etc. -->
|
||||
@ -0,0 +1,14 @@
|
||||
---
|
||||
name: 🚀 Feature Request
|
||||
about: RFC and ideas for new features and improvements
|
||||
---
|
||||
|
||||
**Description**
|
||||
<!-- A clear and concise description of the new feature. -->
|
||||
|
||||
**Example**
|
||||
<!-- A simple example of the new feature in action (include PHP code, YAML config, etc.)
|
||||
If the new feature changes an existing feature, include a simple before/after comparison. -->
|
||||
|
||||
**Additional context**
|
||||
<!-- Add any other context or screenshots about the feature request here. -->
|
||||
@ -0,0 +1,10 @@
|
||||
---
|
||||
name: ⛔ Security Issue
|
||||
about: See the description to report security-related issues
|
||||
---
|
||||
|
||||
⚠ PLEASE DON'T DISCLOSE SECURITY-RELATED ISSUES PUBLICLY, SEE BELOW.
|
||||
|
||||
If you have found a security issue in Guzzle, please send the details to
|
||||
security [at] guzzlephp.org and don't disclose it publicly until we can provide a
|
||||
fix for it.
|
||||
@ -0,0 +1,10 @@
|
||||
---
|
||||
name: ⛔ Support Question
|
||||
about: See https://github.com/guzzle/guzzle/blob/master/.github/SUPPORT.md for questions about using Guzzle and its components
|
||||
---
|
||||
|
||||
We use GitHub issues only to discuss about Guzzle bugs and new features.
|
||||
For this kind of questions about using Guzzle,
|
||||
please use any of the support alternatives shown in https://github.com/guzzle/guzzle/blob/master/.github/SUPPORT.md
|
||||
|
||||
Thanks!
|
||||
@ -0,0 +1,18 @@
|
||||
# Support
|
||||
|
||||
If you're looking for support for Guzzle, here are a few options:
|
||||
|
||||
- [Documentation](http://guzzlephp.org/)
|
||||
- [Gitter](https://gitter.im/guzzle/guzzle)
|
||||
- [#guzzle](https://php-http.slack.com/messages/CE6UAAKL4/) channel in [PHP-HTTP](http://php-http.org) Slack team
|
||||
|
||||
Guzzle is a relatively old project, so chances are you will find
|
||||
much about them on Google or Stack Overflow:
|
||||
|
||||
- [guzzle](https://stackoverflow.com/questions/tagged/guzzle) tag on Stack Overflow (recommended)
|
||||
- [guzzlehttp](https://stackoverflow.com/questions/tagged/guzzlehttp) tag on Stack Overflow
|
||||
- [guzzle6](https://stackoverflow.com/questions/tagged/guzzle6) tag on Stack Overflow
|
||||
|
||||
|
||||
You can also browse the issue tracker for support requests,
|
||||
but we encourage everyone to use the channels above instead.
|
||||
@ -0,0 +1,37 @@
|
||||
#!/bin/sh -l
|
||||
|
||||
#
|
||||
# This file is a hack to suppress warnings from Roave BC check
|
||||
#
|
||||
|
||||
composer install
|
||||
|
||||
# Capture output to variable AND print it
|
||||
exec 4711>&1
|
||||
OUTPUT=$(/composer/vendor/bin/roave-backward-compatibility-check 2>&1 | tee /dev/fd/4711)
|
||||
|
||||
# Remove rows we want to suppress
|
||||
OUTPUT=`echo "$OUTPUT" | sed '/GuzzleHttp\\\ClientInterface::VERSION/'d`
|
||||
OUTPUT=`echo "$OUTPUT" | sed '/Roave\\\BetterReflection\\\Reflection\\\ReflectionClass "Psr\\\Log\\\LogLevel" could not be found in the located source/'d`
|
||||
|
||||
# Number of rows we found with "[BC]" in them
|
||||
BC_BREAKS=`echo "$OUTPUT" | grep -o '\[BC\]' | wc -l | awk '{ print $1 }'`
|
||||
|
||||
# The last row of the output is "X backwards-incompatible changes detected". Find X.
|
||||
STATED_BREAKS=`echo "$OUTPUT" | tail -n 1 | awk -F' ' '{ print $1 }'`
|
||||
|
||||
# If
|
||||
# We found "[BC]" in the command output after we removed suppressed lines
|
||||
# OR
|
||||
# We have suppressed X number of BC breaks. If $STATED_BREAKS is larger than X
|
||||
# THEN
|
||||
# exit 1
|
||||
|
||||
if [ $BC_BREAKS -gt 0 ] || [ $STATED_BREAKS -gt 2 ]; then
|
||||
echo "EXIT 1"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# No BC breaks found
|
||||
echo "EXIT 0"
|
||||
exit 0
|
||||
@ -0,0 +1,21 @@
|
||||
name: Checks
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
roave-bc-check:
|
||||
name: Roave BC Check
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Roave BC Check
|
||||
uses: docker://nyholm/roave-bc-check-ga
|
||||
with:
|
||||
entrypoint: ./.github/workflows/bc.entrypoint
|
||||
@ -0,0 +1,70 @@
|
||||
name: CI
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
pull_request:
|
||||
|
||||
jobs:
|
||||
build-lowest:
|
||||
name: Build lowest
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- name: Set up PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: '5.5'
|
||||
coverage: none
|
||||
extensions: mbstring, intl
|
||||
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: '14.x'
|
||||
|
||||
- name: Setup Problem Matchers for PHPUnit
|
||||
run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json"
|
||||
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Download dependencies
|
||||
run: composer update --no-interaction --no-progress --prefer-stable --prefer-lowest
|
||||
|
||||
- name: Run tests
|
||||
run: make test
|
||||
|
||||
build:
|
||||
name: Build
|
||||
runs-on: ubuntu-latest
|
||||
strategy:
|
||||
max-parallel: 10
|
||||
matrix:
|
||||
php: ['5.5', '5.6', '7.0', '7.1', '7.2', '7.3', '7.4']
|
||||
|
||||
steps:
|
||||
- name: Set up PHP
|
||||
uses: shivammathur/setup-php@v2
|
||||
with:
|
||||
php-version: ${{ matrix.php }}
|
||||
coverage: none
|
||||
extensions: mbstring, intl
|
||||
|
||||
- name: Set up Node
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
node-version: '14.x'
|
||||
|
||||
- name: Setup Problem Matchers for PHPUnit
|
||||
run: echo "::add-matcher::${{ runner.tool_cache }}/phpunit.json"
|
||||
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v2
|
||||
|
||||
- name: Download dependencies
|
||||
run: composer update --no-interaction --no-progress
|
||||
|
||||
- name: Run tests
|
||||
run: make test
|
||||
23
wp-content/upgrade-temp-backup/plugins/w3-total-cache/vendor/guzzlehttp/guzzle/.php_cs
vendored
Normal file
23
wp-content/upgrade-temp-backup/plugins/w3-total-cache/vendor/guzzlehttp/guzzle/.php_cs
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
$config = PhpCsFixer\Config::create()
|
||||
->setRiskyAllowed(true)
|
||||
->setRules([
|
||||
'@PSR2' => true,
|
||||
'array_syntax' => ['syntax' => 'short'],
|
||||
'declare_strict_types' => false,
|
||||
'concat_space' => ['spacing'=>'one'],
|
||||
'php_unit_test_case_static_method_calls' => ['call_type' => 'self'],
|
||||
'ordered_imports' => true,
|
||||
// 'phpdoc_align' => ['align'=>'vertical'],
|
||||
// 'native_function_invocation' => true,
|
||||
])
|
||||
->setFinder(
|
||||
PhpCsFixer\Finder::create()
|
||||
->in(__DIR__.'/src')
|
||||
->in(__DIR__.'/tests')
|
||||
->name('*.php')
|
||||
)
|
||||
;
|
||||
|
||||
return $config;
|
||||
1352
wp-content/upgrade-temp-backup/plugins/w3-total-cache/vendor/guzzlehttp/guzzle/CHANGELOG.md
vendored
Normal file
1352
wp-content/upgrade-temp-backup/plugins/w3-total-cache/vendor/guzzlehttp/guzzle/CHANGELOG.md
vendored
Normal file
File diff suppressed because it is too large
Load Diff
18
wp-content/upgrade-temp-backup/plugins/w3-total-cache/vendor/guzzlehttp/guzzle/Dockerfile
vendored
Normal file
18
wp-content/upgrade-temp-backup/plugins/w3-total-cache/vendor/guzzlehttp/guzzle/Dockerfile
vendored
Normal file
@ -0,0 +1,18 @@
|
||||
FROM composer:latest as setup
|
||||
|
||||
RUN mkdir /guzzle
|
||||
|
||||
WORKDIR /guzzle
|
||||
|
||||
RUN set -xe \
|
||||
&& composer init --name=guzzlehttp/test --description="Simple project for testing Guzzle scripts" --author="Márk Sági-Kazár <mark.sagikazar@gmail.com>" --no-interaction \
|
||||
&& composer require guzzlehttp/guzzle
|
||||
|
||||
|
||||
FROM php:7.3
|
||||
|
||||
RUN mkdir /guzzle
|
||||
|
||||
WORKDIR /guzzle
|
||||
|
||||
COPY --from=setup /guzzle /guzzle
|
||||
27
wp-content/upgrade-temp-backup/plugins/w3-total-cache/vendor/guzzlehttp/guzzle/LICENSE
vendored
Normal file
27
wp-content/upgrade-temp-backup/plugins/w3-total-cache/vendor/guzzlehttp/guzzle/LICENSE
vendored
Normal file
@ -0,0 +1,27 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2011 Michael Dowling <mtdowling@gmail.com>
|
||||
Copyright (c) 2012 Jeremy Lindblom <jeremeamia@gmail.com>
|
||||
Copyright (c) 2014 Graham Campbell <hello@gjcampbell.co.uk>
|
||||
Copyright (c) 2015 Márk Sági-Kazár <mark.sagikazar@gmail.com>
|
||||
Copyright (c) 2015 Tobias Schultze <webmaster@tubo-world.de>
|
||||
Copyright (c) 2016 Tobias Nyholm <tobias.nyholm@gmail.com>
|
||||
Copyright (c) 2016 George Mponos <gmponos@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.
|
||||
78
wp-content/upgrade-temp-backup/plugins/w3-total-cache/vendor/guzzlehttp/guzzle/Makefile
vendored
Normal file
78
wp-content/upgrade-temp-backup/plugins/w3-total-cache/vendor/guzzlehttp/guzzle/Makefile
vendored
Normal file
@ -0,0 +1,78 @@
|
||||
help:
|
||||
@echo "Please use \`make <target>' where <target> is one of"
|
||||
@echo " start-server to start the test server"
|
||||
@echo " stop-server to stop the test server"
|
||||
@echo " test to perform unit tests. Provide TEST to perform a specific test."
|
||||
@echo " coverage to perform unit tests with code coverage. Provide TEST to perform a specific test."
|
||||
@echo " coverage-show to show the code coverage report"
|
||||
@echo " clean to remove build artifacts"
|
||||
@echo " docs to build the Sphinx docs"
|
||||
@echo " docs-show to view the Sphinx docs"
|
||||
@echo " tag to modify the version, update changelog, and chag tag"
|
||||
@echo " package to build the phar and zip files"
|
||||
@echo " static to run phpstan and php-cs-fixer on the codebase"
|
||||
@echo " static-phpstan to run phpstan on the codebase"
|
||||
@echo " static-phpstan-update-baseline to regenerate the phpstan baseline file"
|
||||
@echo " static-codestyle-fix to run php-cs-fixer on the codebase, writing the changes"
|
||||
@echo " static-codestyle-check to run php-cs-fixer on the codebase"
|
||||
|
||||
start-server: stop-server
|
||||
node tests/server.js &> /dev/null &
|
||||
|
||||
stop-server:
|
||||
@PID=$(shell ps axo pid,command \
|
||||
| grep 'tests/server.js' \
|
||||
| grep -v grep \
|
||||
| cut -f 1 -d " "\
|
||||
) && [ -n "$$PID" ] && kill $$PID || true
|
||||
|
||||
test: start-server
|
||||
vendor/bin/phpunit
|
||||
$(MAKE) stop-server
|
||||
|
||||
coverage: start-server
|
||||
vendor/bin/phpunit --coverage-html=build/artifacts/coverage
|
||||
$(MAKE) stop-server
|
||||
|
||||
coverage-show: view-coverage
|
||||
|
||||
view-coverage:
|
||||
open build/artifacts/coverage/index.html
|
||||
|
||||
clean:
|
||||
rm -rf artifacts/*
|
||||
|
||||
docs:
|
||||
cd docs && make html && cd ..
|
||||
|
||||
docs-show:
|
||||
open docs/_build/html/index.html
|
||||
|
||||
tag:
|
||||
$(if $(TAG),,$(error TAG is not defined. Pass via "make tag TAG=4.2.1"))
|
||||
@echo Tagging $(TAG)
|
||||
chag update $(TAG)
|
||||
sed -i '' -e "s/VERSION = '.*'/VERSION = '$(TAG)'/" src/ClientInterface.php
|
||||
php -l src/ClientInterface.php
|
||||
git add -A
|
||||
git commit -m '$(TAG) release'
|
||||
chag tag
|
||||
|
||||
package:
|
||||
php build/packager.php
|
||||
|
||||
static: static-phpstan static-codestyle-check
|
||||
|
||||
static-phpstan:
|
||||
docker run --rm -it -e REQUIRE_DEV=true -v ${PWD}:/app -w /app oskarstark/phpstan-ga:0.12.28 analyze $(PHPSTAN_PARAMS)
|
||||
|
||||
static-phpstan-update-baseline:
|
||||
$(MAKE) static-phpstan PHPSTAN_PARAMS="--generate-baseline"
|
||||
|
||||
static-codestyle-fix:
|
||||
docker run --rm -it -v ${PWD}:/app -w /app oskarstark/php-cs-fixer-ga:2.16.3.1 --diff-format udiff $(CS_PARAMS)
|
||||
|
||||
static-codestyle-check:
|
||||
$(MAKE) static-codestyle-fix CS_PARAMS="--dry-run"
|
||||
|
||||
.PHONY: docs burgomaster coverage-show view-coverage
|
||||
97
wp-content/upgrade-temp-backup/plugins/w3-total-cache/vendor/guzzlehttp/guzzle/README.md
vendored
Normal file
97
wp-content/upgrade-temp-backup/plugins/w3-total-cache/vendor/guzzlehttp/guzzle/README.md
vendored
Normal file
@ -0,0 +1,97 @@
|
||||

|
||||
|
||||
# Guzzle, PHP HTTP client
|
||||
|
||||
[](https://github.com/guzzle/guzzle/releases)
|
||||
[](https://github.com/guzzle/guzzle/actions?query=workflow%3ACI)
|
||||
[](https://packagist.org/packages/guzzlehttp/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();
|
||||
$response = $client->request('GET', 'https://api.github.com/repos/guzzle/guzzle');
|
||||
|
||||
echo $response->getStatusCode(); # 200
|
||||
echo $response->getHeaderLine('content-type'); # 'application/json; charset=utf8'
|
||||
echo $response->getBody(); # '{"id": 1420053, "name": "guzzle", ...}'
|
||||
|
||||
# Send an asynchronous request.
|
||||
$request = new \GuzzleHttp\Psr7\Request('GET', 'http://httpbin.org');
|
||||
$promise = $client->sendAsync($request)->then(function ($response) {
|
||||
echo 'I completed! ' . $response->getBody();
|
||||
});
|
||||
|
||||
$promise->wait();
|
||||
```
|
||||
|
||||
## Help and docs
|
||||
|
||||
We use GitHub issues only to discuss bugs and new features. For support please refer to:
|
||||
|
||||
- [Documentation](https://docs.guzzlephp.org)
|
||||
- [Stack Overflow](https://stackoverflow.com/questions/tagged/guzzle)
|
||||
- [#guzzle](https://app.slack.com/client/T0D2S9JCT/CE6UAAKL4) channel on [PHP-HTTP Slack](https://slack.httplug.io/)
|
||||
- [Gitter](https://gitter.im/guzzle/guzzle)
|
||||
|
||||
|
||||
## Installing Guzzle
|
||||
|
||||
The recommended way to install Guzzle is through
|
||||
[Composer](https://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 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 update
|
||||
```
|
||||
|
||||
|
||||
## Version Guidance
|
||||
|
||||
| Version | Status | Packagist | Namespace | Repo | Docs | PSR-7 | PHP Version |
|
||||
|---------|----------------|---------------------|--------------|---------------------|---------------------|-------|--------------|
|
||||
| 3.x | EOL | `guzzle/guzzle` | `Guzzle` | [v3][guzzle-3-repo] | [v3][guzzle-3-docs] | No | >=5.3.3,<7.0 |
|
||||
| 4.x | EOL | `guzzlehttp/guzzle` | `GuzzleHttp` | [v4][guzzle-4-repo] | N/A | No | >=5.4,<7.0 |
|
||||
| 5.x | EOL | `guzzlehttp/guzzle` | `GuzzleHttp` | [v5][guzzle-5-repo] | [v5][guzzle-5-docs] | No | >=5.4,<7.4 |
|
||||
| 6.x | Security fixes | `guzzlehttp/guzzle` | `GuzzleHttp` | [v6][guzzle-6-repo] | [v6][guzzle-6-docs] | Yes | >=5.5,<8.0 |
|
||||
| 7.x | Latest | `guzzlehttp/guzzle` | `GuzzleHttp` | [v7][guzzle-7-repo] | [v7][guzzle-7-docs] | Yes | >=7.2.5,<8.2 |
|
||||
|
||||
[guzzle-3-repo]: https://github.com/guzzle/guzzle3
|
||||
[guzzle-4-repo]: https://github.com/guzzle/guzzle/tree/4.x
|
||||
[guzzle-5-repo]: https://github.com/guzzle/guzzle/tree/5.3
|
||||
[guzzle-6-repo]: https://github.com/guzzle/guzzle/tree/6.5
|
||||
[guzzle-7-repo]: https://github.com/guzzle/guzzle
|
||||
[guzzle-3-docs]: https://guzzle3.readthedocs.io/
|
||||
[guzzle-5-docs]: https://docs.guzzlephp.org/en/5.3/
|
||||
[guzzle-6-docs]: https://docs.guzzlephp.org/en/6.5/
|
||||
[guzzle-7-docs]: https://docs.guzzlephp.org/en/latest/
|
||||
1203
wp-content/upgrade-temp-backup/plugins/w3-total-cache/vendor/guzzlehttp/guzzle/UPGRADING.md
vendored
Normal file
1203
wp-content/upgrade-temp-backup/plugins/w3-total-cache/vendor/guzzlehttp/guzzle/UPGRADING.md
vendored
Normal file
File diff suppressed because it is too large
Load Diff
385
wp-content/upgrade-temp-backup/plugins/w3-total-cache/vendor/guzzlehttp/guzzle/build/Burgomaster.php
vendored
Normal file
385
wp-content/upgrade-temp-backup/plugins/w3-total-cache/vendor/guzzlehttp/guzzle/build/Burgomaster.php
vendored
Normal file
@ -0,0 +1,385 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Packages the zip and phar file using a staging directory.
|
||||
*
|
||||
* @license MIT, Michael Dowling https://github.com/mtdowling
|
||||
* @license https://github.com/mtdowling/Burgomaster/LICENSE
|
||||
*/
|
||||
class Burgomaster
|
||||
{
|
||||
/** @var string Base staging directory of the project */
|
||||
public $stageDir;
|
||||
|
||||
/** @var string Root directory of the project */
|
||||
public $projectRoot;
|
||||
|
||||
/** @var array stack of sections */
|
||||
private $sections = array();
|
||||
|
||||
/**
|
||||
* @param string $stageDir Staging base directory where your packaging
|
||||
* takes place. This folder will be created for
|
||||
* you if it does not exist. If it exists, it
|
||||
* will be deleted and recreated to start fresh.
|
||||
* @param string $projectRoot Root directory of the project.
|
||||
*
|
||||
* @throws \InvalidArgumentException
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public function __construct($stageDir, $projectRoot = null)
|
||||
{
|
||||
$this->startSection('setting_up');
|
||||
$this->stageDir = $stageDir;
|
||||
$this->projectRoot = $projectRoot;
|
||||
|
||||
if (!$this->stageDir || $this->stageDir == '/') {
|
||||
throw new \InvalidArgumentException('Invalid base directory');
|
||||
}
|
||||
|
||||
if (is_dir($this->stageDir)) {
|
||||
$this->debug("Removing existing directory: $this->stageDir");
|
||||
echo $this->exec("rm -rf $this->stageDir");
|
||||
}
|
||||
|
||||
$this->debug("Creating staging directory: $this->stageDir");
|
||||
|
||||
if (!mkdir($this->stageDir, 0777, true)) {
|
||||
throw new \RuntimeException("Could not create {$this->stageDir}");
|
||||
}
|
||||
|
||||
$this->stageDir = realpath($this->stageDir);
|
||||
$this->debug("Creating staging directory at: {$this->stageDir}");
|
||||
|
||||
if (!is_dir($this->projectRoot)) {
|
||||
throw new \InvalidArgumentException(
|
||||
"Project root not found: $this->projectRoot"
|
||||
);
|
||||
}
|
||||
|
||||
$this->endSection();
|
||||
$this->startSection('staging');
|
||||
|
||||
chdir($this->projectRoot);
|
||||
}
|
||||
|
||||
/**
|
||||
* Cleanup if the last section was not already closed.
|
||||
*/
|
||||
public function __destruct()
|
||||
{
|
||||
if ($this->sections) {
|
||||
$this->endSection();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this method when starting a specific section of the packager.
|
||||
*
|
||||
* This makes the debug messages used in your script more meaningful and
|
||||
* adds context when things go wrong. Be sure to call endSection() when
|
||||
* you have finished a section of your packaging script.
|
||||
*
|
||||
* @param string $section Part of the packager that is running
|
||||
*/
|
||||
public function startSection($section)
|
||||
{
|
||||
$this->sections[] = $section;
|
||||
$this->debug('Starting');
|
||||
}
|
||||
|
||||
/**
|
||||
* Call this method when leaving the last pushed section of the packager.
|
||||
*/
|
||||
public function endSection()
|
||||
{
|
||||
if ($this->sections) {
|
||||
$this->debug('Completed');
|
||||
array_pop($this->sections);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints a debug message to STDERR bound to the current section.
|
||||
*
|
||||
* @param string $message Message to echo to STDERR
|
||||
*/
|
||||
public function debug($message)
|
||||
{
|
||||
$prefix = date('c') . ': ';
|
||||
|
||||
if ($this->sections) {
|
||||
$prefix .= '[' . end($this->sections) . '] ';
|
||||
}
|
||||
|
||||
fwrite(STDERR, $prefix . $message . "\n");
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies a file and creates the destination directory if needed.
|
||||
*
|
||||
* @param string $from File to copy
|
||||
* @param string $to Destination to copy the file to, relative to the
|
||||
* base staging directory.
|
||||
* @throws \InvalidArgumentException if the file cannot be found
|
||||
* @throws \RuntimeException if the directory cannot be created.
|
||||
* @throws \RuntimeException if the file cannot be copied.
|
||||
*/
|
||||
public function deepCopy($from, $to)
|
||||
{
|
||||
if (!is_file($from)) {
|
||||
throw new \InvalidArgumentException("File not found: {$from}");
|
||||
}
|
||||
|
||||
$to = str_replace('//', '/', $this->stageDir . '/' . $to);
|
||||
$dir = dirname($to);
|
||||
|
||||
if (!is_dir($dir)) {
|
||||
if (!mkdir($dir, 0777, true)) {
|
||||
throw new \RuntimeException("Unable to create directory: $dir");
|
||||
}
|
||||
}
|
||||
|
||||
if (!copy($from, $to)) {
|
||||
throw new \RuntimeException("Unable to copy $from to $to");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively copy one folder to another.
|
||||
*
|
||||
* Any LICENSE file is automatically copied.
|
||||
*
|
||||
* @param string $sourceDir Source directory to copy from
|
||||
* @param string $destDir Directory to copy the files to that is relative
|
||||
* to the the stage base directory.
|
||||
* @param array $extensions File extensions to copy from the $sourceDir.
|
||||
* Defaults to "php" files only (e.g., ['php']).
|
||||
* @throws \InvalidArgumentException if the source directory is invalid.
|
||||
*/
|
||||
public function recursiveCopy(
|
||||
$sourceDir,
|
||||
$destDir,
|
||||
$extensions = array('php')
|
||||
) {
|
||||
if (!realpath($sourceDir)) {
|
||||
throw new \InvalidArgumentException("$sourceDir not found");
|
||||
}
|
||||
|
||||
if (!$extensions) {
|
||||
throw new \InvalidArgumentException('$extensions is empty!');
|
||||
}
|
||||
|
||||
$sourceDir = realpath($sourceDir);
|
||||
$exts = array_fill_keys($extensions, true);
|
||||
$iter = new \RecursiveDirectoryIterator($sourceDir);
|
||||
$iter = new \RecursiveIteratorIterator($iter);
|
||||
$total = 0;
|
||||
|
||||
$this->startSection('copy');
|
||||
$this->debug("Starting to copy files from $sourceDir");
|
||||
|
||||
foreach ($iter as $file) {
|
||||
if (isset($exts[$file->getExtension()])
|
||||
|| $file->getBaseName() == 'LICENSE'
|
||||
) {
|
||||
// Remove the source directory from the destination path
|
||||
$toPath = str_replace($sourceDir, '', (string) $file);
|
||||
$toPath = $destDir . '/' . $toPath;
|
||||
$toPath = str_replace('//', '/', $toPath);
|
||||
$this->deepCopy((string) $file, $toPath);
|
||||
$total++;
|
||||
}
|
||||
}
|
||||
|
||||
$this->debug("Copied $total files from $sourceDir");
|
||||
$this->endSection();
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a command and throw an exception if the return code is not 0.
|
||||
*
|
||||
* @param string $command Command to execute
|
||||
*
|
||||
* @return string Returns the output of the command as a string
|
||||
* @throws \RuntimeException on error.
|
||||
*/
|
||||
public function exec($command)
|
||||
{
|
||||
$this->debug("Executing: $command");
|
||||
$output = $returnValue = null;
|
||||
exec($command, $output, $returnValue);
|
||||
|
||||
if ($returnValue != 0) {
|
||||
throw new \RuntimeException('Error executing command: '
|
||||
. $command . ' : ' . implode("\n", $output));
|
||||
}
|
||||
|
||||
return implode("\n", $output);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a class-map autoloader to the staging directory in a file
|
||||
* named autoloader.php
|
||||
*
|
||||
* @param array $files Files to explicitly require in the autoloader. This
|
||||
* is similar to Composer's "files" "autoload" section.
|
||||
* @param string $filename Name of the autoloader file.
|
||||
* @throws \RuntimeException if the file cannot be written
|
||||
*/
|
||||
public function createAutoloader($files = array(), $filename = 'autoloader.php')
|
||||
{
|
||||
$sourceDir = realpath($this->stageDir);
|
||||
$iter = new \RecursiveDirectoryIterator($sourceDir);
|
||||
$iter = new \RecursiveIteratorIterator($iter);
|
||||
|
||||
$this->startSection('autoloader');
|
||||
$this->debug('Creating classmap autoloader');
|
||||
$this->debug("Collecting valid PHP files from {$this->stageDir}");
|
||||
|
||||
$classMap = array();
|
||||
foreach ($iter as $file) {
|
||||
if ($file->getExtension() == 'php') {
|
||||
$location = str_replace($this->stageDir . '/', '', (string) $file);
|
||||
$className = str_replace('/', '\\', $location);
|
||||
$className = substr($className, 0, -4);
|
||||
|
||||
// Remove "src\" or "lib\"
|
||||
if (strpos($className, 'src\\') === 0
|
||||
|| strpos($className, 'lib\\') === 0
|
||||
) {
|
||||
$className = substr($className, 4);
|
||||
}
|
||||
|
||||
$classMap[$className] = "__DIR__ . '/$location'";
|
||||
$this->debug("Found $className");
|
||||
}
|
||||
}
|
||||
|
||||
$destFile = $this->stageDir . '/' . $filename;
|
||||
$this->debug("Writing autoloader to {$destFile}");
|
||||
|
||||
if (!($h = fopen($destFile, 'w'))) {
|
||||
throw new \RuntimeException('Unable to open file for writing');
|
||||
}
|
||||
|
||||
$this->debug('Writing classmap files');
|
||||
fwrite($h, "<?php\n\n");
|
||||
fwrite($h, "\$mapping = array(\n");
|
||||
foreach ($classMap as $c => $f) {
|
||||
fwrite($h, " '$c' => $f,\n");
|
||||
}
|
||||
fwrite($h, ");\n\n");
|
||||
fwrite($h, <<<EOT
|
||||
spl_autoload_register(function (\$class) use (\$mapping) {
|
||||
if (isset(\$mapping[\$class])) {
|
||||
require \$mapping[\$class];
|
||||
}
|
||||
}, true);
|
||||
|
||||
EOT
|
||||
);
|
||||
|
||||
fwrite($h, "\n");
|
||||
|
||||
$this->debug('Writing automatically included files');
|
||||
foreach ($files as $file) {
|
||||
fwrite($h, "require __DIR__ . '/$file';\n");
|
||||
}
|
||||
|
||||
fclose($h);
|
||||
|
||||
$this->endSection();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a default stub for the phar that includeds the generated
|
||||
* autoloader.
|
||||
*
|
||||
* This phar also registers a constant that can be used to check if you
|
||||
* are running the phar. The constant is the basename of the $dest variable
|
||||
* without the extension, with "_PHAR" appended, then converted to all
|
||||
* caps (e.g., "/foo/guzzle.phar" gets a contant defined as GUZZLE_PHAR.
|
||||
*
|
||||
* @param $dest
|
||||
* @param string $autoloaderFilename Name of the autoloader file.
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function createStub($dest, $autoloaderFilename = 'autoloader.php')
|
||||
{
|
||||
$this->startSection('stub');
|
||||
$this->debug("Creating phar stub at $dest");
|
||||
|
||||
$alias = basename($dest);
|
||||
$constName = str_replace('.phar', '', strtoupper($alias)) . '_PHAR';
|
||||
$stub = "<?php\n";
|
||||
$stub .= "define('$constName', true);\n";
|
||||
$stub .= "require 'phar://$alias/{$autoloaderFilename}';\n";
|
||||
$stub .= "__HALT_COMPILER();\n";
|
||||
$this->endSection();
|
||||
|
||||
return $stub;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a phar that automatically registers an autoloader.
|
||||
*
|
||||
* Call this only after your staging directory is built.
|
||||
*
|
||||
* @param string $dest Where to save the file. The basename of the file
|
||||
* is also used as the alias name in the phar
|
||||
* (e.g., /path/to/guzzle.phar => guzzle.phar).
|
||||
* @param string|bool|null $stub The path to the phar stub file. Pass or
|
||||
* leave null to automatically have one created for you. Pass false
|
||||
* to no use a stub in the generated phar.
|
||||
* @param string $autoloaderFilename Name of the autolaoder filename.
|
||||
*/
|
||||
public function createPhar(
|
||||
$dest,
|
||||
$stub = null,
|
||||
$autoloaderFilename = 'autoloader.php'
|
||||
) {
|
||||
$this->startSection('phar');
|
||||
$this->debug("Creating phar file at $dest");
|
||||
$this->createDirIfNeeded(dirname($dest));
|
||||
$phar = new \Phar($dest, 0, basename($dest));
|
||||
$phar->buildFromDirectory($this->stageDir);
|
||||
|
||||
if ($stub !== false) {
|
||||
if (!$stub) {
|
||||
$stub = $this->createStub($dest, $autoloaderFilename);
|
||||
}
|
||||
$phar->setStub($stub);
|
||||
}
|
||||
|
||||
$this->debug("Created phar at $dest");
|
||||
$this->endSection();
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a zip file containing the staged files of your project.
|
||||
*
|
||||
* Call this only after your staging directory is built.
|
||||
*
|
||||
* @param string $dest Where to save the zip file
|
||||
*/
|
||||
public function createZip($dest)
|
||||
{
|
||||
$this->startSection('zip');
|
||||
$this->debug("Creating a zip file at $dest");
|
||||
$this->createDirIfNeeded(dirname($dest));
|
||||
chdir($this->stageDir);
|
||||
$this->exec("zip -r $dest ./");
|
||||
$this->debug(" > Created at $dest");
|
||||
chdir(__DIR__);
|
||||
$this->endSection();
|
||||
}
|
||||
|
||||
private function createDirIfNeeded($dir)
|
||||
{
|
||||
if (!is_dir($dir) && !mkdir($dir, 0755, true)) {
|
||||
throw new \RuntimeException("Could not create dir: $dir");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
require __DIR__ . '/Burgomaster.php';
|
||||
|
||||
$stageDirectory = __DIR__ . '/artifacts/staging';
|
||||
$projectRoot = __DIR__ . '/../';
|
||||
$packager = new \Burgomaster($stageDirectory, $projectRoot);
|
||||
|
||||
// Copy basic files to the stage directory. Note that we have chdir'd onto
|
||||
// the $projectRoot directory, so use relative paths.
|
||||
foreach (['README.md', 'LICENSE'] as $file) {
|
||||
$packager->deepCopy($file, $file);
|
||||
}
|
||||
|
||||
// Copy each dependency to the staging directory. Copy *.php and *.pem files.
|
||||
$packager->recursiveCopy('src', 'GuzzleHttp', ['php']);
|
||||
$packager->recursiveCopy('vendor/guzzlehttp/promises/src', 'GuzzleHttp/Promise');
|
||||
$packager->recursiveCopy('vendor/guzzlehttp/psr7/src', 'GuzzleHttp/Psr7');
|
||||
$packager->recursiveCopy('vendor/psr/http-message/src', 'Psr/Http/Message');
|
||||
|
||||
$packager->createAutoloader([
|
||||
'GuzzleHttp/functions_include.php',
|
||||
'GuzzleHttp/Psr7/functions_include.php',
|
||||
'GuzzleHttp/Promise/functions_include.php',
|
||||
]);
|
||||
|
||||
$packager->createPhar(__DIR__ . '/artifacts/guzzle.phar');
|
||||
$packager->createZip(__DIR__ . '/artifacts/guzzle.zip');
|
||||
92
wp-content/upgrade-temp-backup/plugins/w3-total-cache/vendor/guzzlehttp/guzzle/composer.json
vendored
Normal file
92
wp-content/upgrade-temp-backup/plugins/w3-total-cache/vendor/guzzlehttp/guzzle/composer.json
vendored
Normal file
@ -0,0 +1,92 @@
|
||||
{
|
||||
"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": "Graham Campbell",
|
||||
"email": "hello@gjcampbell.co.uk",
|
||||
"homepage": "https://github.com/GrahamCampbell"
|
||||
},
|
||||
{
|
||||
"name": "Michael Dowling",
|
||||
"email": "mtdowling@gmail.com",
|
||||
"homepage": "https://github.com/mtdowling"
|
||||
},
|
||||
{
|
||||
"name": "Jeremy Lindblom",
|
||||
"email": "jeremeamia@gmail.com",
|
||||
"homepage": "https://github.com/jeremeamia"
|
||||
},
|
||||
{
|
||||
"name": "George Mponos",
|
||||
"email": "gmponos@gmail.com",
|
||||
"homepage": "https://github.com/gmponos"
|
||||
},
|
||||
{
|
||||
"name": "Tobias Nyholm",
|
||||
"email": "tobias.nyholm@gmail.com",
|
||||
"homepage": "https://github.com/Nyholm"
|
||||
},
|
||||
{
|
||||
"name": "Márk Sági-Kazár",
|
||||
"email": "mark.sagikazar@gmail.com",
|
||||
"homepage": "https://github.com/sagikazarmark"
|
||||
},
|
||||
{
|
||||
"name": "Tobias Schultze",
|
||||
"email": "webmaster@tubo-world.de",
|
||||
"homepage": "https://github.com/Tobion"
|
||||
}
|
||||
],
|
||||
"require": {
|
||||
"php": ">=5.5",
|
||||
"ext-json": "*",
|
||||
"symfony/polyfill-intl-idn": "^1.17",
|
||||
"guzzlehttp/promises": "^1.0",
|
||||
"guzzlehttp/psr7": "^1.9"
|
||||
},
|
||||
"require-dev": {
|
||||
"ext-curl": "*",
|
||||
"phpunit/phpunit": "^4.8.35 || ^5.7 || ^6.4 || ^7.0",
|
||||
"psr/log": "^1.1"
|
||||
},
|
||||
"suggest": {
|
||||
"psr/log": "Required for using the Log middleware"
|
||||
},
|
||||
"config": {
|
||||
"sort-packages": true,
|
||||
"allow-plugins": {
|
||||
"bamarni/composer-bin-plugin": true
|
||||
}
|
||||
},
|
||||
"extra": {
|
||||
"branch-alias": {
|
||||
"dev-master": "6.5-dev"
|
||||
}
|
||||
},
|
||||
"autoload": {
|
||||
"psr-4": {
|
||||
"GuzzleHttp\\": "src/"
|
||||
},
|
||||
"files": [
|
||||
"src/functions_include.php"
|
||||
]
|
||||
},
|
||||
"autoload-dev": {
|
||||
"psr-4": {
|
||||
"GuzzleHttp\\Tests\\": "tests/"
|
||||
}
|
||||
}
|
||||
}
|
||||
153
wp-content/upgrade-temp-backup/plugins/w3-total-cache/vendor/guzzlehttp/guzzle/docs/Makefile
vendored
Normal file
153
wp-content/upgrade-temp-backup/plugins/w3-total-cache/vendor/guzzlehttp/guzzle/docs/Makefile
vendored
Normal file
@ -0,0 +1,153 @@
|
||||
# Makefile for Sphinx documentation
|
||||
#
|
||||
|
||||
# You can set these variables from the command line.
|
||||
SPHINXOPTS =
|
||||
SPHINXBUILD = sphinx-build
|
||||
PAPER =
|
||||
BUILDDIR = _build
|
||||
|
||||
# Internal variables.
|
||||
PAPEROPT_a4 = -D latex_paper_size=a4
|
||||
PAPEROPT_letter = -D latex_paper_size=letter
|
||||
ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
|
||||
# the i18n builder cannot share the environment and doctrees with the others
|
||||
I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
|
||||
|
||||
.PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext
|
||||
|
||||
help:
|
||||
@echo "Please use \`make <target>' where <target> is one of"
|
||||
@echo " html to make standalone HTML files"
|
||||
@echo " dirhtml to make HTML files named index.html in directories"
|
||||
@echo " singlehtml to make a single large HTML file"
|
||||
@echo " pickle to make pickle files"
|
||||
@echo " json to make JSON files"
|
||||
@echo " htmlhelp to make HTML files and a HTML help project"
|
||||
@echo " qthelp to make HTML files and a qthelp project"
|
||||
@echo " devhelp to make HTML files and a Devhelp project"
|
||||
@echo " epub to make an epub"
|
||||
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
|
||||
@echo " latexpdf to make LaTeX files and run them through pdflatex"
|
||||
@echo " text to make text files"
|
||||
@echo " man to make manual pages"
|
||||
@echo " texinfo to make Texinfo files"
|
||||
@echo " info to make Texinfo files and run them through makeinfo"
|
||||
@echo " gettext to make PO message catalogs"
|
||||
@echo " changes to make an overview of all changed/added/deprecated items"
|
||||
@echo " linkcheck to check all external links for integrity"
|
||||
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
|
||||
|
||||
clean:
|
||||
-rm -rf $(BUILDDIR)/*
|
||||
|
||||
html:
|
||||
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html
|
||||
@echo
|
||||
@echo "Build finished. The HTML pages are in $(BUILDDIR)/html."
|
||||
|
||||
dirhtml:
|
||||
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml
|
||||
@echo
|
||||
@echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml."
|
||||
|
||||
singlehtml:
|
||||
$(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml
|
||||
@echo
|
||||
@echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml."
|
||||
|
||||
pickle:
|
||||
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle
|
||||
@echo
|
||||
@echo "Build finished; now you can process the pickle files."
|
||||
|
||||
json:
|
||||
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json
|
||||
@echo
|
||||
@echo "Build finished; now you can process the JSON files."
|
||||
|
||||
htmlhelp:
|
||||
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp
|
||||
@echo
|
||||
@echo "Build finished; now you can run HTML Help Workshop with the" \
|
||||
".hhp project file in $(BUILDDIR)/htmlhelp."
|
||||
|
||||
qthelp:
|
||||
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp
|
||||
@echo
|
||||
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
|
||||
".qhcp project file in $(BUILDDIR)/qthelp, like this:"
|
||||
@echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Guzzle.qhcp"
|
||||
@echo "To view the help file:"
|
||||
@echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Guzzle.qhc"
|
||||
|
||||
devhelp:
|
||||
$(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp
|
||||
@echo
|
||||
@echo "Build finished."
|
||||
@echo "To view the help file:"
|
||||
@echo "# mkdir -p $$HOME/.local/share/devhelp/Guzzle"
|
||||
@echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Guzzle"
|
||||
@echo "# devhelp"
|
||||
|
||||
epub:
|
||||
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub
|
||||
@echo
|
||||
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
|
||||
|
||||
latex:
|
||||
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||
@echo
|
||||
@echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex."
|
||||
@echo "Run \`make' in that directory to run these through (pdf)latex" \
|
||||
"(use \`make latexpdf' here to do that automatically)."
|
||||
|
||||
latexpdf:
|
||||
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex
|
||||
@echo "Running LaTeX files through pdflatex..."
|
||||
$(MAKE) -C $(BUILDDIR)/latex all-pdf
|
||||
@echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex."
|
||||
|
||||
text:
|
||||
$(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text
|
||||
@echo
|
||||
@echo "Build finished. The text files are in $(BUILDDIR)/text."
|
||||
|
||||
man:
|
||||
$(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man
|
||||
@echo
|
||||
@echo "Build finished. The manual pages are in $(BUILDDIR)/man."
|
||||
|
||||
texinfo:
|
||||
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
|
||||
@echo
|
||||
@echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo."
|
||||
@echo "Run \`make' in that directory to run these through makeinfo" \
|
||||
"(use \`make info' here to do that automatically)."
|
||||
|
||||
info:
|
||||
$(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo
|
||||
@echo "Running Texinfo files through makeinfo..."
|
||||
make -C $(BUILDDIR)/texinfo info
|
||||
@echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo."
|
||||
|
||||
gettext:
|
||||
$(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale
|
||||
@echo
|
||||
@echo "Build finished. The message catalogs are in $(BUILDDIR)/locale."
|
||||
|
||||
changes:
|
||||
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes
|
||||
@echo
|
||||
@echo "The overview file is in $(BUILDDIR)/changes."
|
||||
|
||||
linkcheck:
|
||||
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck
|
||||
@echo
|
||||
@echo "Link check complete; look for any errors in the above output " \
|
||||
"or in $(BUILDDIR)/linkcheck/output.txt."
|
||||
|
||||
doctest:
|
||||
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest
|
||||
@echo "Testing of doctests in the sources finished, look at the " \
|
||||
"results in $(BUILDDIR)/doctest/output.txt."
|
||||
Binary file not shown.
|
After Width: | Height: | Size: 803 B |
BIN
wp-content/upgrade-temp-backup/plugins/w3-total-cache/vendor/guzzlehttp/guzzle/docs/_static/logo.png
vendored
Normal file
BIN
wp-content/upgrade-temp-backup/plugins/w3-total-cache/vendor/guzzlehttp/guzzle/docs/_static/logo.png
vendored
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 242 KiB |
68
wp-content/upgrade-temp-backup/plugins/w3-total-cache/vendor/guzzlehttp/guzzle/docs/conf.py
vendored
Normal file
68
wp-content/upgrade-temp-backup/plugins/w3-total-cache/vendor/guzzlehttp/guzzle/docs/conf.py
vendored
Normal file
@ -0,0 +1,68 @@
|
||||
import sys, os
|
||||
from sphinx.highlighting import lexers
|
||||
from pygments.lexers.web import PhpLexer
|
||||
|
||||
|
||||
lexers['php'] = PhpLexer(startinline=True, linenos=1)
|
||||
lexers['php-annotations'] = PhpLexer(startinline=True, linenos=1)
|
||||
primary_domain = 'php'
|
||||
|
||||
extensions = []
|
||||
templates_path = ['_templates']
|
||||
source_suffix = '.rst'
|
||||
master_doc = 'index'
|
||||
project = u'Guzzle'
|
||||
copyright = u'2015, Michael Dowling'
|
||||
version = '6'
|
||||
html_title = "Guzzle Documentation"
|
||||
html_short_title = "Guzzle 6"
|
||||
|
||||
exclude_patterns = ['_build']
|
||||
html_static_path = ['_static']
|
||||
|
||||
##### Guzzle sphinx theme
|
||||
|
||||
import guzzle_sphinx_theme
|
||||
html_translator_class = 'guzzle_sphinx_theme.HTMLTranslator'
|
||||
html_theme_path = guzzle_sphinx_theme.html_theme_path()
|
||||
html_theme = 'guzzle_sphinx_theme'
|
||||
|
||||
# Custom sidebar templates, maps document names to template names.
|
||||
html_sidebars = {
|
||||
'**': ['logo-text.html', 'globaltoc.html', 'searchbox.html']
|
||||
}
|
||||
|
||||
# Register the theme as an extension to generate a sitemap.xml
|
||||
extensions.append("guzzle_sphinx_theme")
|
||||
|
||||
# Guzzle theme options (see theme.conf for more information)
|
||||
html_theme_options = {
|
||||
|
||||
# Set the path to a special layout to include for the homepage
|
||||
# "index_template": "homepage.html",
|
||||
|
||||
# Allow a separate homepage from the master_doc
|
||||
# homepage = index
|
||||
|
||||
# Set the name of the project to appear in the nav menu
|
||||
# "project_nav_name": "Guzzle",
|
||||
|
||||
# Set your Disqus short name to enable comments
|
||||
# "disqus_comments_shortname": "my_disqus_comments_short_name",
|
||||
|
||||
# Set you GA account ID to enable tracking
|
||||
# "google_analytics_account": "my_ga_account",
|
||||
|
||||
# Path to a touch icon
|
||||
# "touch_icon": "",
|
||||
|
||||
# Specify a base_url used to generate sitemap.xml links. If not
|
||||
# specified, then no sitemap will be built.
|
||||
"base_url": "http://guzzlephp.org"
|
||||
|
||||
# Allow the "Table of Contents" page to be defined separately from "master_doc"
|
||||
# tocpage = Contents
|
||||
|
||||
# Allow the project link to be overriden to a custom URL.
|
||||
# projectlink = http://myproject.url
|
||||
}
|
||||
193
wp-content/upgrade-temp-backup/plugins/w3-total-cache/vendor/guzzlehttp/guzzle/docs/faq.rst
vendored
Normal file
193
wp-content/upgrade-temp-backup/plugins/w3-total-cache/vendor/guzzlehttp/guzzle/docs/faq.rst
vendored
Normal file
@ -0,0 +1,193 @@
|
||||
===
|
||||
FAQ
|
||||
===
|
||||
|
||||
Does Guzzle require cURL?
|
||||
=========================
|
||||
|
||||
No. Guzzle can use any HTTP handler to send requests. This means that Guzzle
|
||||
can be used with cURL, PHP's stream wrapper, sockets, and non-blocking libraries
|
||||
like `React <http://reactphp.org/>`_. You just need to configure an HTTP handler
|
||||
to use a different method of sending requests.
|
||||
|
||||
.. note::
|
||||
|
||||
Guzzle has historically only utilized cURL to send HTTP requests. cURL is
|
||||
an amazing HTTP client (arguably the best), and Guzzle will continue to use
|
||||
it by default when it is available. It is rare, but some developers don't
|
||||
have cURL installed on their systems or run into version specific issues.
|
||||
By allowing swappable HTTP handlers, Guzzle is now much more customizable
|
||||
and able to adapt to fit the needs of more developers.
|
||||
|
||||
|
||||
Can Guzzle send asynchronous requests?
|
||||
======================================
|
||||
|
||||
Yes. You can use the ``requestAsync``, ``sendAsync``, ``getAsync``,
|
||||
``headAsync``, ``putAsync``, ``postAsync``, ``deleteAsync``, and ``patchAsync``
|
||||
methods of a client to send an asynchronous request. The client will return a
|
||||
``GuzzleHttp\Promise\PromiseInterface`` object. You can chain ``then``
|
||||
functions off of the promise.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
$promise = $client->requestAsync('GET', 'http://httpbin.org/get');
|
||||
$promise->then(function ($response) {
|
||||
echo 'Got a response! ' . $response->getStatusCode();
|
||||
});
|
||||
|
||||
You can force an asynchronous response to complete using the ``wait()`` method
|
||||
of the returned promise.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
$promise = $client->requestAsync('GET', 'http://httpbin.org/get');
|
||||
$response = $promise->wait();
|
||||
|
||||
|
||||
How can I add custom cURL options?
|
||||
==================================
|
||||
|
||||
cURL offers a huge number of `customizable options <http://us1.php.net/curl_setopt>`_.
|
||||
While Guzzle normalizes many of these options across different handlers, there
|
||||
are times when you need to set custom cURL options. This can be accomplished
|
||||
by passing an associative array of cURL settings in the **curl** key of a
|
||||
request.
|
||||
|
||||
For example, let's say you need to customize the outgoing network interface
|
||||
used with a client.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
$client->request('GET', '/', [
|
||||
'curl' => [
|
||||
CURLOPT_INTERFACE => 'xxx.xxx.xxx.xxx'
|
||||
]
|
||||
]);
|
||||
|
||||
If you use asynchronous requests with cURL multi handler and want to tweak it,
|
||||
additional options can be specified as an associative array in the
|
||||
**options** key of the ``CurlMultiHandler`` constructor.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
use \GuzzleHttp\Client;
|
||||
use \GuzzleHttp\HandlerStack;
|
||||
use \GuzzleHttp\Handler\CurlMultiHandler;
|
||||
|
||||
$client = new Client(['handler' => HandlerStack::create(new CurlMultiHandler([
|
||||
'options' => [
|
||||
CURLMOPT_MAX_TOTAL_CONNECTIONS => 50,
|
||||
CURLMOPT_MAX_HOST_CONNECTIONS => 5,
|
||||
]
|
||||
]))]);
|
||||
|
||||
|
||||
How can I add custom stream context options?
|
||||
============================================
|
||||
|
||||
You can pass custom `stream context options <http://www.php.net/manual/en/context.php>`_
|
||||
using the **stream_context** key of the request option. The **stream_context**
|
||||
array is an associative array where each key is a PHP transport, and each value
|
||||
is an associative array of transport options.
|
||||
|
||||
For example, let's say you need to customize the outgoing network interface
|
||||
used with a client and allow self-signed certificates.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
$client->request('GET', '/', [
|
||||
'stream' => true,
|
||||
'stream_context' => [
|
||||
'ssl' => [
|
||||
'allow_self_signed' => true
|
||||
],
|
||||
'socket' => [
|
||||
'bindto' => 'xxx.xxx.xxx.xxx'
|
||||
]
|
||||
]
|
||||
]);
|
||||
|
||||
|
||||
Why am I getting an SSL verification error?
|
||||
===========================================
|
||||
|
||||
You need to specify the path on disk to the CA bundle used by Guzzle for
|
||||
verifying the peer certificate. See :ref:`verify-option`.
|
||||
|
||||
|
||||
What is this Maximum function nesting error?
|
||||
============================================
|
||||
|
||||
Maximum function nesting level of '100' reached, aborting
|
||||
|
||||
You could run into this error if you have the XDebug extension installed and
|
||||
you execute a lot of requests in callbacks. This error message comes
|
||||
specifically from the XDebug extension. PHP itself does not have a function
|
||||
nesting limit. Change this setting in your php.ini to increase the limit::
|
||||
|
||||
xdebug.max_nesting_level = 1000
|
||||
|
||||
|
||||
Why am I getting a 417 error response?
|
||||
======================================
|
||||
|
||||
This can occur for a number of reasons, but if you are sending PUT, POST, or
|
||||
PATCH requests with an ``Expect: 100-Continue`` header, a server that does not
|
||||
support this header will return a 417 response. You can work around this by
|
||||
setting the ``expect`` request option to ``false``:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
$client = new GuzzleHttp\Client();
|
||||
|
||||
// Disable the expect header on a single request
|
||||
$response = $client->request('PUT', '/', ['expect' => false]);
|
||||
|
||||
// Disable the expect header on all client requests
|
||||
$client = new GuzzleHttp\Client(['expect' => false]);
|
||||
|
||||
How can I track redirected requests?
|
||||
====================================
|
||||
|
||||
You can enable tracking of redirected URIs and status codes via the
|
||||
`track_redirects` option. Each redirected URI and status code will be stored in the
|
||||
``X-Guzzle-Redirect-History`` and the ``X-Guzzle-Redirect-Status-History``
|
||||
header respectively.
|
||||
|
||||
The initial request's URI and the final status code will be excluded from the results.
|
||||
With this in mind you should be able to easily track a request's full redirect path.
|
||||
|
||||
For example, let's say you need to track redirects and provide both results
|
||||
together in a single report:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
// First you configure Guzzle with redirect tracking and make a request
|
||||
$client = new Client([
|
||||
RequestOptions::ALLOW_REDIRECTS => [
|
||||
'max' => 10, // allow at most 10 redirects.
|
||||
'strict' => true, // use "strict" RFC compliant redirects.
|
||||
'referer' => true, // add a Referer header
|
||||
'track_redirects' => true,
|
||||
],
|
||||
]);
|
||||
$initialRequest = '/redirect/3'; // Store the request URI for later use
|
||||
$response = $client->request('GET', $initialRequest); // Make your request
|
||||
|
||||
// Retrieve both Redirect History headers
|
||||
$redirectUriHistory = $response->getHeader('X-Guzzle-Redirect-History')[0]; // retrieve Redirect URI history
|
||||
$redirectCodeHistory = $response->getHeader('X-Guzzle-Redirect-Status-History')[0]; // retrieve Redirect HTTP Status history
|
||||
|
||||
// Add the initial URI requested to the (beginning of) URI history
|
||||
array_unshift($redirectUriHistory, $initialRequest);
|
||||
|
||||
// Add the final HTTP status code to the end of HTTP response history
|
||||
array_push($redirectCodeHistory, $response->getStatusCode());
|
||||
|
||||
// (Optional) Combine the items of each array into a single result set
|
||||
$fullRedirectReport = [];
|
||||
foreach ($redirectUriHistory as $key => $value) {
|
||||
$fullRedirectReport[$key] = ['location' => $value, 'code' => $redirectCodeHistory[$key]];
|
||||
}
|
||||
echo json_encode($fullRedirectReport);
|
||||
@ -0,0 +1,303 @@
|
||||
=======================
|
||||
Handlers and Middleware
|
||||
=======================
|
||||
|
||||
Guzzle clients use a handler and middleware system to send HTTP requests.
|
||||
|
||||
Handlers
|
||||
========
|
||||
|
||||
A handler function accepts a ``Psr\Http\Message\RequestInterface`` and array of
|
||||
request options and returns a ``GuzzleHttp\Promise\PromiseInterface`` that is
|
||||
fulfilled with a ``Psr\Http\Message\ResponseInterface`` or rejected with an
|
||||
exception.
|
||||
|
||||
You can provide a custom handler to a client using the ``handler`` option of
|
||||
a client constructor. It is important to understand that several request
|
||||
options used by Guzzle require that specific middlewares wrap the handler used
|
||||
by the client. You can ensure that the handler you provide to a client uses the
|
||||
default middlewares by wrapping the handler in the
|
||||
``GuzzleHttp\HandlerStack::create(callable $handler = null)`` static method.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\HandlerStack;
|
||||
use GuzzleHttp\Handler\CurlHandler;
|
||||
|
||||
$handler = new CurlHandler();
|
||||
$stack = HandlerStack::create($handler); // Wrap w/ middleware
|
||||
$client = new Client(['handler' => $stack]);
|
||||
|
||||
The ``create`` method adds default handlers to the ``HandlerStack``. When the
|
||||
``HandlerStack`` is resolved, the handlers will execute in the following order:
|
||||
|
||||
1. Sending request:
|
||||
|
||||
1. ``http_errors`` - No op when sending a request. The response status code
|
||||
is checked in the response processing when returning a response promise up
|
||||
the stack.
|
||||
2. ``allow_redirects`` - No op when sending a request. Following redirects
|
||||
occurs when a response promise is being returned up the stack.
|
||||
3. ``cookies`` - Adds cookies to requests.
|
||||
4. ``prepare_body`` - The body of an HTTP request will be prepared (e.g.,
|
||||
add default headers like Content-Length, Content-Type, etc.).
|
||||
5. <send request with handler>
|
||||
|
||||
2. Processing response:
|
||||
|
||||
1. ``prepare_body`` - no op on response processing.
|
||||
2. ``cookies`` - extracts response cookies into the cookie jar.
|
||||
3. ``allow_redirects`` - Follows redirects.
|
||||
4. ``http_errors`` - throws exceptions when the response status code ``>=``
|
||||
400.
|
||||
|
||||
When provided no ``$handler`` argument, ``GuzzleHttp\HandlerStack::create()``
|
||||
will choose the most appropriate handler based on the extensions available on
|
||||
your system.
|
||||
|
||||
.. important::
|
||||
|
||||
The handler provided to a client determines how request options are applied
|
||||
and utilized for each request sent by a client. For example, if you do not
|
||||
have a cookie middleware associated with a client, then setting the
|
||||
``cookies`` request option will have no effect on the request.
|
||||
|
||||
|
||||
Middleware
|
||||
==========
|
||||
|
||||
Middleware augments the functionality of handlers by invoking them in the
|
||||
process of generating responses. Middleware is implemented as a higher order
|
||||
function that takes the following form.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
|
||||
function my_middleware()
|
||||
{
|
||||
return function (callable $handler) {
|
||||
return function (RequestInterface $request, array $options) use ($handler) {
|
||||
return $handler($request, $options);
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
Middleware functions return a function that accepts the next handler to invoke.
|
||||
This returned function then returns another function that acts as a composed
|
||||
handler-- it accepts a request and options, and returns a promise that is
|
||||
fulfilled with a response. Your composed middleware can modify the request,
|
||||
add custom request options, and modify the promise returned by the downstream
|
||||
handler.
|
||||
|
||||
Here's an example of adding a header to each request.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
|
||||
function add_header($header, $value)
|
||||
{
|
||||
return function (callable $handler) use ($header, $value) {
|
||||
return function (
|
||||
RequestInterface $request,
|
||||
array $options
|
||||
) use ($handler, $header, $value) {
|
||||
$request = $request->withHeader($header, $value);
|
||||
return $handler($request, $options);
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
Once a middleware has been created, you can add it to a client by either
|
||||
wrapping the handler used by the client or by decorating a handler stack.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
use GuzzleHttp\HandlerStack;
|
||||
use GuzzleHttp\Handler\CurlHandler;
|
||||
use GuzzleHttp\Client;
|
||||
|
||||
$stack = new HandlerStack();
|
||||
$stack->setHandler(new CurlHandler());
|
||||
$stack->push(add_header('X-Foo', 'bar'));
|
||||
$client = new Client(['handler' => $stack]);
|
||||
|
||||
Now when you send a request, the client will use a handler composed with your
|
||||
added middleware, adding a header to each request.
|
||||
|
||||
Here's an example of creating a middleware that modifies the response of the
|
||||
downstream handler. This example adds a header to the response.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use GuzzleHttp\HandlerStack;
|
||||
use GuzzleHttp\Handler\CurlHandler;
|
||||
use GuzzleHttp\Client;
|
||||
|
||||
function add_response_header($header, $value)
|
||||
{
|
||||
return function (callable $handler) use ($header, $value) {
|
||||
return function (
|
||||
RequestInterface $request,
|
||||
array $options
|
||||
) use ($handler, $header, $value) {
|
||||
$promise = $handler($request, $options);
|
||||
return $promise->then(
|
||||
function (ResponseInterface $response) use ($header, $value) {
|
||||
return $response->withHeader($header, $value);
|
||||
}
|
||||
);
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
$stack = new HandlerStack();
|
||||
$stack->setHandler(new CurlHandler());
|
||||
$stack->push(add_response_header('X-Foo', 'bar'));
|
||||
$client = new Client(['handler' => $stack]);
|
||||
|
||||
Creating a middleware that modifies a request is made much simpler using the
|
||||
``GuzzleHttp\Middleware::mapRequest()`` middleware. This middleware accepts
|
||||
a function that takes the request argument and returns the request to send.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
use GuzzleHttp\HandlerStack;
|
||||
use GuzzleHttp\Handler\CurlHandler;
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\Middleware;
|
||||
|
||||
$stack = new HandlerStack();
|
||||
$stack->setHandler(new CurlHandler());
|
||||
|
||||
$stack->push(Middleware::mapRequest(function (RequestInterface $request) {
|
||||
return $request->withHeader('X-Foo', 'bar');
|
||||
}));
|
||||
|
||||
$client = new Client(['handler' => $stack]);
|
||||
|
||||
Modifying a response is also much simpler using the
|
||||
``GuzzleHttp\Middleware::mapResponse()`` middleware.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use GuzzleHttp\HandlerStack;
|
||||
use GuzzleHttp\Handler\CurlHandler;
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\Middleware;
|
||||
|
||||
$stack = new HandlerStack();
|
||||
$stack->setHandler(new CurlHandler());
|
||||
|
||||
$stack->push(Middleware::mapResponse(function (ResponseInterface $response) {
|
||||
return $response->withHeader('X-Foo', 'bar');
|
||||
}));
|
||||
|
||||
$client = new Client(['handler' => $stack]);
|
||||
|
||||
|
||||
HandlerStack
|
||||
============
|
||||
|
||||
A handler stack represents a stack of middleware to apply to a base handler
|
||||
function. You can push middleware to the stack to add to the top of the stack,
|
||||
and unshift middleware onto the stack to add to the bottom of the stack. When
|
||||
the stack is resolved, the handler is pushed onto the stack. Each value is
|
||||
then popped off of the stack, wrapping the previous value popped off of the
|
||||
stack.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
use GuzzleHttp\HandlerStack;
|
||||
use GuzzleHttp\Middleware;
|
||||
use GuzzleHttp\Client;
|
||||
|
||||
$stack = new HandlerStack();
|
||||
$stack->setHandler(\GuzzleHttp\choose_handler());
|
||||
|
||||
$stack->push(Middleware::mapRequest(function (RequestInterface $r) {
|
||||
echo 'A';
|
||||
return $r;
|
||||
});
|
||||
|
||||
$stack->push(Middleware::mapRequest(function (RequestInterface $r) {
|
||||
echo 'B';
|
||||
return $r;
|
||||
});
|
||||
|
||||
$stack->push(Middleware::mapRequest(function (RequestInterface $r) {
|
||||
echo 'C';
|
||||
return $r;
|
||||
});
|
||||
|
||||
$client->request('GET', 'http://httpbin.org/');
|
||||
// echoes 'ABC';
|
||||
|
||||
$stack->unshift(Middleware::mapRequest(function (RequestInterface $r) {
|
||||
echo '0';
|
||||
return $r;
|
||||
});
|
||||
|
||||
$client = new Client(['handler' => $stack]);
|
||||
$client->request('GET', 'http://httpbin.org/');
|
||||
// echoes '0ABC';
|
||||
|
||||
You can give middleware a name, which allows you to add middleware before
|
||||
other named middleware, after other named middleware, or remove middleware
|
||||
by name.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
use GuzzleHttp\Middleware;
|
||||
|
||||
// Add a middleware with a name
|
||||
$stack->push(Middleware::mapRequest(function (RequestInterface $r) {
|
||||
return $r->withHeader('X-Foo', 'Bar');
|
||||
}, 'add_foo');
|
||||
|
||||
// Add a middleware before a named middleware (unshift before).
|
||||
$stack->before('add_foo', Middleware::mapRequest(function (RequestInterface $r) {
|
||||
return $r->withHeader('X-Baz', 'Qux');
|
||||
}, 'add_baz');
|
||||
|
||||
// Add a middleware after a named middleware (pushed after).
|
||||
$stack->after('add_baz', Middleware::mapRequest(function (RequestInterface $r) {
|
||||
return $r->withHeader('X-Lorem', 'Ipsum');
|
||||
});
|
||||
|
||||
// Remove a middleware by name
|
||||
$stack->remove('add_foo');
|
||||
|
||||
|
||||
Creating a Handler
|
||||
==================
|
||||
|
||||
As stated earlier, a handler is a function accepts a
|
||||
``Psr\Http\Message\RequestInterface`` and array of request options and returns
|
||||
a ``GuzzleHttp\Promise\PromiseInterface`` that is fulfilled with a
|
||||
``Psr\Http\Message\ResponseInterface`` or rejected with an exception.
|
||||
|
||||
A handler is responsible for applying the following :doc:`request-options`.
|
||||
These request options are a subset of request options called
|
||||
"transfer options".
|
||||
|
||||
- :ref:`cert-option`
|
||||
- :ref:`connect_timeout-option`
|
||||
- :ref:`debug-option`
|
||||
- :ref:`delay-option`
|
||||
- :ref:`decode_content-option`
|
||||
- :ref:`expect-option`
|
||||
- :ref:`proxy-option`
|
||||
- :ref:`sink-option`
|
||||
- :ref:`timeout-option`
|
||||
- :ref:`ssl_key-option`
|
||||
- :ref:`stream-option`
|
||||
- :ref:`verify-option`
|
||||
54
wp-content/upgrade-temp-backup/plugins/w3-total-cache/vendor/guzzlehttp/guzzle/docs/index.rst
vendored
Normal file
54
wp-content/upgrade-temp-backup/plugins/w3-total-cache/vendor/guzzlehttp/guzzle/docs/index.rst
vendored
Normal file
@ -0,0 +1,54 @@
|
||||
.. title:: Guzzle, PHP HTTP client
|
||||
|
||||
====================
|
||||
Guzzle Documentation
|
||||
====================
|
||||
|
||||
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.
|
||||
|
||||
.. code-block:: 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')[0];
|
||||
// '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();
|
||||
|
||||
|
||||
User Guide
|
||||
==========
|
||||
|
||||
.. toctree::
|
||||
:maxdepth: 3
|
||||
|
||||
overview
|
||||
quickstart
|
||||
request-options
|
||||
psr7
|
||||
handlers-and-middleware
|
||||
testing
|
||||
faq
|
||||
161
wp-content/upgrade-temp-backup/plugins/w3-total-cache/vendor/guzzlehttp/guzzle/docs/overview.rst
vendored
Normal file
161
wp-content/upgrade-temp-backup/plugins/w3-total-cache/vendor/guzzlehttp/guzzle/docs/overview.rst
vendored
Normal file
@ -0,0 +1,161 @@
|
||||
========
|
||||
Overview
|
||||
========
|
||||
|
||||
Requirements
|
||||
============
|
||||
|
||||
#. PHP 5.5.0
|
||||
#. To use the PHP stream handler, ``allow_url_fopen`` must be enabled in your
|
||||
system's php.ini.
|
||||
#. To use the cURL handler, you must have a recent version of cURL >= 7.19.4
|
||||
compiled with OpenSSL and zlib.
|
||||
|
||||
.. note::
|
||||
|
||||
Guzzle no longer requires cURL in order to send HTTP requests. Guzzle will
|
||||
use the PHP stream wrapper to send HTTP requests if cURL is not installed.
|
||||
Alternatively, you can provide your own HTTP handler used to send requests.
|
||||
Keep in mind that cURL is still required for sending concurrent requests.
|
||||
|
||||
|
||||
.. _installation:
|
||||
|
||||
|
||||
Installation
|
||||
============
|
||||
|
||||
The recommended way to install Guzzle is with
|
||||
`Composer <http://getcomposer.org>`_. Composer is a dependency management tool
|
||||
for PHP that allows you to declare the dependencies your project needs and
|
||||
installs them into your project.
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
# Install Composer
|
||||
curl -sS https://getcomposer.org/installer | php
|
||||
|
||||
You can add Guzzle as a dependency using the composer.phar CLI:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
php composer.phar require guzzlehttp/guzzle:~6.0
|
||||
|
||||
Alternatively, you can specify Guzzle as a dependency in your project's
|
||||
existing composer.json file:
|
||||
|
||||
.. code-block:: js
|
||||
|
||||
{
|
||||
"require": {
|
||||
"guzzlehttp/guzzle": "~6.0"
|
||||
}
|
||||
}
|
||||
|
||||
After installing, you need to require Composer's autoloader:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
require 'vendor/autoload.php';
|
||||
|
||||
You can find out more on how to install Composer, configure autoloading, and
|
||||
other best-practices for defining dependencies at `getcomposer.org <http://getcomposer.org>`_.
|
||||
|
||||
|
||||
Bleeding edge
|
||||
-------------
|
||||
|
||||
During your development, you can keep up with the latest changes on the master
|
||||
branch by setting the version requirement for Guzzle to ``~6.0@dev``.
|
||||
|
||||
.. code-block:: js
|
||||
|
||||
{
|
||||
"require": {
|
||||
"guzzlehttp/guzzle": "~6.0@dev"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
License
|
||||
=======
|
||||
|
||||
Licensed using the `MIT license <http://opensource.org/licenses/MIT>`_.
|
||||
|
||||
Copyright (c) 2015 Michael Dowling <https://github.com/mtdowling>
|
||||
|
||||
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.
|
||||
|
||||
|
||||
Contributing
|
||||
============
|
||||
|
||||
|
||||
Guidelines
|
||||
----------
|
||||
|
||||
1. Guzzle utilizes PSR-1, PSR-2, PSR-4, and PSR-7.
|
||||
2. Guzzle is meant to be lean and fast with very few dependencies. This means
|
||||
that not every feature request will be accepted.
|
||||
3. Guzzle has a minimum PHP version requirement of PHP 5.5. Pull requests must
|
||||
not require a PHP version greater than PHP 5.5 unless the feature is only
|
||||
utilized conditionally.
|
||||
4. All pull requests must include unit tests to ensure the change works as
|
||||
expected and to prevent regressions.
|
||||
|
||||
|
||||
Running the tests
|
||||
-----------------
|
||||
|
||||
In order to contribute, you'll need to checkout the source from GitHub and
|
||||
install Guzzle's dependencies using Composer:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
git clone https://github.com/guzzle/guzzle.git
|
||||
cd guzzle && curl -s http://getcomposer.org/installer | php && ./composer.phar install --dev
|
||||
|
||||
Guzzle is unit tested with PHPUnit. Run the tests using the Makefile:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
make test
|
||||
|
||||
.. note::
|
||||
|
||||
You'll need to install node.js v0.5.0 or newer in order to perform
|
||||
integration tests on Guzzle's HTTP handlers.
|
||||
|
||||
|
||||
Reporting a security vulnerability
|
||||
==================================
|
||||
|
||||
We want to ensure that Guzzle is a secure HTTP client library for everyone. If
|
||||
you've discovered a security vulnerability in Guzzle, we appreciate your help
|
||||
in disclosing it to us in a `responsible manner <http://en.wikipedia.org/wiki/Responsible_disclosure>`_.
|
||||
|
||||
Publicly disclosing a vulnerability can put the entire community at risk. If
|
||||
you've discovered a security concern, please email us at
|
||||
security@guzzlephp.org. We'll work with you to make sure that we understand the
|
||||
scope of the issue, and that we fully address your concern. We consider
|
||||
correspondence sent to security@guzzlephp.org our highest priority, and work to
|
||||
address any issues that arise as quickly as possible.
|
||||
|
||||
After a security vulnerability has been corrected, a security hotfix release will
|
||||
be deployed as soon as possible.
|
||||
456
wp-content/upgrade-temp-backup/plugins/w3-total-cache/vendor/guzzlehttp/guzzle/docs/psr7.rst
vendored
Normal file
456
wp-content/upgrade-temp-backup/plugins/w3-total-cache/vendor/guzzlehttp/guzzle/docs/psr7.rst
vendored
Normal file
@ -0,0 +1,456 @@
|
||||
================
|
||||
Guzzle and PSR-7
|
||||
================
|
||||
|
||||
Guzzle utilizes PSR-7 as the HTTP message interface. This allows Guzzle to work
|
||||
with any other library that utilizes PSR-7 message interfaces.
|
||||
|
||||
Guzzle is an HTTP client that sends HTTP requests to a server and receives HTTP
|
||||
responses. Both requests and responses are referred to as messages.
|
||||
|
||||
Guzzle relies on the ``guzzlehttp/psr7`` Composer package for its message
|
||||
implementation of PSR-7.
|
||||
|
||||
You can create a request using the ``GuzzleHttp\Psr7\Request`` class:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
use GuzzleHttp\Psr7\Request;
|
||||
|
||||
$request = new Request('GET', 'http://httpbin.org/get');
|
||||
|
||||
// You can provide other optional constructor arguments.
|
||||
$headers = ['X-Foo' => 'Bar'];
|
||||
$body = 'hello!';
|
||||
$request = new Request('PUT', 'http://httpbin.org/put', $headers, $body);
|
||||
|
||||
You can create a response using the ``GuzzleHttp\Psr7\Response`` class:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
use GuzzleHttp\Psr7\Response;
|
||||
|
||||
// The constructor requires no arguments.
|
||||
$response = new Response();
|
||||
echo $response->getStatusCode(); // 200
|
||||
echo $response->getProtocolVersion(); // 1.1
|
||||
|
||||
// You can supply any number of optional arguments.
|
||||
$status = 200;
|
||||
$headers = ['X-Foo' => 'Bar'];
|
||||
$body = 'hello!';
|
||||
$protocol = '1.1';
|
||||
$response = new Response($status, $headers, $body, $protocol);
|
||||
|
||||
|
||||
Headers
|
||||
=======
|
||||
|
||||
Both request and response messages contain HTTP headers.
|
||||
|
||||
|
||||
Accessing Headers
|
||||
-----------------
|
||||
|
||||
You can check if a request or response has a specific header using the
|
||||
``hasHeader()`` method.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
use GuzzleHttp\Psr7;
|
||||
|
||||
$request = new Psr7\Request('GET', '/', ['X-Foo' => 'bar']);
|
||||
|
||||
if ($request->hasHeader('X-Foo')) {
|
||||
echo 'It is there';
|
||||
}
|
||||
|
||||
You can retrieve all the header values as an array of strings using
|
||||
``getHeader()``.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
$request->getHeader('X-Foo'); // ['bar']
|
||||
|
||||
// Retrieving a missing header returns an empty array.
|
||||
$request->getHeader('X-Bar'); // []
|
||||
|
||||
You can iterate over the headers of a message using the ``getHeaders()``
|
||||
method.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
foreach ($request->getHeaders() as $name => $values) {
|
||||
echo $name . ': ' . implode(', ', $values) . "\r\n";
|
||||
}
|
||||
|
||||
|
||||
Complex Headers
|
||||
---------------
|
||||
|
||||
Some headers contain additional key value pair information. For example, Link
|
||||
headers contain a link and several key value pairs:
|
||||
|
||||
::
|
||||
|
||||
<http://foo.com>; rel="thing"; type="image/jpeg"
|
||||
|
||||
Guzzle provides a convenience feature that can be used to parse these types of
|
||||
headers:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
use GuzzleHttp\Psr7;
|
||||
|
||||
$request = new Psr7\Request('GET', '/', [
|
||||
'Link' => '<http:/.../front.jpeg>; rel="front"; type="image/jpeg"'
|
||||
]);
|
||||
|
||||
$parsed = Psr7\parse_header($request->getHeader('Link'));
|
||||
var_export($parsed);
|
||||
|
||||
Will output:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
array (
|
||||
0 =>
|
||||
array (
|
||||
0 => '<http:/.../front.jpeg>',
|
||||
'rel' => 'front',
|
||||
'type' => 'image/jpeg',
|
||||
),
|
||||
)
|
||||
|
||||
The result contains a hash of key value pairs. Header values that have no key
|
||||
(i.e., the link) are indexed numerically while headers parts that form a key
|
||||
value pair are added as a key value pair.
|
||||
|
||||
|
||||
Body
|
||||
====
|
||||
|
||||
Both request and response messages can contain a body.
|
||||
|
||||
You can retrieve the body of a message using the ``getBody()`` method:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
$response = GuzzleHttp\get('http://httpbin.org/get');
|
||||
echo $response->getBody();
|
||||
// JSON string: { ... }
|
||||
|
||||
The body used in request and response objects is a
|
||||
``Psr\Http\Message\StreamInterface``. This stream is used for both
|
||||
uploading data and downloading data. Guzzle will, by default, store the body of
|
||||
a message in a stream that uses PHP temp streams. When the size of the body
|
||||
exceeds 2 MB, the stream will automatically switch to storing data on disk
|
||||
rather than in memory (protecting your application from memory exhaustion).
|
||||
|
||||
The easiest way to create a body for a message is using the ``stream_for``
|
||||
function from the ``GuzzleHttp\Psr7`` namespace --
|
||||
``GuzzleHttp\Psr7\stream_for``. This function accepts strings, resources,
|
||||
callables, iterators, other streamables, and returns an instance of
|
||||
``Psr\Http\Message\StreamInterface``.
|
||||
|
||||
The body of a request or response can be cast to a string or you can read and
|
||||
write bytes off of the stream as needed.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
use GuzzleHttp\Stream\Stream;
|
||||
$response = $client->request('GET', 'http://httpbin.org/get');
|
||||
|
||||
echo $response->getBody()->read(4);
|
||||
echo $response->getBody()->read(4);
|
||||
echo $response->getBody()->read(1024);
|
||||
var_export($response->eof());
|
||||
|
||||
|
||||
Requests
|
||||
========
|
||||
|
||||
Requests are sent from a client to a server. Requests include the method to
|
||||
be applied to a resource, the identifier of the resource, and the protocol
|
||||
version to use.
|
||||
|
||||
|
||||
Request Methods
|
||||
---------------
|
||||
|
||||
When creating a request, you are expected to provide the HTTP method you wish
|
||||
to perform. You can specify any method you'd like, including a custom method
|
||||
that might not be part of RFC 7231 (like "MOVE").
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
// Create a request using a completely custom HTTP method
|
||||
$request = new \GuzzleHttp\Psr7\Request('MOVE', 'http://httpbin.org/move');
|
||||
|
||||
echo $request->getMethod();
|
||||
// MOVE
|
||||
|
||||
You can create and send a request using methods on a client that map to the
|
||||
HTTP method you wish to use.
|
||||
|
||||
:GET: ``$client->get('http://httpbin.org/get', [/** options **/])``
|
||||
:POST: ``$client->post('http://httpbin.org/post', [/** options **/])``
|
||||
:HEAD: ``$client->head('http://httpbin.org/get', [/** options **/])``
|
||||
:PUT: ``$client->put('http://httpbin.org/put', [/** options **/])``
|
||||
:DELETE: ``$client->delete('http://httpbin.org/delete', [/** options **/])``
|
||||
:OPTIONS: ``$client->options('http://httpbin.org/get', [/** options **/])``
|
||||
:PATCH: ``$client->patch('http://httpbin.org/put', [/** options **/])``
|
||||
|
||||
For example:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
$response = $client->patch('http://httpbin.org/patch', ['body' => 'content']);
|
||||
|
||||
|
||||
Request URI
|
||||
-----------
|
||||
|
||||
The request URI is represented by a ``Psr\Http\Message\UriInterface`` object.
|
||||
Guzzle provides an implementation of this interface using the
|
||||
``GuzzleHttp\Psr7\Uri`` class.
|
||||
|
||||
When creating a request, you can provide the URI as a string or an instance of
|
||||
``Psr\Http\Message\UriInterface``.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
$response = $client->request('GET', 'http://httpbin.org/get?q=foo');
|
||||
|
||||
|
||||
Scheme
|
||||
------
|
||||
|
||||
The `scheme <http://tools.ietf.org/html/rfc3986#section-3.1>`_ of a request
|
||||
specifies the protocol to use when sending the request. When using Guzzle, the
|
||||
scheme can be set to "http" or "https".
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
$request = new Request('GET', 'http://httpbin.org');
|
||||
echo $request->getUri()->getScheme(); // http
|
||||
echo $request->getUri(); // http://httpbin.org
|
||||
|
||||
|
||||
Host
|
||||
----
|
||||
|
||||
The host is accessible using the URI owned by the request or by accessing the
|
||||
Host header.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
$request = new Request('GET', 'http://httpbin.org');
|
||||
echo $request->getUri()->getHost(); // httpbin.org
|
||||
echo $request->getHeader('Host'); // httpbin.org
|
||||
|
||||
|
||||
Port
|
||||
----
|
||||
|
||||
No port is necessary when using the "http" or "https" schemes.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
$request = new Request('GET', 'http://httpbin.org:8080');
|
||||
echo $request->getUri()->getPort(); // 8080
|
||||
echo $request->getUri(); // http://httpbin.org:8080
|
||||
|
||||
|
||||
Path
|
||||
----
|
||||
|
||||
The path of a request is accessible via the URI object.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
$request = new Request('GET', 'http://httpbin.org/get');
|
||||
echo $request->getUri()->getPath(); // /get
|
||||
|
||||
The contents of the path will be automatically filtered to ensure that only
|
||||
allowed characters are present in the path. Any characters that are not allowed
|
||||
in the path will be percent-encoded according to
|
||||
`RFC 3986 section 3.3 <https://tools.ietf.org/html/rfc3986#section-3.3>`_
|
||||
|
||||
|
||||
Query string
|
||||
------------
|
||||
|
||||
The query string of a request can be accessed using the ``getQuery()`` of the
|
||||
URI object owned by the request.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
$request = new Request('GET', 'http://httpbin.org/?foo=bar');
|
||||
echo $request->getUri()->getQuery(); // foo=bar
|
||||
|
||||
The contents of the query string will be automatically filtered to ensure that
|
||||
only allowed characters are present in the query string. Any characters that
|
||||
are not allowed in the query string will be percent-encoded according to
|
||||
`RFC 3986 section 3.4 <https://tools.ietf.org/html/rfc3986#section-3.4>`_
|
||||
|
||||
|
||||
Responses
|
||||
=========
|
||||
|
||||
Responses are the HTTP messages a client receives from a server after sending
|
||||
an HTTP request message.
|
||||
|
||||
|
||||
Start-Line
|
||||
----------
|
||||
|
||||
The start-line of a response contains the protocol and protocol version,
|
||||
status code, and reason phrase.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
$client = new \GuzzleHttp\Client();
|
||||
$response = $client->request('GET', 'http://httpbin.org/get');
|
||||
|
||||
echo $response->getStatusCode(); // 200
|
||||
echo $response->getReasonPhrase(); // OK
|
||||
echo $response->getProtocolVersion(); // 1.1
|
||||
|
||||
|
||||
Body
|
||||
----
|
||||
|
||||
As described earlier, you can get the body of a response using the
|
||||
``getBody()`` method.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
$body = $response->getBody();
|
||||
echo $body;
|
||||
// Cast to a string: { ... }
|
||||
$body->seek(0);
|
||||
// Rewind the body
|
||||
$body->read(1024);
|
||||
// Read bytes of the body
|
||||
|
||||
|
||||
Streams
|
||||
=======
|
||||
|
||||
Guzzle uses PSR-7 stream objects to represent request and response message
|
||||
bodies. These stream objects allow you to work with various types of data all
|
||||
using a common interface.
|
||||
|
||||
HTTP messages consist of a start-line, headers, and a body. The body of an HTTP
|
||||
message can be very small or extremely large. Attempting to represent the body
|
||||
of a message as a string can easily consume more memory than intended because
|
||||
the body must be stored completely in memory. Attempting to store the body of a
|
||||
request or response in memory would preclude the use of that implementation from
|
||||
being able to work with large message bodies. The StreamInterface is used in
|
||||
order to hide the implementation details of where a stream of data is read from
|
||||
or written to.
|
||||
|
||||
The PSR-7 ``Psr\Http\Message\StreamInterface`` exposes several methods
|
||||
that enable streams to be read from, written to, and traversed effectively.
|
||||
|
||||
Streams expose their capabilities using three methods: ``isReadable()``,
|
||||
``isWritable()``, and ``isSeekable()``. These methods can be used by stream
|
||||
collaborators to determine if a stream is capable of their requirements.
|
||||
|
||||
Each stream instance has various capabilities: they can be read-only,
|
||||
write-only, read-write, allow arbitrary random access (seeking forwards or
|
||||
backwards to any location), or only allow sequential access (for example in the
|
||||
case of a socket or pipe).
|
||||
|
||||
Guzzle uses the ``guzzlehttp/psr7`` package to provide stream support. More
|
||||
information on using streams, creating streams, converting streams to PHP
|
||||
stream resource, and stream decorators can be found in the
|
||||
`Guzzle PSR-7 documentation <https://github.com/guzzle/psr7/blob/master/README.md>`_.
|
||||
|
||||
|
||||
Creating Streams
|
||||
----------------
|
||||
|
||||
The best way to create a stream is using the ``GuzzleHttp\Psr7\stream_for``
|
||||
function. This function accepts strings, resources returned from ``fopen()``,
|
||||
an object that implements ``__toString()``, iterators, callables, and instances
|
||||
of ``Psr\Http\Message\StreamInterface``.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
use GuzzleHttp\Psr7;
|
||||
|
||||
$stream = Psr7\stream_for('string data');
|
||||
echo $stream;
|
||||
// string data
|
||||
echo $stream->read(3);
|
||||
// str
|
||||
echo $stream->getContents();
|
||||
// ing data
|
||||
var_export($stream->eof());
|
||||
// true
|
||||
var_export($stream->tell());
|
||||
// 11
|
||||
|
||||
You can create streams from iterators. The iterator can yield any number of
|
||||
bytes per iteration. Any excess bytes returned by the iterator that were not
|
||||
requested by a stream consumer will be buffered until a subsequent read.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
use GuzzleHttp\Psr7;
|
||||
|
||||
$generator = function ($bytes) {
|
||||
for ($i = 0; $i < $bytes; $i++) {
|
||||
yield '.';
|
||||
}
|
||||
};
|
||||
|
||||
$iter = $generator(1024);
|
||||
$stream = Psr7\stream_for($iter);
|
||||
echo $stream->read(3); // ...
|
||||
|
||||
|
||||
Metadata
|
||||
--------
|
||||
|
||||
Streams expose stream metadata through the ``getMetadata()`` method. This
|
||||
method provides the data you would retrieve when calling PHP's
|
||||
`stream_get_meta_data() function <http://php.net/manual/en/function.stream-get-meta-data.php>`_,
|
||||
and can optionally expose other custom data.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
use GuzzleHttp\Psr7;
|
||||
|
||||
$resource = fopen('/path/to/file', 'r');
|
||||
$stream = Psr7\stream_for($resource);
|
||||
echo $stream->getMetadata('uri');
|
||||
// /path/to/file
|
||||
var_export($stream->isReadable());
|
||||
// true
|
||||
var_export($stream->isWritable());
|
||||
// false
|
||||
var_export($stream->isSeekable());
|
||||
// true
|
||||
|
||||
|
||||
Stream Decorators
|
||||
-----------------
|
||||
|
||||
Adding custom functionality to streams is very simple with stream decorators.
|
||||
Guzzle provides several built-in decorators that provide additional stream
|
||||
functionality.
|
||||
|
||||
- `AppendStream <https://github.com/guzzle/psr7#appendstream>`_
|
||||
- `BufferStream <https://github.com/guzzle/psr7#bufferstream>`_
|
||||
- `CachingStream <https://github.com/guzzle/psr7#cachingstream>`_
|
||||
- `DroppingStream <https://github.com/guzzle/psr7#droppingstream>`_
|
||||
- `FnStream <https://github.com/guzzle/psr7#fnstream>`_
|
||||
- `InflateStream <https://github.com/guzzle/psr7#inflatestream>`_
|
||||
- `LazyOpenStream <https://github.com/guzzle/psr7#lazyopenstream>`_
|
||||
- `LimitStream <https://github.com/guzzle/psr7#limitstream>`_
|
||||
- `MultipartStream <https://github.com/guzzle/psr7#multipartstream>`_
|
||||
- `NoSeekStream <https://github.com/guzzle/psr7#noseekstream>`_
|
||||
- `PumpStream <https://github.com/guzzle/psr7#pumpstream>`_
|
||||
624
wp-content/upgrade-temp-backup/plugins/w3-total-cache/vendor/guzzlehttp/guzzle/docs/quickstart.rst
vendored
Normal file
624
wp-content/upgrade-temp-backup/plugins/w3-total-cache/vendor/guzzlehttp/guzzle/docs/quickstart.rst
vendored
Normal file
@ -0,0 +1,624 @@
|
||||
==========
|
||||
Quickstart
|
||||
==========
|
||||
|
||||
This page provides a quick introduction to Guzzle and introductory examples.
|
||||
If you have not already installed, Guzzle, head over to the :ref:`installation`
|
||||
page.
|
||||
|
||||
|
||||
Making a Request
|
||||
================
|
||||
|
||||
You can send requests with Guzzle using a ``GuzzleHttp\ClientInterface``
|
||||
object.
|
||||
|
||||
|
||||
Creating a Client
|
||||
-----------------
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
use GuzzleHttp\Client;
|
||||
|
||||
$client = new Client([
|
||||
// Base URI is used with relative requests
|
||||
'base_uri' => 'http://httpbin.org',
|
||||
// You can set any number of default request options.
|
||||
'timeout' => 2.0,
|
||||
]);
|
||||
|
||||
Clients are immutable in Guzzle 6, which means that you cannot change the defaults used by a client after it's created.
|
||||
|
||||
The client constructor accepts an associative array of options:
|
||||
|
||||
``base_uri``
|
||||
(string|UriInterface) Base URI of the client that is merged into relative
|
||||
URIs. Can be a string or instance of UriInterface. When a relative URI
|
||||
is provided to a client, the client will combine the base URI with the
|
||||
relative URI using the rules described in
|
||||
`RFC 3986, section 2 <http://tools.ietf.org/html/rfc3986#section-5.2>`_.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
// Create a client with a base URI
|
||||
$client = new GuzzleHttp\Client(['base_uri' => 'https://foo.com/api/']);
|
||||
// Send a request to https://foo.com/api/test
|
||||
$response = $client->request('GET', 'test');
|
||||
// Send a request to https://foo.com/root
|
||||
$response = $client->request('GET', '/root');
|
||||
|
||||
Don't feel like reading RFC 3986? Here are some quick examples on how a
|
||||
``base_uri`` is resolved with another URI.
|
||||
|
||||
======================= ================== ===============================
|
||||
base_uri URI Result
|
||||
======================= ================== ===============================
|
||||
``http://foo.com`` ``/bar`` ``http://foo.com/bar``
|
||||
``http://foo.com/foo`` ``/bar`` ``http://foo.com/bar``
|
||||
``http://foo.com/foo`` ``bar`` ``http://foo.com/bar``
|
||||
``http://foo.com/foo/`` ``bar`` ``http://foo.com/foo/bar``
|
||||
``http://foo.com`` ``http://baz.com`` ``http://baz.com``
|
||||
``http://foo.com/?bar`` ``bar`` ``http://foo.com/bar``
|
||||
======================= ================== ===============================
|
||||
|
||||
``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.
|
||||
|
||||
``...``
|
||||
(mixed) All other options passed to the constructor are used as default
|
||||
request options with every request created by the client.
|
||||
|
||||
|
||||
Sending Requests
|
||||
----------------
|
||||
|
||||
Magic methods on the client make it easy to send synchronous requests:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
$response = $client->get('http://httpbin.org/get');
|
||||
$response = $client->delete('http://httpbin.org/delete');
|
||||
$response = $client->head('http://httpbin.org/get');
|
||||
$response = $client->options('http://httpbin.org/get');
|
||||
$response = $client->patch('http://httpbin.org/patch');
|
||||
$response = $client->post('http://httpbin.org/post');
|
||||
$response = $client->put('http://httpbin.org/put');
|
||||
|
||||
You can create a request and then send the request with the client when you're
|
||||
ready:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
use GuzzleHttp\Psr7\Request;
|
||||
|
||||
$request = new Request('PUT', 'http://httpbin.org/put');
|
||||
$response = $client->send($request, ['timeout' => 2]);
|
||||
|
||||
Client objects provide a great deal of flexibility in how request are
|
||||
transferred including default request options, default handler stack middleware
|
||||
that are used by each request, and a base URI that allows you to send requests
|
||||
with relative URIs.
|
||||
|
||||
You can find out more about client middleware in the
|
||||
:doc:`handlers-and-middleware` page of the documentation.
|
||||
|
||||
|
||||
Async Requests
|
||||
--------------
|
||||
|
||||
You can send asynchronous requests using the magic methods provided by a client:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
$promise = $client->getAsync('http://httpbin.org/get');
|
||||
$promise = $client->deleteAsync('http://httpbin.org/delete');
|
||||
$promise = $client->headAsync('http://httpbin.org/get');
|
||||
$promise = $client->optionsAsync('http://httpbin.org/get');
|
||||
$promise = $client->patchAsync('http://httpbin.org/patch');
|
||||
$promise = $client->postAsync('http://httpbin.org/post');
|
||||
$promise = $client->putAsync('http://httpbin.org/put');
|
||||
|
||||
You can also use the `sendAsync()` and `requestAsync()` methods of a client:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
use GuzzleHttp\Psr7\Request;
|
||||
|
||||
// Create a PSR-7 request object to send
|
||||
$headers = ['X-Foo' => 'Bar'];
|
||||
$body = 'Hello!';
|
||||
$request = new Request('HEAD', 'http://httpbin.org/head', $headers, $body);
|
||||
$promise = $client->sendAsync($request);
|
||||
|
||||
// Or, if you don't need to pass in a request instance:
|
||||
$promise = $client->requestAsync('GET', 'http://httpbin.org/get');
|
||||
|
||||
The promise returned by these methods implements the
|
||||
`Promises/A+ spec <https://promisesaplus.com/>`_, provided by the
|
||||
`Guzzle promises library <https://github.com/guzzle/promises>`_. This means
|
||||
that you can chain ``then()`` calls off of the promise. These then calls are
|
||||
either fulfilled with a successful ``Psr\Http\Message\ResponseInterface`` or
|
||||
rejected with an exception.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use GuzzleHttp\Exception\RequestException;
|
||||
|
||||
$promise = $client->requestAsync('GET', 'http://httpbin.org/get');
|
||||
$promise->then(
|
||||
function (ResponseInterface $res) {
|
||||
echo $res->getStatusCode() . "\n";
|
||||
},
|
||||
function (RequestException $e) {
|
||||
echo $e->getMessage() . "\n";
|
||||
echo $e->getRequest()->getMethod();
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
Concurrent requests
|
||||
-------------------
|
||||
|
||||
You can send multiple requests concurrently using promises and asynchronous
|
||||
requests.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\Promise;
|
||||
|
||||
$client = new Client(['base_uri' => 'http://httpbin.org/']);
|
||||
|
||||
// Initiate each request but do not block
|
||||
$promises = [
|
||||
'image' => $client->getAsync('/image'),
|
||||
'png' => $client->getAsync('/image/png'),
|
||||
'jpeg' => $client->getAsync('/image/jpeg'),
|
||||
'webp' => $client->getAsync('/image/webp')
|
||||
];
|
||||
|
||||
// Wait for the requests to complete; throws a ConnectException
|
||||
// if any of the requests fail
|
||||
$responses = Promise\unwrap($promises);
|
||||
|
||||
// Wait for the requests to complete, even if some of them fail
|
||||
$responses = Promise\settle($promises)->wait();
|
||||
|
||||
// You can access each response using the key of the promise
|
||||
echo $responses['image']->getHeader('Content-Length')[0];
|
||||
echo $responses['png']->getHeader('Content-Length')[0];
|
||||
|
||||
You can use the ``GuzzleHttp\Pool`` object when you have an indeterminate
|
||||
amount of requests you wish to send.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\Exception\RequestException;
|
||||
use GuzzleHttp\Pool;
|
||||
use GuzzleHttp\Psr7\Request;
|
||||
use GuzzleHttp\Psr7\Response;
|
||||
|
||||
$client = new Client();
|
||||
|
||||
$requests = function ($total) {
|
||||
$uri = 'http://127.0.0.1:8126/guzzle-server/perf';
|
||||
for ($i = 0; $i < $total; $i++) {
|
||||
yield new Request('GET', $uri);
|
||||
}
|
||||
};
|
||||
|
||||
$pool = new Pool($client, $requests(100), [
|
||||
'concurrency' => 5,
|
||||
'fulfilled' => function (Response $response, $index) {
|
||||
// this is delivered each successful response
|
||||
},
|
||||
'rejected' => function (RequestException $reason, $index) {
|
||||
// this is delivered each failed request
|
||||
},
|
||||
]);
|
||||
|
||||
// Initiate the transfers and create a promise
|
||||
$promise = $pool->promise();
|
||||
|
||||
// Force the pool of requests to complete.
|
||||
$promise->wait();
|
||||
|
||||
Or using a closure that will return a promise once the pool calls the closure.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
$client = new Client();
|
||||
|
||||
$requests = function ($total) use ($client) {
|
||||
$uri = 'http://127.0.0.1:8126/guzzle-server/perf';
|
||||
for ($i = 0; $i < $total; $i++) {
|
||||
yield function() use ($client, $uri) {
|
||||
return $client->getAsync($uri);
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
$pool = new Pool($client, $requests(100));
|
||||
|
||||
|
||||
Using Responses
|
||||
===============
|
||||
|
||||
In the previous examples, we retrieved a ``$response`` variable or we were
|
||||
delivered a response from a promise. The response object implements a PSR-7
|
||||
response, ``Psr\Http\Message\ResponseInterface``, and contains lots of
|
||||
helpful information.
|
||||
|
||||
You can get the status code and reason phrase of the response:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
$code = $response->getStatusCode(); // 200
|
||||
$reason = $response->getReasonPhrase(); // OK
|
||||
|
||||
You can retrieve headers from the response:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
// Check if a header exists.
|
||||
if ($response->hasHeader('Content-Length')) {
|
||||
echo "It exists";
|
||||
}
|
||||
|
||||
// Get a header from the response.
|
||||
echo $response->getHeader('Content-Length')[0];
|
||||
|
||||
// Get all of the response headers.
|
||||
foreach ($response->getHeaders() as $name => $values) {
|
||||
echo $name . ': ' . implode(', ', $values) . "\r\n";
|
||||
}
|
||||
|
||||
The body of a response can be retrieved using the ``getBody`` method. The body
|
||||
can be used as a string, cast to a string, or used as a stream like object.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
$body = $response->getBody();
|
||||
// Implicitly cast the body to a string and echo it
|
||||
echo $body;
|
||||
// Explicitly cast the body to a string
|
||||
$stringBody = (string) $body;
|
||||
// Read 10 bytes from the body
|
||||
$tenBytes = $body->read(10);
|
||||
// Read the remaining contents of the body as a string
|
||||
$remainingBytes = $body->getContents();
|
||||
|
||||
|
||||
Query String Parameters
|
||||
=======================
|
||||
|
||||
You can provide query string parameters with a request in several ways.
|
||||
|
||||
You can set query string parameters in the request's URI:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
$response = $client->request('GET', 'http://httpbin.org?foo=bar');
|
||||
|
||||
You can specify the query string parameters using the ``query`` request
|
||||
option as an array.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
$client->request('GET', 'http://httpbin.org', [
|
||||
'query' => ['foo' => 'bar']
|
||||
]);
|
||||
|
||||
Providing the option as an array will use PHP's ``http_build_query`` function
|
||||
to format the query string.
|
||||
|
||||
And finally, you can provide the ``query`` request option as a string.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
$client->request('GET', 'http://httpbin.org', ['query' => 'foo=bar']);
|
||||
|
||||
|
||||
Uploading Data
|
||||
==============
|
||||
|
||||
Guzzle provides several methods for uploading data.
|
||||
|
||||
You can send requests that contain a stream of data by passing a string,
|
||||
resource returned from ``fopen``, or an instance of a
|
||||
``Psr\Http\Message\StreamInterface`` to the ``body`` request option.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
// Provide the body as a string.
|
||||
$r = $client->request('POST', 'http://httpbin.org/post', [
|
||||
'body' => 'raw data'
|
||||
]);
|
||||
|
||||
// Provide an fopen resource.
|
||||
$body = fopen('/path/to/file', 'r');
|
||||
$r = $client->request('POST', 'http://httpbin.org/post', ['body' => $body]);
|
||||
|
||||
// Use the stream_for() function to create a PSR-7 stream.
|
||||
$body = \GuzzleHttp\Psr7\stream_for('hello!');
|
||||
$r = $client->request('POST', 'http://httpbin.org/post', ['body' => $body]);
|
||||
|
||||
An easy way to upload JSON data and set the appropriate header is using the
|
||||
``json`` request option:
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
$r = $client->request('PUT', 'http://httpbin.org/put', [
|
||||
'json' => ['foo' => 'bar']
|
||||
]);
|
||||
|
||||
|
||||
POST/Form Requests
|
||||
------------------
|
||||
|
||||
In addition to specifying the raw data of a request using the ``body`` request
|
||||
option, Guzzle provides helpful abstractions over sending POST data.
|
||||
|
||||
|
||||
Sending form fields
|
||||
~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Sending ``application/x-www-form-urlencoded`` POST requests requires that you
|
||||
specify the POST fields as an array in the ``form_params`` request options.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
$response = $client->request('POST', 'http://httpbin.org/post', [
|
||||
'form_params' => [
|
||||
'field_name' => 'abc',
|
||||
'other_field' => '123',
|
||||
'nested_field' => [
|
||||
'nested' => 'hello'
|
||||
]
|
||||
]
|
||||
]);
|
||||
|
||||
|
||||
Sending form files
|
||||
~~~~~~~~~~~~~~~~~~
|
||||
|
||||
You can send files along with a form (``multipart/form-data`` POST requests),
|
||||
using the ``multipart`` request option. ``multipart`` accepts an array of
|
||||
associative arrays, where each associative array contains the following keys:
|
||||
|
||||
- name: (required, string) key mapping to the form field name.
|
||||
- contents: (required, mixed) Provide a string to send the contents of the
|
||||
file as a string, provide an fopen resource to stream the contents from a
|
||||
PHP stream, or provide a ``Psr\Http\Message\StreamInterface`` to stream
|
||||
the contents from a PSR-7 stream.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
$response = $client->request('POST', 'http://httpbin.org/post', [
|
||||
'multipart' => [
|
||||
[
|
||||
'name' => 'field_name',
|
||||
'contents' => 'abc'
|
||||
],
|
||||
[
|
||||
'name' => 'file_name',
|
||||
'contents' => fopen('/path/to/file', 'r')
|
||||
],
|
||||
[
|
||||
'name' => 'other_file',
|
||||
'contents' => 'hello',
|
||||
'filename' => 'filename.txt',
|
||||
'headers' => [
|
||||
'X-Foo' => 'this is an extra header to include'
|
||||
]
|
||||
]
|
||||
]
|
||||
]);
|
||||
|
||||
|
||||
Cookies
|
||||
=======
|
||||
|
||||
Guzzle can maintain a cookie session for you if instructed using the
|
||||
``cookies`` request option. When sending a request, the ``cookies`` option
|
||||
must be set to an instance of ``GuzzleHttp\Cookie\CookieJarInterface``.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
// Use a specific cookie jar
|
||||
$jar = new \GuzzleHttp\Cookie\CookieJar;
|
||||
$r = $client->request('GET', 'http://httpbin.org/cookies', [
|
||||
'cookies' => $jar
|
||||
]);
|
||||
|
||||
You can set ``cookies`` to ``true`` in a client constructor if you would like
|
||||
to use a shared cookie jar for all requests.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
// Use a shared client cookie jar
|
||||
$client = new \GuzzleHttp\Client(['cookies' => true]);
|
||||
$r = $client->request('GET', 'http://httpbin.org/cookies');
|
||||
|
||||
Different implementations exist for the ``GuzzleHttp\Cookie\CookieJarInterface``
|
||||
:
|
||||
|
||||
- The ``GuzzleHttp\Cookie\CookieJar`` class stores cookies as an array.
|
||||
- The ``GuzzleHttp\Cookie\FileCookieJar`` class persists non-session cookies
|
||||
using a JSON formatted file.
|
||||
- The ``GuzzleHttp\Cookie\SessionCookieJar`` class persists cookies in the
|
||||
client session.
|
||||
|
||||
You can manually set cookies into a cookie jar with the named constructor
|
||||
``fromArray(array $cookies, $domain)``.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
$jar = \GuzzleHttp\Cookie\CookieJar::fromArray(
|
||||
[
|
||||
'some_cookie' => 'foo',
|
||||
'other_cookie' => 'barbaz1234'
|
||||
],
|
||||
'example.org'
|
||||
);
|
||||
|
||||
You can get a cookie by its name with the ``getCookieByName($name)`` method
|
||||
which returns a ``GuzzleHttp\Cookie\SetCookie`` instance.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
$cookie = $jar->getCookieByName('some_cookie');
|
||||
|
||||
$cookie->getValue(); // 'foo'
|
||||
$cookie->getDomain(); // 'example.org'
|
||||
$cookie->getExpires(); // expiration date as a Unix timestamp
|
||||
|
||||
The cookies can be also fetched into an array thanks to the `toArray()` method.
|
||||
The ``GuzzleHttp\Cookie\CookieJarInterface`` interface extends
|
||||
``Traversable`` so it can be iterated in a foreach loop.
|
||||
|
||||
|
||||
Redirects
|
||||
=========
|
||||
|
||||
Guzzle will automatically follow redirects unless you tell it not to. You can
|
||||
customize the redirect behavior using the ``allow_redirects`` request option.
|
||||
|
||||
- Set to ``true`` to enable normal redirects with a maximum number of 5
|
||||
redirects. This is the default setting.
|
||||
- Set to ``false`` to disable redirects.
|
||||
- Pass an associative array containing the 'max' key to specify the maximum
|
||||
number of redirects and optionally provide a 'strict' key value to specify
|
||||
whether or not to use strict RFC compliant redirects (meaning redirect POST
|
||||
requests with POST requests vs. doing what most browsers do which is
|
||||
redirect POST requests with GET requests).
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
$response = $client->request('GET', 'http://github.com');
|
||||
echo $response->getStatusCode();
|
||||
// 200
|
||||
|
||||
The following example shows that redirects can be disabled.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
$response = $client->request('GET', 'http://github.com', [
|
||||
'allow_redirects' => false
|
||||
]);
|
||||
echo $response->getStatusCode();
|
||||
// 301
|
||||
|
||||
|
||||
Exceptions
|
||||
==========
|
||||
|
||||
**Tree View**
|
||||
|
||||
The following tree view describes how the Guzzle Exceptions depend
|
||||
on each other.
|
||||
|
||||
.. code-block:: none
|
||||
|
||||
. \RuntimeException
|
||||
├── SeekException (implements GuzzleException)
|
||||
└── TransferException (implements GuzzleException)
|
||||
└── RequestException
|
||||
├── BadResponseException
|
||||
│ ├── ServerException
|
||||
│ └── ClientException
|
||||
├── ConnectException
|
||||
└── TooManyRedirectsException
|
||||
|
||||
Guzzle throws exceptions for errors that occur during a transfer.
|
||||
|
||||
- In the event of a networking error (connection timeout, DNS errors, etc.),
|
||||
a ``GuzzleHttp\Exception\RequestException`` is thrown. This exception
|
||||
extends from ``GuzzleHttp\Exception\TransferException``. Catching this
|
||||
exception will catch any exception that can be thrown while transferring
|
||||
requests.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
use GuzzleHttp\Psr7;
|
||||
use GuzzleHttp\Exception\RequestException;
|
||||
|
||||
try {
|
||||
$client->request('GET', 'https://github.com/_abc_123_404');
|
||||
} catch (RequestException $e) {
|
||||
echo Psr7\str($e->getRequest());
|
||||
if ($e->hasResponse()) {
|
||||
echo Psr7\str($e->getResponse());
|
||||
}
|
||||
}
|
||||
|
||||
- A ``GuzzleHttp\Exception\ConnectException`` exception is thrown in the
|
||||
event of a networking error. This exception extends from
|
||||
``GuzzleHttp\Exception\RequestException``.
|
||||
|
||||
- A ``GuzzleHttp\Exception\ClientException`` is thrown for 400
|
||||
level errors if the ``http_errors`` request option is set to true. This
|
||||
exception extends from ``GuzzleHttp\Exception\BadResponseException`` and
|
||||
``GuzzleHttp\Exception\BadResponseException`` extends from
|
||||
``GuzzleHttp\Exception\RequestException``.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
use GuzzleHttp\Psr7;
|
||||
use GuzzleHttp\Exception\ClientException;
|
||||
|
||||
try {
|
||||
$client->request('GET', 'https://github.com/_abc_123_404');
|
||||
} catch (ClientException $e) {
|
||||
echo Psr7\str($e->getRequest());
|
||||
echo Psr7\str($e->getResponse());
|
||||
}
|
||||
|
||||
- A ``GuzzleHttp\Exception\ServerException`` is thrown for 500 level
|
||||
errors if the ``http_errors`` request option is set to true. This
|
||||
exception extends from ``GuzzleHttp\Exception\BadResponseException``.
|
||||
|
||||
- A ``GuzzleHttp\Exception\TooManyRedirectsException`` is thrown when too
|
||||
many redirects are followed. This exception extends from ``GuzzleHttp\Exception\RequestException``.
|
||||
|
||||
All of the above exceptions extend from
|
||||
``GuzzleHttp\Exception\TransferException``.
|
||||
|
||||
|
||||
Environment Variables
|
||||
=====================
|
||||
|
||||
Guzzle exposes a few environment variables that can be used to customize the
|
||||
behavior of the library.
|
||||
|
||||
``GUZZLE_CURL_SELECT_TIMEOUT``
|
||||
Controls the duration in seconds that a curl_multi_* handler will use when
|
||||
selecting on curl handles using ``curl_multi_select()``. Some systems
|
||||
have issues with PHP's implementation of ``curl_multi_select()`` where
|
||||
calling this function always results in waiting for the maximum duration of
|
||||
the timeout.
|
||||
``HTTP_PROXY``
|
||||
Defines the proxy to use when sending requests using the "http" protocol.
|
||||
|
||||
Note: because the HTTP_PROXY variable may contain arbitrary user input on some (CGI) environments, the variable is only used on the CLI SAPI. See https://httpoxy.org for more information.
|
||||
``HTTPS_PROXY``
|
||||
Defines the proxy to use when sending requests using the "https" protocol.
|
||||
``NO_PROXY``
|
||||
Defines URLs for which a proxy should not be used. See :ref:`proxy-option` for usage.
|
||||
|
||||
|
||||
Relevant ini Settings
|
||||
---------------------
|
||||
|
||||
Guzzle can utilize PHP ini settings when configuring clients.
|
||||
|
||||
``openssl.cafile``
|
||||
Specifies the path on disk to a CA file in PEM format to use when sending
|
||||
requests over "https". See: https://wiki.php.net/rfc/tls-peer-verification#phpini_defaults
|
||||
1085
wp-content/upgrade-temp-backup/plugins/w3-total-cache/vendor/guzzlehttp/guzzle/docs/request-options.rst
vendored
Normal file
1085
wp-content/upgrade-temp-backup/plugins/w3-total-cache/vendor/guzzlehttp/guzzle/docs/request-options.rst
vendored
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,2 @@
|
||||
Sphinx>=1.3.0,<1.4.0
|
||||
guzzle_sphinx_theme>=0.7.0,<0.8.0
|
||||
196
wp-content/upgrade-temp-backup/plugins/w3-total-cache/vendor/guzzlehttp/guzzle/docs/testing.rst
vendored
Normal file
196
wp-content/upgrade-temp-backup/plugins/w3-total-cache/vendor/guzzlehttp/guzzle/docs/testing.rst
vendored
Normal file
@ -0,0 +1,196 @@
|
||||
======================
|
||||
Testing Guzzle Clients
|
||||
======================
|
||||
|
||||
Guzzle provides several tools that will enable you to easily mock the HTTP
|
||||
layer without needing to send requests over the internet.
|
||||
|
||||
* Mock handler
|
||||
* History middleware
|
||||
* Node.js web server for integration testing
|
||||
|
||||
|
||||
Mock Handler
|
||||
============
|
||||
|
||||
When testing HTTP clients, you often need to simulate specific scenarios like
|
||||
returning a successful response, returning an error, or returning specific
|
||||
responses in a certain order. Because unit tests need to be predictable, easy
|
||||
to bootstrap, and fast, hitting an actual remote API is a test smell.
|
||||
|
||||
Guzzle provides a mock handler that can be used to fulfill HTTP requests with
|
||||
a response or exception by shifting return values off of a queue.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\Handler\MockHandler;
|
||||
use GuzzleHttp\HandlerStack;
|
||||
use GuzzleHttp\Psr7\Response;
|
||||
use GuzzleHttp\Psr7\Request;
|
||||
use GuzzleHttp\Exception\RequestException;
|
||||
|
||||
// Create a mock and queue two responses.
|
||||
$mock = new MockHandler([
|
||||
new Response(200, ['X-Foo' => 'Bar'], 'Hello, World'),
|
||||
new Response(202, ['Content-Length' => 0]),
|
||||
new RequestException('Error Communicating with Server', new Request('GET', 'test'))
|
||||
]);
|
||||
|
||||
$handlerStack = HandlerStack::create($mock);
|
||||
$client = new Client(['handler' => $handlerStack]);
|
||||
|
||||
// The first request is intercepted with the first response.
|
||||
$response = $client->request('GET', '/');
|
||||
echo $response->getStatusCode();
|
||||
//> 200
|
||||
echo $response->getBody();
|
||||
//> Hello, World
|
||||
// The second request is intercepted with the second response.
|
||||
echo $client->request('GET', '/')->getStatusCode();
|
||||
//> 202
|
||||
|
||||
// Reset the queue and queue up a new response
|
||||
$mock->reset();
|
||||
$mock->append(new Response(201));
|
||||
|
||||
// As the mock was reset, the new response is the 201 CREATED,
|
||||
// instead of the previously queued RequestException
|
||||
echo $client->request('GET', '/')->getStatusCode();
|
||||
//> 201
|
||||
|
||||
|
||||
When no more responses are in the queue and a request is sent, an
|
||||
``OutOfBoundsException`` is thrown.
|
||||
|
||||
History Middleware
|
||||
==================
|
||||
|
||||
When using things like the ``Mock`` handler, you often need to know if the
|
||||
requests you expected to send were sent exactly as you intended. While the mock
|
||||
handler responds with mocked responses, the history middleware maintains a
|
||||
history of the requests that were sent by a client.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\HandlerStack;
|
||||
use GuzzleHttp\Middleware;
|
||||
|
||||
$container = [];
|
||||
$history = Middleware::history($container);
|
||||
|
||||
$handlerStack = HandlerStack::create();
|
||||
// or $handlerStack = HandlerStack::create($mock); if using the Mock handler.
|
||||
|
||||
// Add the history middleware to the handler stack.
|
||||
$handlerStack->push($history);
|
||||
|
||||
$client = new Client(['handler' => $handlerStack]);
|
||||
|
||||
$client->request('GET', 'http://httpbin.org/get');
|
||||
$client->request('HEAD', 'http://httpbin.org/get');
|
||||
|
||||
// Count the number of transactions
|
||||
echo count($container);
|
||||
//> 2
|
||||
|
||||
// Iterate over the requests and responses
|
||||
foreach ($container as $transaction) {
|
||||
echo $transaction['request']->getMethod();
|
||||
//> GET, HEAD
|
||||
if ($transaction['response']) {
|
||||
echo $transaction['response']->getStatusCode();
|
||||
//> 200, 200
|
||||
} elseif ($transaction['error']) {
|
||||
echo $transaction['error'];
|
||||
//> exception
|
||||
}
|
||||
var_dump($transaction['options']);
|
||||
//> dumps the request options of the sent request.
|
||||
}
|
||||
|
||||
|
||||
Test Web Server
|
||||
===============
|
||||
|
||||
Using mock responses is almost always enough when testing a web service client.
|
||||
When implementing custom :doc:`HTTP handlers <handlers-and-middleware>`, you'll
|
||||
need to send actual HTTP requests in order to sufficiently test the handler.
|
||||
However, a best practice is to contact a local web server rather than a server
|
||||
over the internet.
|
||||
|
||||
- Tests are more reliable
|
||||
- Tests do not require a network connection
|
||||
- Tests have no external dependencies
|
||||
|
||||
|
||||
Using the test server
|
||||
---------------------
|
||||
|
||||
.. warning::
|
||||
|
||||
The following functionality is provided to help developers of Guzzle
|
||||
develop HTTP handlers. There is no promise of backwards compatibility
|
||||
when it comes to the node.js test server or the ``GuzzleHttp\Tests\Server``
|
||||
class. If you are using the test server or ``Server`` class outside of
|
||||
guzzlehttp/guzzle, then you will need to configure autoloading and
|
||||
ensure the web server is started manually.
|
||||
|
||||
.. hint::
|
||||
|
||||
You almost never need to use this test web server. You should only ever
|
||||
consider using it when developing HTTP handlers. The test web server
|
||||
is not necessary for mocking requests. For that, please use the
|
||||
Mock handler and history middleware.
|
||||
|
||||
Guzzle ships with a node.js test server that receives requests and returns
|
||||
responses from a queue. The test server exposes a simple API that is used to
|
||||
enqueue responses and inspect the requests that it has received.
|
||||
|
||||
Any operation on the ``Server`` object will ensure that
|
||||
the server is running and wait until it is able to receive requests before
|
||||
returning.
|
||||
|
||||
``GuzzleHttp\Tests\Server`` provides a static interface to the test server. You
|
||||
can queue an HTTP response or an array of responses by calling
|
||||
``Server::enqueue()``. This method accepts an array of
|
||||
``Psr\Http\Message\ResponseInterface`` and ``Exception`` objects.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\Psr7\Response;
|
||||
use GuzzleHttp\Tests\Server;
|
||||
|
||||
// Start the server and queue a response
|
||||
Server::enqueue([
|
||||
new Response(200, ['Content-Length' => 0])
|
||||
]);
|
||||
|
||||
$client = new Client(['base_uri' => Server::$url]);
|
||||
echo $client->request('GET', '/foo')->getStatusCode();
|
||||
// 200
|
||||
|
||||
When a response is queued on the test server, the test server will remove any
|
||||
previously queued responses. As the server receives requests, queued responses
|
||||
are dequeued and returned to the request. When the queue is empty, the server
|
||||
will return a 500 response.
|
||||
|
||||
You can inspect the requests that the server has retrieved by calling
|
||||
``Server::received()``.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
foreach (Server::received() as $response) {
|
||||
echo $response->getStatusCode();
|
||||
}
|
||||
|
||||
You can clear the list of received requests from the web server using the
|
||||
``Server::flush()`` method.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
Server::flush();
|
||||
echo count(Server::received());
|
||||
// 0
|
||||
1352
wp-content/upgrade-temp-backup/plugins/w3-total-cache/vendor/guzzlehttp/guzzle/phpstan-baseline.neon
vendored
Normal file
1352
wp-content/upgrade-temp-backup/plugins/w3-total-cache/vendor/guzzlehttp/guzzle/phpstan-baseline.neon
vendored
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,7 @@
|
||||
includes:
|
||||
- phpstan-baseline.neon
|
||||
|
||||
parameters:
|
||||
level: max
|
||||
paths:
|
||||
- src
|
||||
22
wp-content/upgrade-temp-backup/plugins/w3-total-cache/vendor/guzzlehttp/guzzle/phpunit.xml.dist
vendored
Normal file
22
wp-content/upgrade-temp-backup/plugins/w3-total-cache/vendor/guzzlehttp/guzzle/phpunit.xml.dist
vendored
Normal file
@ -0,0 +1,22 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
|
||||
bootstrap="./tests/bootstrap.php"
|
||||
backupGlobals="true"
|
||||
colors="true"
|
||||
executionOrder="random"
|
||||
>
|
||||
<testsuites>
|
||||
<testsuite name="Test Suite">
|
||||
<directory>tests</directory>
|
||||
</testsuite>
|
||||
</testsuites>
|
||||
<filter>
|
||||
<whitelist>
|
||||
<directory suffix=".php">src</directory>
|
||||
<exclude>
|
||||
<directory suffix="Interface.php">src/</directory>
|
||||
</exclude>
|
||||
</whitelist>
|
||||
</filter>
|
||||
</phpunit>
|
||||
501
wp-content/upgrade-temp-backup/plugins/w3-total-cache/vendor/guzzlehttp/guzzle/src/Client.php
vendored
Normal file
501
wp-content/upgrade-temp-backup/plugins/w3-total-cache/vendor/guzzlehttp/guzzle/src/Client.php
vendored
Normal file
@ -0,0 +1,501 @@
|
||||
<?php
|
||||
namespace GuzzleHttp;
|
||||
|
||||
use GuzzleHttp\Cookie\CookieJar;
|
||||
use GuzzleHttp\Exception\GuzzleException;
|
||||
use GuzzleHttp\Promise;
|
||||
use GuzzleHttp\Psr7;
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\UriInterface;
|
||||
|
||||
/**
|
||||
* @method ResponseInterface get(string|UriInterface $uri, array $options = [])
|
||||
* @method ResponseInterface head(string|UriInterface $uri, array $options = [])
|
||||
* @method ResponseInterface put(string|UriInterface $uri, array $options = [])
|
||||
* @method ResponseInterface post(string|UriInterface $uri, array $options = [])
|
||||
* @method ResponseInterface patch(string|UriInterface $uri, array $options = [])
|
||||
* @method ResponseInterface delete(string|UriInterface $uri, array $options = [])
|
||||
* @method Promise\PromiseInterface getAsync(string|UriInterface $uri, array $options = [])
|
||||
* @method Promise\PromiseInterface headAsync(string|UriInterface $uri, array $options = [])
|
||||
* @method Promise\PromiseInterface putAsync(string|UriInterface $uri, array $options = [])
|
||||
* @method Promise\PromiseInterface postAsync(string|UriInterface $uri, array $options = [])
|
||||
* @method Promise\PromiseInterface patchAsync(string|UriInterface $uri, array $options = [])
|
||||
* @method Promise\PromiseInterface deleteAsync(string|UriInterface $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.
|
||||
* 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();
|
||||
} elseif (!is_callable($config['handler'])) {
|
||||
throw new \InvalidArgumentException('handler must be a callable');
|
||||
}
|
||||
|
||||
// Convert the base_uri to a UriInterface
|
||||
if (isset($config['base_uri'])) {
|
||||
$config['base_uri'] = Psr7\uri_for($config['base_uri']);
|
||||
}
|
||||
|
||||
$this->configureDefaults($config);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $method
|
||||
* @param array $args
|
||||
*
|
||||
* @return Promise\PromiseInterface
|
||||
*/
|
||||
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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Asynchronously send an HTTP request.
|
||||
*
|
||||
* @param array $options Request options to apply to the given
|
||||
* request and to the transfer. See \GuzzleHttp\RequestOptions.
|
||||
*
|
||||
* @return Promise\PromiseInterface
|
||||
*/
|
||||
public function sendAsync(RequestInterface $request, array $options = [])
|
||||
{
|
||||
// Merge the base URI into the request URI if needed.
|
||||
$options = $this->prepareDefaults($options);
|
||||
|
||||
return $this->transfer(
|
||||
$request->withUri($this->buildUri($request->getUri(), $options), $request->hasHeader('Host')),
|
||||
$options
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send an HTTP request.
|
||||
*
|
||||
* @param array $options Request options to apply to the given
|
||||
* request and to the transfer. See \GuzzleHttp\RequestOptions.
|
||||
*
|
||||
* @return ResponseInterface
|
||||
* @throws GuzzleException
|
||||
*/
|
||||
public function send(RequestInterface $request, array $options = [])
|
||||
{
|
||||
$options[RequestOptions::SYNCHRONOUS] = true;
|
||||
return $this->sendAsync($request, $options)->wait();
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and send an asynchronous HTTP request.
|
||||
*
|
||||
* Use an absolute path to override the base path of the client, or a
|
||||
* relative path to append to the base path of the client. The URL can
|
||||
* contain the query string as well. Use an array to provide a URL
|
||||
* template and additional variables to use in the URL template expansion.
|
||||
*
|
||||
* @param string $method HTTP method
|
||||
* @param string|UriInterface $uri URI object or string.
|
||||
* @param array $options Request options to apply. See \GuzzleHttp\RequestOptions.
|
||||
*
|
||||
* @return Promise\PromiseInterface
|
||||
*/
|
||||
public function requestAsync($method, $uri = '', array $options = [])
|
||||
{
|
||||
$options = $this->prepareDefaults($options);
|
||||
// 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create and send an HTTP request.
|
||||
*
|
||||
* Use an absolute path to override the base path of the client, or a
|
||||
* relative path to append to the base path of the client. The URL can
|
||||
* contain the query string as well.
|
||||
*
|
||||
* @param string $method HTTP method.
|
||||
* @param string|UriInterface $uri URI object or string.
|
||||
* @param array $options Request options to apply. See \GuzzleHttp\RequestOptions.
|
||||
*
|
||||
* @return ResponseInterface
|
||||
* @throws GuzzleException
|
||||
*/
|
||||
public function request($method, $uri = '', array $options = [])
|
||||
{
|
||||
$options[RequestOptions::SYNCHRONOUS] = true;
|
||||
return $this->requestAsync($method, $uri, $options)->wait();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a client configuration option.
|
||||
*
|
||||
* These options include default request options of the client, a "handler"
|
||||
* (if utilized by the concrete client), and a "base_uri" if utilized by
|
||||
* the concrete client.
|
||||
*
|
||||
* @param string|null $option The config option to retrieve.
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
public function getConfig($option = null)
|
||||
{
|
||||
return $option === null
|
||||
? $this->config
|
||||
: (isset($this->config[$option]) ? $this->config[$option] : null);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string|null $uri
|
||||
*
|
||||
* @return UriInterface
|
||||
*/
|
||||
private function buildUri($uri, array $config)
|
||||
{
|
||||
// for BC we accept null which would otherwise fail in uri_for
|
||||
$uri = Psr7\uri_for($uri === null ? '' : $uri);
|
||||
|
||||
if (isset($config['base_uri'])) {
|
||||
$uri = Psr7\UriResolver::resolve(Psr7\uri_for($config['base_uri']), $uri);
|
||||
}
|
||||
|
||||
if (isset($config['idn_conversion']) && ($config['idn_conversion'] !== false)) {
|
||||
$idnOptions = ($config['idn_conversion'] === true) ? IDNA_DEFAULT : $config['idn_conversion'];
|
||||
$uri = Utils::idnUriConvert($uri, $idnOptions);
|
||||
}
|
||||
|
||||
return $uri->getScheme() === '' && $uri->getHost() !== '' ? $uri->withScheme('http') : $uri;
|
||||
}
|
||||
|
||||
/**
|
||||
* Configures the default options for a client.
|
||||
*
|
||||
* @param array $config
|
||||
* @return void
|
||||
*/
|
||||
private function configureDefaults(array $config)
|
||||
{
|
||||
$defaults = [
|
||||
'allow_redirects' => RedirectMiddleware::$defaultSettings,
|
||||
'http_errors' => true,
|
||||
'decode_content' => true,
|
||||
'verify' => true,
|
||||
'cookies' => false,
|
||||
'idn_conversion' => true,
|
||||
];
|
||||
|
||||
// Use the standard Linux HTTP_PROXY and HTTPS_PROXY if set.
|
||||
|
||||
// We can only trust the HTTP_PROXY environment variable in a CLI
|
||||
// process due to the fact that PHP has no reliable mechanism to
|
||||
// get environment variables that start with "HTTP_".
|
||||
if (php_sapi_name() === 'cli' && getenv('HTTP_PROXY')) {
|
||||
$defaults['proxy']['http'] = getenv('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(array $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'] = [];
|
||||
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 array $options See \GuzzleHttp\RequestOptions.
|
||||
*
|
||||
* @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_errors
|
||||
if (isset($options['exceptions'])) {
|
||||
$options['http_errors'] = $options['exceptions'];
|
||||
unset($options['exceptions']);
|
||||
}
|
||||
|
||||
$request = $this->applyOptions($request, $options);
|
||||
/** @var HandlerStack $handler */
|
||||
$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 = [
|
||||
'set_headers' => [],
|
||||
];
|
||||
|
||||
if (isset($options['headers'])) {
|
||||
$modify['set_headers'] = $options['headers'];
|
||||
unset($options['headers']);
|
||||
}
|
||||
|
||||
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'], '', '&');
|
||||
unset($options['form_params']);
|
||||
// Ensure that we don't have the header in different case and set the new value.
|
||||
$options['_conditional'] = Psr7\_caseless_remove(['Content-Type'], $options['_conditional']);
|
||||
$options['_conditional']['Content-Type'] = 'application/x-www-form-urlencoded';
|
||||
}
|
||||
|
||||
if (isset($options['multipart'])) {
|
||||
$options['body'] = new Psr7\MultipartStream($options['multipart']);
|
||||
unset($options['multipart']);
|
||||
}
|
||||
|
||||
if (isset($options['json'])) {
|
||||
$options['body'] = \GuzzleHttp\json_encode($options['json']);
|
||||
unset($options['json']);
|
||||
// Ensure that we don't have the header in different case and set the new value.
|
||||
$options['_conditional'] = Psr7\_caseless_remove(['Content-Type'], $options['_conditional']);
|
||||
$options['_conditional']['Content-Type'] = 'application/json';
|
||||
}
|
||||
|
||||
if (!empty($options['decode_content'])
|
||||
&& $options['decode_content'] !== true
|
||||
) {
|
||||
// Ensure that we don't have the header in different case and set the new value.
|
||||
$options['_conditional'] = Psr7\_caseless_remove(['Accept-Encoding'], $options['_conditional']);
|
||||
$modify['set_headers']['Accept-Encoding'] = $options['decode_content'];
|
||||
}
|
||||
|
||||
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']) && is_array($options['auth'])) {
|
||||
$value = $options['auth'];
|
||||
$type = isset($value[2]) ? strtolower($value[2]) : 'basic';
|
||||
switch ($type) {
|
||||
case 'basic':
|
||||
// Ensure that we don't have the header in different case and set the new value.
|
||||
$modify['set_headers'] = Psr7\_caseless_remove(['Authorization'], $modify['set_headers']);
|
||||
$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;
|
||||
case 'ntlm':
|
||||
$options['curl'][CURLOPT_HTTPAUTH] = CURLAUTH_NTLM;
|
||||
$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']);
|
||||
}
|
||||
|
||||
// Ensure that sink is not an invalid value.
|
||||
if (isset($options['sink'])) {
|
||||
// TODO: Add more sink validation?
|
||||
if (is_bool($options['sink'])) {
|
||||
throw new \InvalidArgumentException('sink must not be a boolean');
|
||||
}
|
||||
}
|
||||
|
||||
$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.
|
||||
// Ensure that we don't have the header in different case and set the new value.
|
||||
$options['_conditional'] = Psr7\_caseless_remove(['Content-Type'], $options['_conditional']);
|
||||
$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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Throw Exception with pre-set message.
|
||||
* @return void
|
||||
* @throws \InvalidArgumentException Invalid body.
|
||||
*/
|
||||
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 the "multipart" '
|
||||
. 'request option to send a multipart/form-data request.');
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,87 @@
|
||||
<?php
|
||||
namespace GuzzleHttp;
|
||||
|
||||
use GuzzleHttp\Exception\GuzzleException;
|
||||
use GuzzleHttp\Promise\PromiseInterface;
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\UriInterface;
|
||||
|
||||
/**
|
||||
* Client interface for sending HTTP requests.
|
||||
*/
|
||||
interface ClientInterface
|
||||
{
|
||||
/**
|
||||
* @deprecated Will be removed in Guzzle 7.0.0
|
||||
*/
|
||||
const VERSION = '6.5.5';
|
||||
|
||||
/**
|
||||
* 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);
|
||||
}
|
||||
@ -0,0 +1,321 @@
|
||||
<?php
|
||||
namespace GuzzleHttp\Cookie;
|
||||
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
/**
|
||||
* Cookie jar that stores cookies as 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
*/
|
||||
public static function getCookieValue($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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds and returns the cookie based on the name
|
||||
*
|
||||
* @param string $name cookie name to search for
|
||||
* @return SetCookie|null cookie that was found or null if not found
|
||||
*/
|
||||
public function getCookieByName($name)
|
||||
{
|
||||
// don't allow a non string name
|
||||
if ($name === null || !is_scalar($name)) {
|
||||
return null;
|
||||
}
|
||||
foreach ($this->cookies as $cookie) {
|
||||
if ($cookie->getName() !== null && strcasecmp($cookie->getName(), $name) === 0) {
|
||||
return $cookie;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
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 ($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());
|
||||
}
|
||||
if (0 !== strpos($sc->getPath(), '/')) {
|
||||
$sc->setPath($this->getCookiePathFromRequest($request));
|
||||
}
|
||||
if (!$sc->matchesDomain($request->getUri()->getHost())) {
|
||||
continue;
|
||||
}
|
||||
// Note: At this point `$sc->getDomain()` being a public suffix should
|
||||
// be rejected, but we don't want to pull in the full PSL dependency.
|
||||
$this->setCookie($sc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Computes cookie path following RFC 6265 section 5.1.4
|
||||
*
|
||||
* @link https://tools.ietf.org/html/rfc6265#section-5.1.4
|
||||
*
|
||||
* @param RequestInterface $request
|
||||
* @return string
|
||||
*/
|
||||
private function getCookiePathFromRequest(RequestInterface $request)
|
||||
{
|
||||
$uriPath = $request->getUri()->getPath();
|
||||
if ('' === $uriPath) {
|
||||
return '/';
|
||||
}
|
||||
if (0 !== strpos($uriPath, '/')) {
|
||||
return '/';
|
||||
}
|
||||
if ('/' === $uriPath) {
|
||||
return '/';
|
||||
}
|
||||
if (0 === $lastSlashPos = strrpos($uriPath, '/')) {
|
||||
return '/';
|
||||
}
|
||||
|
||||
return substr($uriPath, 0, $lastSlashPos);
|
||||
}
|
||||
|
||||
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() . '='
|
||||
. $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()
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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|null $domain Clears cookies matching a domain
|
||||
* @param string|null $path Clears cookies matching a domain and path
|
||||
* @param string|null $name Clears cookies matching a domain, path, and name
|
||||
*
|
||||
* @return CookieJarInterface
|
||||
*/
|
||||
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();
|
||||
}
|
||||
@ -0,0 +1,91 @@
|
||||
<?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)
|
||||
{
|
||||
parent::__construct();
|
||||
$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();
|
||||
}
|
||||
}
|
||||
|
||||
$jsonStr = \GuzzleHttp\json_encode($json);
|
||||
if (false === file_put_contents($filename, $jsonStr, LOCK_EX)) {
|
||||
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}");
|
||||
} elseif ($json === '') {
|
||||
return;
|
||||
}
|
||||
|
||||
$data = \GuzzleHttp\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}");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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)
|
||||
{
|
||||
parent::__construct();
|
||||
$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()
|
||||
{
|
||||
if (!isset($_SESSION[$this->sessionKey])) {
|
||||
return;
|
||||
}
|
||||
$data = json_decode($_SESSION[$this->sessionKey], true);
|
||||
if (is_array($data)) {
|
||||
foreach ($data as $cookie) {
|
||||
$this->setCookie(new SetCookie($cookie));
|
||||
}
|
||||
} elseif (strlen($data)) {
|
||||
throw new \RuntimeException("Invalid cookie data");
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,410 @@
|
||||
<?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 exist and include an equal sign.
|
||||
if (empty($pieces[0]) || !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 bool|null
|
||||
*/
|
||||
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 bool|null
|
||||
*/
|
||||
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)
|
||||
{
|
||||
$cookieDomain = $this->getDomain();
|
||||
if (null === $cookieDomain) {
|
||||
return true;
|
||||
}
|
||||
|
||||
// Remove the leading '.' as per spec in RFC 6265.
|
||||
// http://tools.ietf.org/html/rfc6265#section-5.2.3
|
||||
$cookieDomain = ltrim(strtolower($cookieDomain), '.');
|
||||
|
||||
$domain = strtolower($domain);
|
||||
|
||||
// Domain not set or exact match.
|
||||
if ('' === $cookieDomain || $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() !== null && 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;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,27 @@
|
||||
<?php
|
||||
namespace GuzzleHttp\Exception;
|
||||
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
/**
|
||||
* Exception when an HTTP error occurs (4xx or 5xx error)
|
||||
*/
|
||||
class BadResponseException extends RequestException
|
||||
{
|
||||
public function __construct(
|
||||
$message,
|
||||
RequestInterface $request,
|
||||
ResponseInterface $response = null,
|
||||
\Exception $previous = null,
|
||||
array $handlerContext = []
|
||||
) {
|
||||
if (null === $response) {
|
||||
@trigger_error(
|
||||
'Instantiating the ' . __CLASS__ . ' class without a Response is deprecated since version 6.3 and will be removed in 7.0.',
|
||||
E_USER_DEPRECATED
|
||||
);
|
||||
}
|
||||
parent::__construct($message, $request, $response, $previous, $handlerContext);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,9 @@
|
||||
<?php
|
||||
namespace GuzzleHttp\Exception;
|
||||
|
||||
/**
|
||||
* Exception when a client error is encountered (4xx codes)
|
||||
*/
|
||||
class ClientException extends BadResponseException
|
||||
{
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
namespace GuzzleHttp\Exception;
|
||||
|
||||
use Throwable;
|
||||
|
||||
if (interface_exists(Throwable::class)) {
|
||||
interface GuzzleException extends Throwable
|
||||
{
|
||||
}
|
||||
} else {
|
||||
/**
|
||||
* @method string getMessage()
|
||||
* @method \Throwable|null getPrevious()
|
||||
* @method mixed getCode()
|
||||
* @method string getFile()
|
||||
* @method int getLine()
|
||||
* @method array getTrace()
|
||||
* @method string getTraceAsString()
|
||||
*/
|
||||
interface GuzzleException
|
||||
{
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace GuzzleHttp\Exception;
|
||||
|
||||
final class InvalidArgumentException extends \InvalidArgumentException implements GuzzleException
|
||||
{
|
||||
}
|
||||
@ -0,0 +1,192 @@
|
||||
<?php
|
||||
namespace GuzzleHttp\Exception;
|
||||
|
||||
use GuzzleHttp\Promise\PromiseInterface;
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Http\Message\UriInterface;
|
||||
|
||||
/**
|
||||
* HTTP Request exception
|
||||
*/
|
||||
class RequestException extends TransferException
|
||||
{
|
||||
/** @var RequestInterface */
|
||||
private $request;
|
||||
|
||||
/** @var ResponseInterface|null */
|
||||
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 = (int) floor($response->getStatusCode() / 100);
|
||||
if ($level === 4) {
|
||||
$label = 'Client error';
|
||||
$className = ClientException::class;
|
||||
} elseif ($level === 5) {
|
||||
$label = 'Server error';
|
||||
$className = ServerException::class;
|
||||
} else {
|
||||
$label = 'Unsuccessful request';
|
||||
$className = __CLASS__;
|
||||
}
|
||||
|
||||
$uri = $request->getUri();
|
||||
$uri = static::obfuscateUri($uri);
|
||||
|
||||
// Client Error: `GET /` resulted in a `404 Not Found` response:
|
||||
// <html> ... (truncated)
|
||||
$message = sprintf(
|
||||
'%s: `%s %s` resulted in a `%s %s` response',
|
||||
$label,
|
||||
$request->getMethod(),
|
||||
$uri,
|
||||
$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)
|
||||
{
|
||||
return \GuzzleHttp\Psr7\get_message_body_summary($response);
|
||||
}
|
||||
|
||||
/**
|
||||
* Obfuscates URI if there is a username and a password present
|
||||
*
|
||||
* @param UriInterface $uri
|
||||
*
|
||||
* @return UriInterface
|
||||
*/
|
||||
private static function obfuscateUri(UriInterface $uri)
|
||||
{
|
||||
$userInfo = $uri->getUserInfo();
|
||||
|
||||
if (false !== ($pos = strpos($userInfo, ':'))) {
|
||||
return $uri->withUserInfo(substr($userInfo, 0, $pos), '***');
|
||||
}
|
||||
|
||||
return $uri;
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
}
|
||||
@ -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;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,9 @@
|
||||
<?php
|
||||
namespace GuzzleHttp\Exception;
|
||||
|
||||
/**
|
||||
* Exception when a server error is encountered (5xx codes)
|
||||
*/
|
||||
class ServerException extends BadResponseException
|
||||
{
|
||||
}
|
||||
@ -0,0 +1,6 @@
|
||||
<?php
|
||||
namespace GuzzleHttp\Exception;
|
||||
|
||||
class TooManyRedirectsException extends RequestException
|
||||
{
|
||||
}
|
||||
@ -0,0 +1,6 @@
|
||||
<?php
|
||||
namespace GuzzleHttp\Exception;
|
||||
|
||||
class TransferException extends \RuntimeException implements GuzzleException
|
||||
{
|
||||
}
|
||||
@ -0,0 +1,585 @@
|
||||
<?php
|
||||
namespace GuzzleHttp\Handler;
|
||||
|
||||
use GuzzleHttp\Exception\ConnectException;
|
||||
use GuzzleHttp\Exception\RequestException;
|
||||
use GuzzleHttp\Promise\FulfilledPromise;
|
||||
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
|
||||
{
|
||||
const CURL_VERSION_STR = 'curl_version';
|
||||
const LOW_CURL_VERSION_NUMBER = '7.21.2';
|
||||
|
||||
/** @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);
|
||||
$curlStats['appconnect_time'] = curl_getinfo($easy->handle, CURLINFO_APPCONNECT_TIME);
|
||||
$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),
|
||||
'appconnect_time' => curl_getinfo($easy->handle, CURLINFO_APPCONNECT_TIME),
|
||||
] + curl_getinfo($easy->handle);
|
||||
$ctx[self::CURL_VERSION_STR] = curl_version()['version'];
|
||||
$factory->release($easy);
|
||||
|
||||
// Retry when nothing is present or when curl failed to rewind.
|
||||
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 \GuzzleHttp\Promise\rejection_for(
|
||||
new RequestException(
|
||||
'An error was encountered during the on_headers event',
|
||||
$easy->request,
|
||||
$easy->response,
|
||||
$easy->onHeadersException,
|
||||
$ctx
|
||||
)
|
||||
);
|
||||
}
|
||||
if (version_compare($ctx[self::CURL_VERSION_STR], self::LOW_CURL_VERSION_NUMBER)) {
|
||||
$message = sprintf(
|
||||
'cURL error %s: %s (%s)',
|
||||
$ctx['errno'],
|
||||
$ctx['error'],
|
||||
'see https://curl.haxx.se/libcurl/c/libcurl-errors.html'
|
||||
);
|
||||
} else {
|
||||
$message = sprintf(
|
||||
'cURL error %s: %s (%s) for %s',
|
||||
$ctx['errno'],
|
||||
$ctx['error'],
|
||||
'see https://curl.haxx.se/libcurl/c/libcurl-errors.html',
|
||||
$easy->request->getUri()
|
||||
);
|
||||
}
|
||||
|
||||
// Create a connection exception if it was a specific error code.
|
||||
$error = isset($connectionErrors[$easy->errno])
|
||||
? new ConnectException($message, $easy->request, null, $ctx)
|
||||
: new RequestException($message, $easy->request, $easy->response, null, $ctx);
|
||||
|
||||
return \GuzzleHttp\Promise\rejection_for($error);
|
||||
}
|
||||
|
||||
private function getDefaultConf(EasyHandle $easy)
|
||||
{
|
||||
$conf = [
|
||||
'_headers' => $easy->request->getHeaders(),
|
||||
CURLOPT_CUSTOMREQUEST => $easy->request->getMethod(),
|
||||
CURLOPT_URL => (string) $easy->request->getUri()->withFragment(''),
|
||||
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();
|
||||
if ($body->isSeekable()) {
|
||||
$body->rewind();
|
||||
}
|
||||
$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) {
|
||||
$value = (string) $value;
|
||||
if ($value === '') {
|
||||
// cURL requires a special format for empty headers.
|
||||
// See https://github.com/guzzle/guzzle/issues/1882 for more details.
|
||||
$conf[CURLOPT_HTTPHEADER][] = "$name;";
|
||||
} else {
|
||||
$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'])) {
|
||||
// Throw an error if the file/folder/link path is not valid or doesn't exist.
|
||||
if (!file_exists($options['verify'])) {
|
||||
throw new \InvalidArgumentException(
|
||||
"SSL CA bundle not found: {$options['verify']}"
|
||||
);
|
||||
}
|
||||
// If it's a directory or a link to a directory use CURLOPT_CAPATH.
|
||||
// If not, it's probably a file, or a link to a file, so use CURLOPT_CAINFO.
|
||||
if (is_dir($options['verify']) ||
|
||||
(is_link($options['verify']) && is_dir(readlink($options['verify'])))) {
|
||||
$conf[CURLOPT_CAPATH] = $options['verify'];
|
||||
} else {
|
||||
$conf[CURLOPT_CAINFO] = $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]);
|
||||
}
|
||||
$timeoutRequiresNoSignal = false;
|
||||
if (isset($options['timeout'])) {
|
||||
$timeoutRequiresNoSignal |= $options['timeout'] < 1;
|
||||
$conf[CURLOPT_TIMEOUT_MS] = $options['timeout'] * 1000;
|
||||
}
|
||||
|
||||
// CURL default value is CURL_IPRESOLVE_WHATEVER
|
||||
if (isset($options['force_ip_resolve'])) {
|
||||
if ('v4' === $options['force_ip_resolve']) {
|
||||
$conf[CURLOPT_IPRESOLVE] = CURL_IPRESOLVE_V4;
|
||||
} elseif ('v6' === $options['force_ip_resolve']) {
|
||||
$conf[CURLOPT_IPRESOLVE] = CURL_IPRESOLVE_V6;
|
||||
}
|
||||
}
|
||||
|
||||
if (isset($options['connect_timeout'])) {
|
||||
$timeoutRequiresNoSignal |= $options['connect_timeout'] < 1;
|
||||
$conf[CURLOPT_CONNECTTIMEOUT_MS] = $options['connect_timeout'] * 1000;
|
||||
}
|
||||
|
||||
if ($timeoutRequiresNoSignal && strtoupper(substr(PHP_OS, 0, 3)) !== 'WIN') {
|
||||
$conf[CURLOPT_NOSIGNAL] = true;
|
||||
}
|
||||
|
||||
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'])) {
|
||||
if (is_array($options['ssl_key'])) {
|
||||
if (count($options['ssl_key']) === 2) {
|
||||
list($sslKey, $conf[CURLOPT_SSLKEYPASSWD]) = $options['ssl_key'];
|
||||
} else {
|
||||
list($sslKey) = $options['ssl_key'];
|
||||
}
|
||||
}
|
||||
|
||||
$sslKey = isset($sslKey) ? $sslKey: $options['ssl_key'];
|
||||
|
||||
if (!file_exists($sslKey)) {
|
||||
throw new \InvalidArgumentException(
|
||||
"SSL private key not found: {$sslKey}"
|
||||
);
|
||||
}
|
||||
$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 = $easy->options['on_headers'];
|
||||
|
||||
if (!is_callable($onHeaders)) {
|
||||
throw new \InvalidArgumentException('on_headers must be callable');
|
||||
}
|
||||
} else {
|
||||
$onHeaders = null;
|
||||
}
|
||||
|
||||
return function ($ch, $h) use (
|
||||
$onHeaders,
|
||||
$easy,
|
||||
&$startingResponse
|
||||
) {
|
||||
$value = trim($h);
|
||||
if ($value === '') {
|
||||
$startingResponse = true;
|
||||
$easy->createResponse();
|
||||
if ($onHeaders !== null) {
|
||||
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);
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,219 @@
|
||||
<?php
|
||||
namespace GuzzleHttp\Handler;
|
||||
|
||||
use GuzzleHttp\Promise as P;
|
||||
use GuzzleHttp\Promise\Promise;
|
||||
use GuzzleHttp\Utils;
|
||||
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 = [];
|
||||
private $options = [];
|
||||
|
||||
/**
|
||||
* 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.
|
||||
* - options: An associative array of CURLMOPT_* options and
|
||||
* corresponding values for curl_multi_setopt()
|
||||
*
|
||||
* @param array $options
|
||||
*/
|
||||
public function __construct(array $options = [])
|
||||
{
|
||||
$this->factory = isset($options['handle_factory'])
|
||||
? $options['handle_factory'] : new CurlFactory(50);
|
||||
|
||||
if (isset($options['select_timeout'])) {
|
||||
$this->selectTimeout = $options['select_timeout'];
|
||||
} elseif ($selectTimeout = getenv('GUZZLE_CURL_SELECT_TIMEOUT')) {
|
||||
$this->selectTimeout = $selectTimeout;
|
||||
} else {
|
||||
$this->selectTimeout = 1;
|
||||
}
|
||||
|
||||
$this->options = isset($options['options']) ? $options['options'] : [];
|
||||
}
|
||||
|
||||
public function __get($name)
|
||||
{
|
||||
if ($name === '_mh') {
|
||||
$this->_mh = curl_multi_init();
|
||||
|
||||
foreach ($this->options as $option => $value) {
|
||||
// A warning is raised in case of a wrong option.
|
||||
curl_multi_setopt($this->_mh, $option, $value);
|
||||
}
|
||||
|
||||
// Further calls to _mh will return the value directly, without entering the
|
||||
// __get() method at all.
|
||||
return $this->_mh;
|
||||
}
|
||||
|
||||
throw new \BadMethodCallException();
|
||||
}
|
||||
|
||||
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 = Utils::currentTime();
|
||||
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] = Utils::currentTime() + ($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 = Utils::currentTime();
|
||||
$nextTime = PHP_INT_MAX;
|
||||
foreach ($this->delays as $time) {
|
||||
if ($time < $nextTime) {
|
||||
$nextTime = $time;
|
||||
}
|
||||
}
|
||||
|
||||
return max(0, $nextTime - $currentTime) * 1000000;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,92 @@
|
||||
<?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'])
|
||||
) {
|
||||
$headers['x-encoded-content-encoding']
|
||||
= $headers[$normalizedKeys['content-encoding']];
|
||||
unset($headers[$normalizedKeys['content-encoding']]);
|
||||
if (isset($normalizedKeys['content-length'])) {
|
||||
$headers['x-encoded-content-length']
|
||||
= $headers[$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);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,195 @@
|
||||
<?php
|
||||
namespace GuzzleHttp\Handler;
|
||||
|
||||
use GuzzleHttp\Exception\RequestException;
|
||||
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 HandlerStack
|
||||
*/
|
||||
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']) && is_numeric($options['delay'])) {
|
||||
usleep($options['delay'] * 1000);
|
||||
}
|
||||
|
||||
$this->lastRequest = $request;
|
||||
$this->lastOptions = $options;
|
||||
$response = array_shift($this->queue);
|
||||
|
||||
if (isset($options['on_headers'])) {
|
||||
if (!is_callable($options['on_headers'])) {
|
||||
throw new \InvalidArgumentException('on_headers must be callable');
|
||||
}
|
||||
try {
|
||||
$options['on_headers']($response);
|
||||
} catch (\Exception $e) {
|
||||
$msg = 'An error was encountered during the on_headers event';
|
||||
$response = new RequestException($msg, $request, $response, $e);
|
||||
}
|
||||
}
|
||||
|
||||
if (is_callable($response)) {
|
||||
$response = call_user_func($response, $request, $options);
|
||||
}
|
||||
|
||||
$response = $response instanceof \Exception
|
||||
? \GuzzleHttp\Promise\rejection_for($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 \GuzzleHttp\Promise\rejection_for($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 array
|
||||
*/
|
||||
public function getLastOptions()
|
||||
{
|
||||
return $this->lastOptions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of remaining items in the queue.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function count()
|
||||
{
|
||||
return count($this->queue);
|
||||
}
|
||||
|
||||
public function reset()
|
||||
{
|
||||
$this->queue = [];
|
||||
}
|
||||
|
||||
private function invokeStats(
|
||||
RequestInterface $request,
|
||||
array $options,
|
||||
ResponseInterface $response = null,
|
||||
$reason = null
|
||||
) {
|
||||
if (isset($options['on_stats'])) {
|
||||
$transferTime = isset($options['transfer_time']) ? $options['transfer_time'] : 0;
|
||||
$stats = new TransferStats($request, $response, $transferTime, $reason);
|
||||
call_user_func($options['on_stats'], $stats);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -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);
|
||||
};
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,545 @@
|
||||
<?php
|
||||
namespace GuzzleHttp\Handler;
|
||||
|
||||
use GuzzleHttp\Exception\ConnectException;
|
||||
use GuzzleHttp\Exception\RequestException;
|
||||
use GuzzleHttp\Promise\FulfilledPromise;
|
||||
use GuzzleHttp\Promise\PromiseInterface;
|
||||
use GuzzleHttp\Psr7;
|
||||
use GuzzleHttp\TransferStats;
|
||||
use GuzzleHttp\Utils;
|
||||
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']) ? Utils::currentTime() : 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
|
||||
|| strpos($message, "connection attempt failed")
|
||||
) {
|
||||
$e = new ConnectException($e->getMessage(), $request, $e);
|
||||
}
|
||||
$e = RequestException::wrapException($request, $e);
|
||||
$this->invokeStats($options, $request, $startTime, null, $e);
|
||||
|
||||
return \GuzzleHttp\Promise\rejection_for($e);
|
||||
}
|
||||
}
|
||||
|
||||
private function invokeStats(
|
||||
array $options,
|
||||
RequestInterface $request,
|
||||
$startTime,
|
||||
ResponseInterface $response = null,
|
||||
$error = null
|
||||
) {
|
||||
if (isset($options['on_stats'])) {
|
||||
$stats = new TransferStats(
|
||||
$request,
|
||||
$response,
|
||||
Utils::currentTime() - $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 = $stream;
|
||||
|
||||
if (strcasecmp('HEAD', $request->getMethod())) {
|
||||
$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 \GuzzleHttp\Promise\rejection_for($ex);
|
||||
}
|
||||
}
|
||||
|
||||
// Do not drain when the request is a HEAD request because they have
|
||||
// no body.
|
||||
if ($sink !== $stream) {
|
||||
$this->drain(
|
||||
$stream,
|
||||
$sink,
|
||||
$response->getHeaderLine('Content-Length')
|
||||
);
|
||||
}
|
||||
|
||||
$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\LazyOpenStream($sink, 'w+')
|
||||
: 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)
|
||||
);
|
||||
$headers['x-encoded-content-encoding']
|
||||
= $headers[$normalizedKeys['content-encoding']];
|
||||
// Remove content-encoding header
|
||||
unset($headers[$normalizedKeys['content-encoding']]);
|
||||
// Fix content-length header
|
||||
if (isset($normalizedKeys['content-length'])) {
|
||||
$headers['x-encoded-content-length']
|
||||
= $headers[$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
|
||||
* @param string $contentLength Header specifying the amount of
|
||||
* data to read.
|
||||
*
|
||||
* @return StreamInterface
|
||||
* @throws \RuntimeException when the sink option is invalid.
|
||||
*/
|
||||
private function drain(
|
||||
StreamInterface $source,
|
||||
StreamInterface $sink,
|
||||
$contentLength
|
||||
) {
|
||||
// If a content-length header is provided, then stop reading once
|
||||
// that number of bytes has been read. This can prevent infinitely
|
||||
// reading from a stream when dealing with servers that do not honor
|
||||
// Connection: Close headers.
|
||||
Psr7\copy_to_stream(
|
||||
$source,
|
||||
$sink,
|
||||
(strlen($contentLength) > 0 && (int) $contentLength > 0) ? (int) $contentLength : -1
|
||||
);
|
||||
|
||||
$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);
|
||||
|
||||
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']
|
||||
);
|
||||
}
|
||||
|
||||
// Microsoft NTLM authentication only supported with curl handler
|
||||
if (isset($options['auth'])
|
||||
&& is_array($options['auth'])
|
||||
&& isset($options['auth'][2])
|
||||
&& 'ntlm' == $options['auth'][2]
|
||||
) {
|
||||
throw new \InvalidArgumentException('Microsoft NTLM authentication only supported with curl handler');
|
||||
}
|
||||
|
||||
$uri = $this->resolveHost($request, $options);
|
||||
|
||||
$context = $this->createResource(
|
||||
function () use ($context, $params) {
|
||||
return stream_context_create($context, $params);
|
||||
}
|
||||
);
|
||||
|
||||
return $this->createResource(
|
||||
function () use ($uri, &$http_response_header, $context, $options) {
|
||||
$resource = fopen((string) $uri, 'r', null, $context);
|
||||
$this->lastHeaders = $http_response_header;
|
||||
|
||||
if (isset($options['read_timeout'])) {
|
||||
$readTimeout = $options['read_timeout'];
|
||||
$sec = (int) $readTimeout;
|
||||
$usec = ($readTimeout - $sec) * 100000;
|
||||
stream_set_timeout($resource, $sec, $usec);
|
||||
}
|
||||
|
||||
return $resource;
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
private function resolveHost(RequestInterface $request, array $options)
|
||||
{
|
||||
$uri = $request->getUri();
|
||||
|
||||
if (isset($options['force_ip_resolve']) && !filter_var($uri->getHost(), FILTER_VALIDATE_IP)) {
|
||||
if ('v4' === $options['force_ip_resolve']) {
|
||||
$records = dns_get_record($uri->getHost(), DNS_A);
|
||||
if (!isset($records[0]['ip'])) {
|
||||
throw new ConnectException(
|
||||
sprintf(
|
||||
"Could not resolve IPv4 address for host '%s'",
|
||||
$uri->getHost()
|
||||
),
|
||||
$request
|
||||
);
|
||||
}
|
||||
$uri = $uri->withHost($records[0]['ip']);
|
||||
} elseif ('v6' === $options['force_ip_resolve']) {
|
||||
$records = dns_get_record($uri->getHost(), DNS_AAAA);
|
||||
if (!isset($records[0]['ipv6'])) {
|
||||
throw new ConnectException(
|
||||
sprintf(
|
||||
"Could not resolve IPv6 address for host '%s'",
|
||||
$uri->getHost()
|
||||
),
|
||||
$request
|
||||
);
|
||||
}
|
||||
$uri = $uri->withHost('[' . $records[0]['ipv6'] . ']');
|
||||
}
|
||||
}
|
||||
|
||||
return $uri;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
if ($value > 0) {
|
||||
$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()->withFragment('');
|
||||
$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);
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
277
wp-content/upgrade-temp-backup/plugins/w3-total-cache/vendor/guzzlehttp/guzzle/src/HandlerStack.php
vendored
Normal file
277
wp-content/upgrade-temp-backup/plugins/w3-total-cache/vendor/guzzlehttp/guzzle/src/HandlerStack.php
vendored
Normal file
@ -0,0 +1,277 @@
|
||||
<?php
|
||||
namespace GuzzleHttp;
|
||||
|
||||
use GuzzleHttp\Promise\PromiseInterface;
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
/**
|
||||
* Creates a composed Guzzle handler function by stacking middlewares on top of
|
||||
* an HTTP handler function.
|
||||
*/
|
||||
class HandlerStack
|
||||
{
|
||||
/** @var callable|null */
|
||||
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 your 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
|
||||
*
|
||||
* @return ResponseInterface|PromiseInterface
|
||||
*/
|
||||
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 string $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 string $findName
|
||||
* @param string $withName
|
||||
* @param callable $middleware
|
||||
* @param bool $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) . ')';
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,185 @@
|
||||
<?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
|
||||
* - {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
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get headers from message as string
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
private function headers(MessageInterface $message)
|
||||
{
|
||||
$result = '';
|
||||
foreach ($message->getHeaders() as $name => $values) {
|
||||
$result .= $name . ': ' . implode(', ', $values) . "\r\n";
|
||||
}
|
||||
|
||||
return trim($result);
|
||||
}
|
||||
}
|
||||
254
wp-content/upgrade-temp-backup/plugins/w3-total-cache/vendor/guzzlehttp/guzzle/src/Middleware.php
vendored
Normal file
254
wp-content/upgrade-temp-backup/plugins/w3-total-cache/vendor/guzzlehttp/guzzle/src/Middleware.php
vendored
Normal file
@ -0,0 +1,254 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* 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) {
|
||||
$code = $response->getStatusCode();
|
||||
if ($code < 400) {
|
||||
return $response;
|
||||
}
|
||||
throw RequestException::create($request, $response);
|
||||
}
|
||||
);
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Middleware that pushes history data to an ArrayAccess container.
|
||||
*
|
||||
* @param array|\ArrayAccess $container Container to hold the history (by reference).
|
||||
*
|
||||
* @return callable Returns a function that accepts the next handler.
|
||||
* @throws \InvalidArgumentException if container is not an array or ArrayAccess.
|
||||
*/
|
||||
public static function history(&$container)
|
||||
{
|
||||
if (!is_array($container) && !$container instanceof \ArrayAccess) {
|
||||
throw new \InvalidArgumentException('history container must be an array or object implementing ArrayAccess');
|
||||
}
|
||||
|
||||
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 \GuzzleHttp\Promise\rejection_for($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 = 'info' /* \Psr\Log\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);
|
||||
};
|
||||
};
|
||||
}
|
||||
}
|
||||
134
wp-content/upgrade-temp-backup/plugins/w3-total-cache/vendor/guzzlehttp/guzzle/src/Pool.php
vendored
Normal file
134
wp-content/upgrade-temp-backup/plugins/w3-total-cache/vendor/guzzlehttp/guzzle/src/Pool.php
vendored
Normal file
@ -0,0 +1,134 @@
|
||||
<?php
|
||||
namespace GuzzleHttp;
|
||||
|
||||
use GuzzleHttp\Promise\EachPromise;
|
||||
use GuzzleHttp\Promise\PromiseInterface;
|
||||
use GuzzleHttp\Promise\PromisorInterface;
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
|
||||
/**
|
||||
* Sends an iterator of requests concurrently using a capped pool size.
|
||||
*
|
||||
* The pool will read from an iterator until it is cancelled or until the
|
||||
* iterator is consumed. When a request is yielded, the request is sent after
|
||||
* 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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get promise
|
||||
*
|
||||
* @return PromiseInterface
|
||||
*/
|
||||
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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute callback(s)
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
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;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,111 @@
|
||||
<?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;
|
||||
|
||||
/**
|
||||
* @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 ($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 (!$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);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add expect header
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
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';
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,264 @@
|
||||
<?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';
|
||||
|
||||
const STATUS_HISTORY_HEADER = 'X-Guzzle-Redirect-Status-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 $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 authorization is handled by curl, unset it if URI is cross-origin.
|
||||
if (Psr7\UriComparator::isCrossOrigin($request->getUri(), $nextRequest->getUri()) && defined('\CURLOPT_HTTPAUTH')) {
|
||||
unset(
|
||||
$options['curl'][\CURLOPT_HTTPAUTH],
|
||||
$options['curl'][\CURLOPT_USERPWD]
|
||||
);
|
||||
}
|
||||
|
||||
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(),
|
||||
$response->getStatusCode()
|
||||
);
|
||||
}
|
||||
|
||||
return $promise;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable tracking on promise.
|
||||
*
|
||||
* @return PromiseInterface
|
||||
*/
|
||||
private function withTracking(PromiseInterface $promise, $uri, $statusCode)
|
||||
{
|
||||
return $promise->then(
|
||||
function (ResponseInterface $response) use ($uri, $statusCode) {
|
||||
// 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.
|
||||
$historyHeader = $response->getHeader(self::HISTORY_HEADER);
|
||||
$statusHeader = $response->getHeader(self::STATUS_HISTORY_HEADER);
|
||||
array_unshift($historyHeader, $uri);
|
||||
array_unshift($statusHeader, $statusCode);
|
||||
return $response->withHeader(self::HISTORY_HEADER, $historyHeader)
|
||||
->withHeader(self::STATUS_HISTORY_HEADER, $statusHeader);
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check for too many redirects.
|
||||
*
|
||||
* @return void
|
||||
*
|
||||
* @throws TooManyRedirectsException Too many redirects.
|
||||
*/
|
||||
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 && !$options['allow_redirects']['strict'])
|
||||
) {
|
||||
$modify['method'] = 'GET';
|
||||
$modify['body'] = '';
|
||||
}
|
||||
|
||||
$uri = self::redirectUri($request, $response, $protocols);
|
||||
if (isset($options['idn_conversion']) && ($options['idn_conversion'] !== false)) {
|
||||
$idnOptions = ($options['idn_conversion'] === true) ? IDNA_DEFAULT : $options['idn_conversion'];
|
||||
$uri = Utils::idnUriConvert($uri, $idnOptions);
|
||||
}
|
||||
|
||||
$modify['uri'] = $uri;
|
||||
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 and Cookie headers if URI is cross-origin.
|
||||
if (Psr7\UriComparator::isCrossOrigin($request->getUri(), $modify['uri'])) {
|
||||
$modify['remove_headers'][] = 'Authorization';
|
||||
$modify['remove_headers'][] = 'Cookie';
|
||||
}
|
||||
|
||||
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 static function redirectUri(
|
||||
RequestInterface $request,
|
||||
ResponseInterface $response,
|
||||
array $protocols
|
||||
) {
|
||||
$location = Psr7\UriResolver::resolve(
|
||||
$request->getUri(),
|
||||
new Psr7\Uri($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;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,263 @@
|
||||
<?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=false) Set to true to enable 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: (resource|string|null|int|float|StreamInterface|callable|\Iterator)
|
||||
* 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';
|
||||
|
||||
/**
|
||||
* idn: (bool|int, default=true) A combination of IDNA_* constants for
|
||||
* idn_to_ascii() PHP's function (see "options" parameter). Set to false to
|
||||
* disable IDN support completely, or to true to use the default
|
||||
* configuration (IDNA_DEFAULT constant).
|
||||
*/
|
||||
const IDN_CONVERSION = 'idn_conversion';
|
||||
|
||||
/**
|
||||
* json: (mixed) Adds JSON data to a request. The provided value is JSON
|
||||
* encoded and a Content-Type header of application/json will be added to
|
||||
* the request if no Content-Type header is already present.
|
||||
*/
|
||||
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';
|
||||
|
||||
/**
|
||||
* read_timeout: (float, default=default_socket_timeout ini setting) Float describing
|
||||
* the body read timeout, for stream requests.
|
||||
*/
|
||||
const READ_TIMEOUT = 'read_timeout';
|
||||
|
||||
/**
|
||||
* version: (float) Specifies the HTTP protocol version to attempt to use.
|
||||
*/
|
||||
const VERSION = 'version';
|
||||
|
||||
/**
|
||||
* force_ip_resolve: (bool) Force client to use only ipv4 or ipv6 protocol
|
||||
*/
|
||||
const FORCE_IP_RESOLVE = 'force_ip_resolve';
|
||||
}
|
||||
@ -0,0 +1,128 @@
|
||||
<?php
|
||||
namespace GuzzleHttp;
|
||||
|
||||
use GuzzleHttp\Promise\PromiseInterface;
|
||||
use GuzzleHttp\Promise\RejectedPromise;
|
||||
use GuzzleHttp\Psr7;
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
/**
|
||||
* 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;
|
||||
|
||||
/** @var callable */
|
||||
private $delay;
|
||||
|
||||
/**
|
||||
* @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 [response] 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 int $retries
|
||||
*
|
||||
* @return int milliseconds.
|
||||
*/
|
||||
public static function exponentialDelay($retries)
|
||||
{
|
||||
return (int) pow(2, $retries - 1) * 1000;
|
||||
}
|
||||
|
||||
/**
|
||||
* @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)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute fulfilled closure
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
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, $value);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute rejected closure
|
||||
*
|
||||
* @return callable
|
||||
*/
|
||||
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 \GuzzleHttp\Promise\rejection_for($reason);
|
||||
}
|
||||
return $this->doRetry($req, $options);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* @return self
|
||||
*/
|
||||
private function doRetry(RequestInterface $request, array $options, ResponseInterface $response = null)
|
||||
{
|
||||
$options['delay'] = call_user_func($this->delay, ++$options['retries'], $response);
|
||||
|
||||
return $this($request, $options);
|
||||
}
|
||||
}
|
||||
126
wp-content/upgrade-temp-backup/plugins/w3-total-cache/vendor/guzzlehttp/guzzle/src/TransferStats.php
vendored
Normal file
126
wp-content/upgrade-temp-backup/plugins/w3-total-cache/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|null $response Response received (if any)
|
||||
* @param float|null $transferTime Total handler transfer time.
|
||||
* @param mixed $handlerErrorData Handler error data.
|
||||
* @param array $handlerStats Handler specific stats.
|
||||
*/
|
||||
public function __construct(
|
||||
RequestInterface $request,
|
||||
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|null 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;
|
||||
}
|
||||
}
|
||||
237
wp-content/upgrade-temp-backup/plugins/w3-total-cache/vendor/guzzlehttp/guzzle/src/UriTemplate.php
vendored
Normal file
237
wp-content/upgrade-temp-backup/plugins/w3-total-cache/vendor/guzzlehttp/guzzle/src/UriTemplate.php
vendored
Normal file
@ -0,0 +1,237 @@
|
||||
<?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 = [
|
||||
'' => ['prefix' => '', 'joiner' => ',', 'query' => false],
|
||||
'+' => ['prefix' => '', 'joiner' => ',', 'query' => false],
|
||||
'#' => ['prefix' => '#', 'joiner' => ',', 'query' => false],
|
||||
'.' => ['prefix' => '.', 'joiner' => '.', 'query' => false],
|
||||
'/' => ['prefix' => '/', 'joiner' => '/', 'query' => false],
|
||||
';' => ['prefix' => ';', 'joiner' => ';', 'query' => true],
|
||||
'?' => ['prefix' => '?', 'joiner' => '&', 'query' => true],
|
||||
'&' => ['prefix' => '&', 'joiner' => '&', 'query' => true]
|
||||
];
|
||||
|
||||
/** @var array Delimiters */
|
||||
private static $delims = [':', '/', '?', '#', '[', ']', '@', '!', '$',
|
||||
'&', '\'', '(', ')', '*', '+', ',', ';', '='];
|
||||
|
||||
/** @var array Percent encoded delimiters */
|
||||
private static $delimsPct = ['%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 = [];
|
||||
|
||||
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 = [];
|
||||
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 = ['+' => '%20', '%7e' => '~'];
|
||||
|
||||
$replacements = [];
|
||||
$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 = [];
|
||||
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);
|
||||
}
|
||||
}
|
||||
92
wp-content/upgrade-temp-backup/plugins/w3-total-cache/vendor/guzzlehttp/guzzle/src/Utils.php
vendored
Normal file
92
wp-content/upgrade-temp-backup/plugins/w3-total-cache/vendor/guzzlehttp/guzzle/src/Utils.php
vendored
Normal file
@ -0,0 +1,92 @@
|
||||
<?php
|
||||
namespace GuzzleHttp;
|
||||
|
||||
use GuzzleHttp\Exception\InvalidArgumentException;
|
||||
use Psr\Http\Message\UriInterface;
|
||||
use Symfony\Polyfill\Intl\Idn\Idn;
|
||||
|
||||
final class Utils
|
||||
{
|
||||
/**
|
||||
* Wrapper for the hrtime() or microtime() functions
|
||||
* (depending on the PHP version, one of the two is used)
|
||||
*
|
||||
* @return float|mixed UNIX timestamp
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public static function currentTime()
|
||||
{
|
||||
return function_exists('hrtime') ? hrtime(true) / 1e9 : microtime(true);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $options
|
||||
*
|
||||
* @return UriInterface
|
||||
* @throws InvalidArgumentException
|
||||
*
|
||||
* @internal
|
||||
*/
|
||||
public static function idnUriConvert(UriInterface $uri, $options = 0)
|
||||
{
|
||||
if ($uri->getHost()) {
|
||||
$asciiHost = self::idnToAsci($uri->getHost(), $options, $info);
|
||||
if ($asciiHost === false) {
|
||||
$errorBitSet = isset($info['errors']) ? $info['errors'] : 0;
|
||||
|
||||
$errorConstants = array_filter(array_keys(get_defined_constants()), function ($name) {
|
||||
return substr($name, 0, 11) === 'IDNA_ERROR_';
|
||||
});
|
||||
|
||||
$errors = [];
|
||||
foreach ($errorConstants as $errorConstant) {
|
||||
if ($errorBitSet & constant($errorConstant)) {
|
||||
$errors[] = $errorConstant;
|
||||
}
|
||||
}
|
||||
|
||||
$errorMessage = 'IDN conversion failed';
|
||||
if ($errors) {
|
||||
$errorMessage .= ' (errors: ' . implode(', ', $errors) . ')';
|
||||
}
|
||||
|
||||
throw new InvalidArgumentException($errorMessage);
|
||||
} else {
|
||||
if ($uri->getHost() !== $asciiHost) {
|
||||
// Replace URI only if the ASCII version is different
|
||||
$uri = $uri->withHost($asciiHost);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $uri;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param string $domain
|
||||
* @param int $options
|
||||
* @param array $info
|
||||
*
|
||||
* @return string|false
|
||||
*/
|
||||
private static function idnToAsci($domain, $options, &$info = [])
|
||||
{
|
||||
if (\preg_match('%^[ -~]+$%', $domain) === 1) {
|
||||
return $domain;
|
||||
}
|
||||
|
||||
if (\extension_loaded('intl') && defined('INTL_IDNA_VARIANT_UTS46')) {
|
||||
return \idn_to_ascii($domain, $options, INTL_IDNA_VARIANT_UTS46, $info);
|
||||
}
|
||||
|
||||
/*
|
||||
* The Idn class is marked as @internal. Verify that class and method exists.
|
||||
*/
|
||||
if (method_exists(Idn::class, 'idn_to_ascii')) {
|
||||
return Idn::idn_to_ascii($domain, $options, Idn::INTL_IDNA_VARIANT_UTS46, $info);
|
||||
}
|
||||
|
||||
throw new \RuntimeException('ext-intl or symfony/polyfill-intl-idn not loaded or too old');
|
||||
}
|
||||
}
|
||||
334
wp-content/upgrade-temp-backup/plugins/w3-total-cache/vendor/guzzlehttp/guzzle/src/functions.php
vendored
Normal file
334
wp-content/upgrade-temp-backup/plugins/w3-total-cache/vendor/guzzlehttp/guzzle/src/functions.php
vendored
Normal file
@ -0,0 +1,334 @@
|
||||
<?php
|
||||
namespace GuzzleHttp;
|
||||
|
||||
use GuzzleHttp\Handler\CurlHandler;
|
||||
use GuzzleHttp\Handler\CurlMultiHandler;
|
||||
use GuzzleHttp\Handler\Proxy;
|
||||
use GuzzleHttp\Handler\StreamHandler;
|
||||
|
||||
/**
|
||||
* 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 iterable $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.
|
||||
*
|
||||
* @return callable Returns the best handler for the given system.
|
||||
* @throws \RuntimeException if no viable Handler is available.
|
||||
*/
|
||||
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',
|
||||
// SLES 12 (provided by the ca-certificates package)
|
||||
'/var/lib/ca-certificates/ca-bundle.pem',
|
||||
// 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for json_decode that throws when an error occurs.
|
||||
*
|
||||
* @param string $json JSON data to parse
|
||||
* @param bool $assoc When true, returned objects will be converted
|
||||
* into associative arrays.
|
||||
* @param int $depth User specified recursion depth.
|
||||
* @param int $options Bitmask of JSON decode options.
|
||||
*
|
||||
* @return mixed
|
||||
* @throws Exception\InvalidArgumentException if the JSON cannot be decoded.
|
||||
* @link http://www.php.net/manual/en/function.json-decode.php
|
||||
*/
|
||||
function json_decode($json, $assoc = false, $depth = 512, $options = 0)
|
||||
{
|
||||
$data = \json_decode($json, $assoc, $depth, $options);
|
||||
if (JSON_ERROR_NONE !== json_last_error()) {
|
||||
throw new Exception\InvalidArgumentException(
|
||||
'json_decode error: ' . json_last_error_msg()
|
||||
);
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Wrapper for JSON encoding that throws when an error occurs.
|
||||
*
|
||||
* @param mixed $value The value being encoded
|
||||
* @param int $options JSON encode option bitmask
|
||||
* @param int $depth Set the maximum depth. Must be greater than zero.
|
||||
*
|
||||
* @return string
|
||||
* @throws Exception\InvalidArgumentException if the JSON cannot be encoded.
|
||||
* @link http://www.php.net/manual/en/function.json-encode.php
|
||||
*/
|
||||
function json_encode($value, $options = 0, $depth = 512)
|
||||
{
|
||||
$json = \json_encode($value, $options, $depth);
|
||||
if (JSON_ERROR_NONE !== json_last_error()) {
|
||||
throw new Exception\InvalidArgumentException(
|
||||
'json_encode error: ' . json_last_error_msg()
|
||||
);
|
||||
}
|
||||
|
||||
return $json;
|
||||
}
|
||||
@ -0,0 +1,6 @@
|
||||
<?php
|
||||
|
||||
// Don't redefine the functions if included multiple times.
|
||||
if (!function_exists('GuzzleHttp\uri_template')) {
|
||||
require __DIR__ . '/functions.php';
|
||||
}
|
||||
811
wp-content/upgrade-temp-backup/plugins/w3-total-cache/vendor/guzzlehttp/guzzle/tests/ClientTest.php
vendored
Normal file
811
wp-content/upgrade-temp-backup/plugins/w3-total-cache/vendor/guzzlehttp/guzzle/tests/ClientTest.php
vendored
Normal file
@ -0,0 +1,811 @@
|
||||
<?php
|
||||
namespace GuzzleHttp\Tests;
|
||||
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\Cookie\CookieJar;
|
||||
use GuzzleHttp\Handler\MockHandler;
|
||||
use GuzzleHttp\HandlerStack;
|
||||
use GuzzleHttp\Middleware;
|
||||
use GuzzleHttp\Promise\PromiseInterface;
|
||||
use GuzzleHttp\Psr7;
|
||||
use GuzzleHttp\Psr7\Request;
|
||||
use GuzzleHttp\Psr7\Response;
|
||||
use GuzzleHttp\Psr7\Uri;
|
||||
use GuzzleHttp\RequestOptions;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
class ClientTest extends TestCase
|
||||
{
|
||||
public function testUsesDefaultHandler()
|
||||
{
|
||||
$client = new Client();
|
||||
Server::enqueue([new Response(200, ['Content-Length' => 0])]);
|
||||
$response = $client->get(Server::$url);
|
||||
self::assertSame(200, $response->getStatusCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \InvalidArgumentException
|
||||
* @expectedExceptionMessage Magic request methods require a URI and optional options array
|
||||
*/
|
||||
public function testValidatesArgsForMagicMethods()
|
||||
{
|
||||
$client = new Client();
|
||||
$client->get();
|
||||
}
|
||||
|
||||
public function testCanSendMagicAsyncRequests()
|
||||
{
|
||||
$client = new Client();
|
||||
Server::flush();
|
||||
Server::enqueue([new Response(200, ['Content-Length' => 2], 'hi')]);
|
||||
$p = $client->getAsync(Server::$url, ['query' => ['test' => 'foo']]);
|
||||
self::assertInstanceOf(PromiseInterface::class, $p);
|
||||
self::assertSame(200, $p->wait()->getStatusCode());
|
||||
$received = Server::received(true);
|
||||
self::assertCount(1, $received);
|
||||
self::assertSame('test=foo', $received[0]->getUri()->getQuery());
|
||||
}
|
||||
|
||||
public function testCanSendSynchronously()
|
||||
{
|
||||
$client = new Client(['handler' => new MockHandler([new Response()])]);
|
||||
$request = new Request('GET', 'http://example.com');
|
||||
$r = $client->send($request);
|
||||
self::assertInstanceOf(ResponseInterface::class, $r);
|
||||
self::assertSame(200, $r->getStatusCode());
|
||||
}
|
||||
|
||||
public function testClientHasOptions()
|
||||
{
|
||||
$client = new Client([
|
||||
'base_uri' => 'http://foo.com',
|
||||
'timeout' => 2,
|
||||
'headers' => ['bar' => 'baz'],
|
||||
'handler' => new MockHandler()
|
||||
]);
|
||||
$base = $client->getConfig('base_uri');
|
||||
self::assertSame('http://foo.com', (string) $base);
|
||||
self::assertInstanceOf(Uri::class, $base);
|
||||
self::assertNotNull($client->getConfig('handler'));
|
||||
self::assertSame(2, $client->getConfig('timeout'));
|
||||
self::assertArrayHasKey('timeout', $client->getConfig());
|
||||
self::assertArrayHasKey('headers', $client->getConfig());
|
||||
}
|
||||
|
||||
public function testCanMergeOnBaseUri()
|
||||
{
|
||||
$mock = new MockHandler([new Response()]);
|
||||
$client = new Client([
|
||||
'base_uri' => 'http://foo.com/bar/',
|
||||
'handler' => $mock
|
||||
]);
|
||||
$client->get('baz');
|
||||
self::assertSame(
|
||||
'http://foo.com/bar/baz',
|
||||
(string)$mock->getLastRequest()->getUri()
|
||||
);
|
||||
}
|
||||
|
||||
public function testCanMergeOnBaseUriWithRequest()
|
||||
{
|
||||
$mock = new MockHandler([new Response(), new Response()]);
|
||||
$client = new Client([
|
||||
'handler' => $mock,
|
||||
'base_uri' => 'http://foo.com/bar/'
|
||||
]);
|
||||
$client->request('GET', new Uri('baz'));
|
||||
self::assertSame(
|
||||
'http://foo.com/bar/baz',
|
||||
(string) $mock->getLastRequest()->getUri()
|
||||
);
|
||||
|
||||
$client->request('GET', new Uri('baz'), ['base_uri' => 'http://example.com/foo/']);
|
||||
self::assertSame(
|
||||
'http://example.com/foo/baz',
|
||||
(string) $mock->getLastRequest()->getUri(),
|
||||
'Can overwrite the base_uri through the request options'
|
||||
);
|
||||
}
|
||||
|
||||
public function testCanUseRelativeUriWithSend()
|
||||
{
|
||||
$mock = new MockHandler([new Response()]);
|
||||
$client = new Client([
|
||||
'handler' => $mock,
|
||||
'base_uri' => 'http://bar.com'
|
||||
]);
|
||||
self::assertSame('http://bar.com', (string) $client->getConfig('base_uri'));
|
||||
$request = new Request('GET', '/baz');
|
||||
$client->send($request);
|
||||
self::assertSame(
|
||||
'http://bar.com/baz',
|
||||
(string) $mock->getLastRequest()->getUri()
|
||||
);
|
||||
}
|
||||
|
||||
public function testMergesDefaultOptionsAndDoesNotOverwriteUa()
|
||||
{
|
||||
$c = new Client(['headers' => ['User-agent' => 'foo']]);
|
||||
self::assertSame(['User-agent' => 'foo'], $c->getConfig('headers'));
|
||||
self::assertInternalType('array', $c->getConfig('allow_redirects'));
|
||||
self::assertTrue($c->getConfig('http_errors'));
|
||||
self::assertTrue($c->getConfig('decode_content'));
|
||||
self::assertTrue($c->getConfig('verify'));
|
||||
}
|
||||
|
||||
public function testDoesNotOverwriteHeaderWithDefault()
|
||||
{
|
||||
$mock = new MockHandler([new Response()]);
|
||||
$c = new Client([
|
||||
'headers' => ['User-agent' => 'foo'],
|
||||
'handler' => $mock
|
||||
]);
|
||||
$c->get('http://example.com', ['headers' => ['User-Agent' => 'bar']]);
|
||||
self::assertSame('bar', $mock->getLastRequest()->getHeaderLine('User-Agent'));
|
||||
}
|
||||
|
||||
public function testDoesNotOverwriteHeaderWithDefaultInRequest()
|
||||
{
|
||||
$mock = new MockHandler([new Response()]);
|
||||
$c = new Client([
|
||||
'headers' => ['User-agent' => 'foo'],
|
||||
'handler' => $mock
|
||||
]);
|
||||
$request = new Request('GET', Server::$url, ['User-Agent' => 'bar']);
|
||||
$c->send($request);
|
||||
self::assertSame('bar', $mock->getLastRequest()->getHeaderLine('User-Agent'));
|
||||
}
|
||||
|
||||
public function testDoesOverwriteHeaderWithSetRequestOption()
|
||||
{
|
||||
$mock = new MockHandler([new Response()]);
|
||||
$c = new Client([
|
||||
'headers' => ['User-agent' => 'foo'],
|
||||
'handler' => $mock
|
||||
]);
|
||||
$request = new Request('GET', Server::$url, ['User-Agent' => 'bar']);
|
||||
$c->send($request, ['headers' => ['User-Agent' => 'YO']]);
|
||||
self::assertSame('YO', $mock->getLastRequest()->getHeaderLine('User-Agent'));
|
||||
}
|
||||
|
||||
public function testCanUnsetRequestOptionWithNull()
|
||||
{
|
||||
$mock = new MockHandler([new Response()]);
|
||||
$c = new Client([
|
||||
'headers' => ['foo' => 'bar'],
|
||||
'handler' => $mock
|
||||
]);
|
||||
$c->get('http://example.com', ['headers' => null]);
|
||||
self::assertFalse($mock->getLastRequest()->hasHeader('foo'));
|
||||
}
|
||||
|
||||
public function testRewriteExceptionsToHttpErrors()
|
||||
{
|
||||
$client = new Client(['handler' => new MockHandler([new Response(404)])]);
|
||||
$res = $client->get('http://foo.com', ['exceptions' => false]);
|
||||
self::assertSame(404, $res->getStatusCode());
|
||||
}
|
||||
|
||||
public function testRewriteSaveToToSink()
|
||||
{
|
||||
$r = Psr7\stream_for(fopen('php://temp', 'r+'));
|
||||
$mock = new MockHandler([new Response(200, [], 'foo')]);
|
||||
$client = new Client(['handler' => $mock]);
|
||||
$client->get('http://foo.com', ['save_to' => $r]);
|
||||
self::assertSame($r, $mock->getLastOptions()['sink']);
|
||||
}
|
||||
|
||||
public function testAllowRedirectsCanBeTrue()
|
||||
{
|
||||
$mock = new MockHandler([new Response(200, [], 'foo')]);
|
||||
$handler = HandlerStack::create($mock);
|
||||
$client = new Client(['handler' => $handler]);
|
||||
$client->get('http://foo.com', ['allow_redirects' => true]);
|
||||
self::assertInternalType('array', $mock->getLastOptions()['allow_redirects']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \InvalidArgumentException
|
||||
* @expectedExceptionMessage allow_redirects must be true, false, or array
|
||||
*/
|
||||
public function testValidatesAllowRedirects()
|
||||
{
|
||||
$mock = new MockHandler([new Response(200, [], 'foo')]);
|
||||
$handler = HandlerStack::create($mock);
|
||||
$client = new Client(['handler' => $handler]);
|
||||
$client->get('http://foo.com', ['allow_redirects' => 'foo']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \GuzzleHttp\Exception\ClientException
|
||||
*/
|
||||
public function testThrowsHttpErrorsByDefault()
|
||||
{
|
||||
$mock = new MockHandler([new Response(404)]);
|
||||
$handler = HandlerStack::create($mock);
|
||||
$client = new Client(['handler' => $handler]);
|
||||
$client->get('http://foo.com');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \InvalidArgumentException
|
||||
* @expectedExceptionMessage cookies must be an instance of GuzzleHttp\Cookie\CookieJarInterface
|
||||
*/
|
||||
public function testValidatesCookies()
|
||||
{
|
||||
$mock = new MockHandler([new Response(200, [], 'foo')]);
|
||||
$handler = HandlerStack::create($mock);
|
||||
$client = new Client(['handler' => $handler]);
|
||||
$client->get('http://foo.com', ['cookies' => 'foo']);
|
||||
}
|
||||
|
||||
public function testSetCookieToTrueUsesSharedJar()
|
||||
{
|
||||
$mock = new MockHandler([
|
||||
new Response(200, ['Set-Cookie' => 'foo=bar']),
|
||||
new Response()
|
||||
]);
|
||||
$handler = HandlerStack::create($mock);
|
||||
$client = new Client(['handler' => $handler, 'cookies' => true]);
|
||||
$client->get('http://foo.com');
|
||||
$client->get('http://foo.com');
|
||||
self::assertSame('foo=bar', $mock->getLastRequest()->getHeaderLine('Cookie'));
|
||||
}
|
||||
|
||||
public function testSetCookieToJar()
|
||||
{
|
||||
$mock = new MockHandler([
|
||||
new Response(200, ['Set-Cookie' => 'foo=bar']),
|
||||
new Response()
|
||||
]);
|
||||
$handler = HandlerStack::create($mock);
|
||||
$client = new Client(['handler' => $handler]);
|
||||
$jar = new CookieJar();
|
||||
$client->get('http://foo.com', ['cookies' => $jar]);
|
||||
$client->get('http://foo.com', ['cookies' => $jar]);
|
||||
self::assertSame('foo=bar', $mock->getLastRequest()->getHeaderLine('Cookie'));
|
||||
}
|
||||
|
||||
public function testCanDisableContentDecoding()
|
||||
{
|
||||
$mock = new MockHandler([new Response()]);
|
||||
$client = new Client(['handler' => $mock]);
|
||||
$client->get('http://foo.com', ['decode_content' => false]);
|
||||
$last = $mock->getLastRequest();
|
||||
self::assertFalse($last->hasHeader('Accept-Encoding'));
|
||||
self::assertFalse($mock->getLastOptions()['decode_content']);
|
||||
}
|
||||
|
||||
public function testCanSetContentDecodingToValue()
|
||||
{
|
||||
$mock = new MockHandler([new Response()]);
|
||||
$client = new Client(['handler' => $mock]);
|
||||
$client->get('http://foo.com', ['decode_content' => 'gzip']);
|
||||
$last = $mock->getLastRequest();
|
||||
self::assertSame('gzip', $last->getHeaderLine('Accept-Encoding'));
|
||||
self::assertSame('gzip', $mock->getLastOptions()['decode_content']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \InvalidArgumentException
|
||||
*/
|
||||
public function testValidatesHeaders()
|
||||
{
|
||||
$mock = new MockHandler();
|
||||
$client = new Client(['handler' => $mock]);
|
||||
$client->get('http://foo.com', ['headers' => 'foo']);
|
||||
}
|
||||
|
||||
public function testAddsBody()
|
||||
{
|
||||
$mock = new MockHandler([new Response()]);
|
||||
$client = new Client(['handler' => $mock]);
|
||||
$request = new Request('PUT', 'http://foo.com');
|
||||
$client->send($request, ['body' => 'foo']);
|
||||
$last = $mock->getLastRequest();
|
||||
self::assertSame('foo', (string) $last->getBody());
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \InvalidArgumentException
|
||||
*/
|
||||
public function testValidatesQuery()
|
||||
{
|
||||
$mock = new MockHandler();
|
||||
$client = new Client(['handler' => $mock]);
|
||||
$request = new Request('PUT', 'http://foo.com');
|
||||
$client->send($request, ['query' => false]);
|
||||
}
|
||||
|
||||
public function testQueryCanBeString()
|
||||
{
|
||||
$mock = new MockHandler([new Response()]);
|
||||
$client = new Client(['handler' => $mock]);
|
||||
$request = new Request('PUT', 'http://foo.com');
|
||||
$client->send($request, ['query' => 'foo']);
|
||||
self::assertSame('foo', $mock->getLastRequest()->getUri()->getQuery());
|
||||
}
|
||||
|
||||
public function testQueryCanBeArray()
|
||||
{
|
||||
$mock = new MockHandler([new Response()]);
|
||||
$client = new Client(['handler' => $mock]);
|
||||
$request = new Request('PUT', 'http://foo.com');
|
||||
$client->send($request, ['query' => ['foo' => 'bar baz']]);
|
||||
self::assertSame('foo=bar%20baz', $mock->getLastRequest()->getUri()->getQuery());
|
||||
}
|
||||
|
||||
public function testCanAddJsonData()
|
||||
{
|
||||
$mock = new MockHandler([new Response()]);
|
||||
$client = new Client(['handler' => $mock]);
|
||||
$request = new Request('PUT', 'http://foo.com');
|
||||
$client->send($request, ['json' => ['foo' => 'bar']]);
|
||||
$last = $mock->getLastRequest();
|
||||
self::assertSame('{"foo":"bar"}', (string) $mock->getLastRequest()->getBody());
|
||||
self::assertSame('application/json', $last->getHeaderLine('Content-Type'));
|
||||
}
|
||||
|
||||
public function testCanAddJsonDataWithoutOverwritingContentType()
|
||||
{
|
||||
$mock = new MockHandler([new Response()]);
|
||||
$client = new Client(['handler' => $mock]);
|
||||
$request = new Request('PUT', 'http://foo.com');
|
||||
$client->send($request, [
|
||||
'headers' => ['content-type' => 'foo'],
|
||||
'json' => 'a'
|
||||
]);
|
||||
$last = $mock->getLastRequest();
|
||||
self::assertSame('"a"', (string) $mock->getLastRequest()->getBody());
|
||||
self::assertSame('foo', $last->getHeaderLine('Content-Type'));
|
||||
}
|
||||
|
||||
public function testCanAddJsonDataWithNullHeader()
|
||||
{
|
||||
$mock = new MockHandler([new Response()]);
|
||||
$client = new Client(['handler' => $mock]);
|
||||
$request = new Request('PUT', 'http://foo.com');
|
||||
$client->send($request, [
|
||||
'headers' => null,
|
||||
'json' => 'a'
|
||||
]);
|
||||
$last = $mock->getLastRequest();
|
||||
self::assertSame('"a"', (string) $mock->getLastRequest()->getBody());
|
||||
self::assertSame('application/json', $last->getHeaderLine('Content-Type'));
|
||||
}
|
||||
|
||||
public function testAuthCanBeTrue()
|
||||
{
|
||||
$mock = new MockHandler([new Response()]);
|
||||
$client = new Client(['handler' => $mock]);
|
||||
$client->get('http://foo.com', ['auth' => false]);
|
||||
$last = $mock->getLastRequest();
|
||||
self::assertFalse($last->hasHeader('Authorization'));
|
||||
}
|
||||
|
||||
public function testAuthCanBeArrayForBasicAuth()
|
||||
{
|
||||
$mock = new MockHandler([new Response()]);
|
||||
$client = new Client(['handler' => $mock]);
|
||||
$client->get('http://foo.com', ['auth' => ['a', 'b']]);
|
||||
$last = $mock->getLastRequest();
|
||||
self::assertSame('Basic YTpi', $last->getHeaderLine('Authorization'));
|
||||
}
|
||||
|
||||
public function testAuthCanBeArrayForDigestAuth()
|
||||
{
|
||||
$mock = new MockHandler([new Response()]);
|
||||
$client = new Client(['handler' => $mock]);
|
||||
$client->get('http://foo.com', ['auth' => ['a', 'b', 'digest']]);
|
||||
$last = $mock->getLastOptions();
|
||||
self::assertSame([
|
||||
CURLOPT_HTTPAUTH => 2,
|
||||
CURLOPT_USERPWD => 'a:b'
|
||||
], $last['curl']);
|
||||
}
|
||||
|
||||
public function testAuthCanBeArrayForNtlmAuth()
|
||||
{
|
||||
$mock = new MockHandler([new Response()]);
|
||||
$client = new Client(['handler' => $mock]);
|
||||
$client->get('http://foo.com', ['auth' => ['a', 'b', 'ntlm']]);
|
||||
$last = $mock->getLastOptions();
|
||||
self::assertSame([
|
||||
CURLOPT_HTTPAUTH => 8,
|
||||
CURLOPT_USERPWD => 'a:b'
|
||||
], $last['curl']);
|
||||
}
|
||||
|
||||
public function testAuthCanBeCustomType()
|
||||
{
|
||||
$mock = new MockHandler([new Response()]);
|
||||
$client = new Client(['handler' => $mock]);
|
||||
$client->get('http://foo.com', ['auth' => 'foo']);
|
||||
$last = $mock->getLastOptions();
|
||||
self::assertSame('foo', $last['auth']);
|
||||
}
|
||||
|
||||
public function testCanAddFormParams()
|
||||
{
|
||||
$mock = new MockHandler([new Response()]);
|
||||
$client = new Client(['handler' => $mock]);
|
||||
$client->post('http://foo.com', [
|
||||
'form_params' => [
|
||||
'foo' => 'bar bam',
|
||||
'baz' => ['boo' => 'qux']
|
||||
]
|
||||
]);
|
||||
$last = $mock->getLastRequest();
|
||||
self::assertSame(
|
||||
'application/x-www-form-urlencoded',
|
||||
$last->getHeaderLine('Content-Type')
|
||||
);
|
||||
self::assertSame(
|
||||
'foo=bar+bam&baz%5Bboo%5D=qux',
|
||||
(string) $last->getBody()
|
||||
);
|
||||
}
|
||||
|
||||
public function testFormParamsEncodedProperly()
|
||||
{
|
||||
$separator = ini_get('arg_separator.output');
|
||||
ini_set('arg_separator.output', '&');
|
||||
$mock = new MockHandler([new Response()]);
|
||||
$client = new Client(['handler' => $mock]);
|
||||
$client->post('http://foo.com', [
|
||||
'form_params' => [
|
||||
'foo' => 'bar bam',
|
||||
'baz' => ['boo' => 'qux']
|
||||
]
|
||||
]);
|
||||
$last = $mock->getLastRequest();
|
||||
self::assertSame(
|
||||
'foo=bar+bam&baz%5Bboo%5D=qux',
|
||||
(string) $last->getBody()
|
||||
);
|
||||
|
||||
ini_set('arg_separator.output', $separator);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \InvalidArgumentException
|
||||
*/
|
||||
public function testEnsuresThatFormParamsAndMultipartAreExclusive()
|
||||
{
|
||||
$client = new Client(['handler' => function () {
|
||||
}]);
|
||||
$client->post('http://foo.com', [
|
||||
'form_params' => ['foo' => 'bar bam'],
|
||||
'multipart' => []
|
||||
]);
|
||||
}
|
||||
|
||||
public function testCanSendMultipart()
|
||||
{
|
||||
$mock = new MockHandler([new Response()]);
|
||||
$client = new Client(['handler' => $mock]);
|
||||
$client->post('http://foo.com', [
|
||||
'multipart' => [
|
||||
[
|
||||
'name' => 'foo',
|
||||
'contents' => 'bar'
|
||||
],
|
||||
[
|
||||
'name' => 'test',
|
||||
'contents' => fopen(__FILE__, 'r')
|
||||
]
|
||||
]
|
||||
]);
|
||||
|
||||
$last = $mock->getLastRequest();
|
||||
self::assertContains(
|
||||
'multipart/form-data; boundary=',
|
||||
$last->getHeaderLine('Content-Type')
|
||||
);
|
||||
|
||||
self::assertContains(
|
||||
'Content-Disposition: form-data; name="foo"',
|
||||
(string) $last->getBody()
|
||||
);
|
||||
|
||||
self::assertContains('bar', (string) $last->getBody());
|
||||
self::assertContains(
|
||||
'Content-Disposition: form-data; name="foo"' . "\r\n",
|
||||
(string) $last->getBody()
|
||||
);
|
||||
self::assertContains(
|
||||
'Content-Disposition: form-data; name="test"; filename="ClientTest.php"',
|
||||
(string) $last->getBody()
|
||||
);
|
||||
}
|
||||
|
||||
public function testCanSendMultipartWithExplicitBody()
|
||||
{
|
||||
$mock = new MockHandler([new Response()]);
|
||||
$client = new Client(['handler' => $mock]);
|
||||
$client->send(
|
||||
new Request(
|
||||
'POST',
|
||||
'http://foo.com',
|
||||
[],
|
||||
new Psr7\MultipartStream(
|
||||
[
|
||||
[
|
||||
'name' => 'foo',
|
||||
'contents' => 'bar',
|
||||
],
|
||||
[
|
||||
'name' => 'test',
|
||||
'contents' => fopen(__FILE__, 'r'),
|
||||
],
|
||||
]
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
$last = $mock->getLastRequest();
|
||||
self::assertContains(
|
||||
'multipart/form-data; boundary=',
|
||||
$last->getHeaderLine('Content-Type')
|
||||
);
|
||||
|
||||
self::assertContains(
|
||||
'Content-Disposition: form-data; name="foo"',
|
||||
(string) $last->getBody()
|
||||
);
|
||||
|
||||
self::assertContains('bar', (string) $last->getBody());
|
||||
self::assertContains(
|
||||
'Content-Disposition: form-data; name="foo"' . "\r\n",
|
||||
(string) $last->getBody()
|
||||
);
|
||||
self::assertContains(
|
||||
'Content-Disposition: form-data; name="test"; filename="ClientTest.php"',
|
||||
(string) $last->getBody()
|
||||
);
|
||||
}
|
||||
|
||||
public function testUsesProxyEnvironmentVariables()
|
||||
{
|
||||
$http = getenv('HTTP_PROXY');
|
||||
$https = getenv('HTTPS_PROXY');
|
||||
$no = getenv('NO_PROXY');
|
||||
$client = new Client();
|
||||
self::assertNull($client->getConfig('proxy'));
|
||||
putenv('HTTP_PROXY=127.0.0.1');
|
||||
$client = new Client();
|
||||
self::assertSame(
|
||||
['http' => '127.0.0.1'],
|
||||
$client->getConfig('proxy')
|
||||
);
|
||||
putenv('HTTPS_PROXY=127.0.0.2');
|
||||
putenv('NO_PROXY=127.0.0.3, 127.0.0.4');
|
||||
$client = new Client();
|
||||
self::assertSame(
|
||||
['http' => '127.0.0.1', 'https' => '127.0.0.2', 'no' => ['127.0.0.3','127.0.0.4']],
|
||||
$client->getConfig('proxy')
|
||||
);
|
||||
putenv("HTTP_PROXY=$http");
|
||||
putenv("HTTPS_PROXY=$https");
|
||||
putenv("NO_PROXY=$no");
|
||||
}
|
||||
|
||||
public function testRequestSendsWithSync()
|
||||
{
|
||||
$mock = new MockHandler([new Response()]);
|
||||
$client = new Client(['handler' => $mock]);
|
||||
$client->request('GET', 'http://foo.com');
|
||||
self::assertTrue($mock->getLastOptions()['synchronous']);
|
||||
}
|
||||
|
||||
public function testSendSendsWithSync()
|
||||
{
|
||||
$mock = new MockHandler([new Response()]);
|
||||
$client = new Client(['handler' => $mock]);
|
||||
$client->send(new Request('GET', 'http://foo.com'));
|
||||
self::assertTrue($mock->getLastOptions()['synchronous']);
|
||||
}
|
||||
|
||||
public function testCanSetCustomHandler()
|
||||
{
|
||||
$mock = new MockHandler([new Response(500)]);
|
||||
$client = new Client(['handler' => $mock]);
|
||||
$mock2 = new MockHandler([new Response(200)]);
|
||||
self::assertSame(
|
||||
200,
|
||||
$client->send(new Request('GET', 'http://foo.com'), [
|
||||
'handler' => $mock2
|
||||
])->getStatusCode()
|
||||
);
|
||||
}
|
||||
|
||||
public function testProperlyBuildsQuery()
|
||||
{
|
||||
$mock = new MockHandler([new Response()]);
|
||||
$client = new Client(['handler' => $mock]);
|
||||
$request = new Request('PUT', 'http://foo.com');
|
||||
$client->send($request, ['query' => ['foo' => 'bar', 'john' => 'doe']]);
|
||||
self::assertSame('foo=bar&john=doe', $mock->getLastRequest()->getUri()->getQuery());
|
||||
}
|
||||
|
||||
public function testSendSendsWithIpAddressAndPortAndHostHeaderInRequestTheHostShouldBePreserved()
|
||||
{
|
||||
$mockHandler = new MockHandler([new Response()]);
|
||||
$client = new Client(['base_uri' => 'http://127.0.0.1:8585', 'handler' => $mockHandler]);
|
||||
$request = new Request('GET', '/test', ['Host'=>'foo.com']);
|
||||
|
||||
$client->send($request);
|
||||
|
||||
self::assertSame('foo.com', $mockHandler->getLastRequest()->getHeader('Host')[0]);
|
||||
}
|
||||
|
||||
public function testSendSendsWithDomainAndHostHeaderInRequestTheHostShouldBePreserved()
|
||||
{
|
||||
$mockHandler = new MockHandler([new Response()]);
|
||||
$client = new Client(['base_uri' => 'http://foo2.com', 'handler' => $mockHandler]);
|
||||
$request = new Request('GET', '/test', ['Host'=>'foo.com']);
|
||||
|
||||
$client->send($request);
|
||||
|
||||
self::assertSame('foo.com', $mockHandler->getLastRequest()->getHeader('Host')[0]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \InvalidArgumentException
|
||||
*/
|
||||
public function testValidatesSink()
|
||||
{
|
||||
$mockHandler = new MockHandler([new Response()]);
|
||||
$client = new Client(['handler' => $mockHandler]);
|
||||
$client->get('http://test.com', ['sink' => true]);
|
||||
}
|
||||
|
||||
public function testHttpDefaultSchemeIfUriHasNone()
|
||||
{
|
||||
$mockHandler = new MockHandler([new Response()]);
|
||||
$client = new Client(['handler' => $mockHandler]);
|
||||
|
||||
$client->request('GET', '//example.org/test');
|
||||
|
||||
self::assertSame('http://example.org/test', (string) $mockHandler->getLastRequest()->getUri());
|
||||
}
|
||||
|
||||
public function testOnlyAddSchemeWhenHostIsPresent()
|
||||
{
|
||||
$mockHandler = new MockHandler([new Response()]);
|
||||
$client = new Client(['handler' => $mockHandler]);
|
||||
|
||||
$client->request('GET', 'baz');
|
||||
self::assertSame(
|
||||
'baz',
|
||||
(string) $mockHandler->getLastRequest()->getUri()
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException InvalidArgumentException
|
||||
*/
|
||||
public function testHandlerIsCallable()
|
||||
{
|
||||
new Client(['handler' => 'not_cllable']);
|
||||
}
|
||||
|
||||
public function testResponseBodyAsString()
|
||||
{
|
||||
$responseBody = '{ "package": "guzzle" }';
|
||||
$mock = new MockHandler([new Response(200, ['Content-Type' => 'application/json'], $responseBody)]);
|
||||
$client = new Client(['handler' => $mock]);
|
||||
$request = new Request('GET', 'http://foo.com');
|
||||
$response = $client->send($request, ['json' => ['a' => 'b']]);
|
||||
|
||||
self::assertSame($responseBody, (string) $response->getBody());
|
||||
}
|
||||
|
||||
public function testResponseContent()
|
||||
{
|
||||
$responseBody = '{ "package": "guzzle" }';
|
||||
$mock = new MockHandler([new Response(200, ['Content-Type' => 'application/json'], $responseBody)]);
|
||||
$client = new Client(['handler' => $mock]);
|
||||
$request = new Request('POST', 'http://foo.com');
|
||||
$response = $client->send($request, ['json' => ['a' => 'b']]);
|
||||
|
||||
self::assertSame($responseBody, $response->getBody()->getContents());
|
||||
}
|
||||
|
||||
public function testIdnSupportDefaultValue()
|
||||
{
|
||||
$mockHandler = new MockHandler([new Response()]);
|
||||
$client = new Client(['handler' => $mockHandler]);
|
||||
|
||||
$config = $client->getConfig();
|
||||
|
||||
self::assertTrue($config['idn_conversion']);
|
||||
}
|
||||
|
||||
public function testIdnIsTranslatedToAsciiWhenConversionIsEnabled()
|
||||
{
|
||||
$mockHandler = new MockHandler([new Response()]);
|
||||
$client = new Client(['handler' => $mockHandler]);
|
||||
|
||||
$client->request('GET', 'https://яндекс.рф/images', ['idn_conversion' => true]);
|
||||
|
||||
$request = $mockHandler->getLastRequest();
|
||||
|
||||
self::assertSame('https://xn--d1acpjx3f.xn--p1ai/images', (string) $request->getUri());
|
||||
self::assertSame('xn--d1acpjx3f.xn--p1ai', (string) $request->getHeaderLine('Host'));
|
||||
}
|
||||
|
||||
public function testIdnStaysTheSameWhenConversionIsDisabled()
|
||||
{
|
||||
$mockHandler = new MockHandler([new Response()]);
|
||||
$client = new Client(['handler' => $mockHandler]);
|
||||
|
||||
$client->request('GET', 'https://яндекс.рф/images', ['idn_conversion' => false]);
|
||||
|
||||
$request = $mockHandler->getLastRequest();
|
||||
|
||||
self::assertSame('https://яндекс.рф/images', (string) $request->getUri());
|
||||
self::assertSame('яндекс.рф', (string) $request->getHeaderLine('Host'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \GuzzleHttp\Exception\InvalidArgumentException
|
||||
* @expectedExceptionMessage IDN conversion failed
|
||||
*/
|
||||
public function testExceptionOnInvalidIdn()
|
||||
{
|
||||
$mockHandler = new MockHandler([new Response()]);
|
||||
$client = new Client(['handler' => $mockHandler]);
|
||||
|
||||
$client->request('GET', 'https://-яндекс.рф/images', ['idn_conversion' => true]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @depends testCanUseRelativeUriWithSend
|
||||
* @depends testIdnSupportDefaultValue
|
||||
*/
|
||||
public function testIdnBaseUri()
|
||||
{
|
||||
$mock = new MockHandler([new Response()]);
|
||||
$client = new Client([
|
||||
'handler' => $mock,
|
||||
'base_uri' => 'http://яндекс.рф',
|
||||
]);
|
||||
self::assertSame('http://яндекс.рф', (string) $client->getConfig('base_uri'));
|
||||
$request = new Request('GET', '/baz');
|
||||
$client->send($request);
|
||||
self::assertSame('http://xn--d1acpjx3f.xn--p1ai/baz', (string) $mock->getLastRequest()->getUri());
|
||||
self::assertSame('xn--d1acpjx3f.xn--p1ai', (string) $mock->getLastRequest()->getHeaderLine('Host'));
|
||||
}
|
||||
|
||||
public function testIdnWithRedirect()
|
||||
{
|
||||
$mockHandler = new MockHandler([
|
||||
new Response(302, ['Location' => 'http://www.tést.com/whatever']),
|
||||
new Response()
|
||||
]);
|
||||
$handler = HandlerStack::create($mockHandler);
|
||||
$requests = [];
|
||||
$handler->push(Middleware::history($requests));
|
||||
$client = new Client(['handler' => $handler]);
|
||||
|
||||
$client->request('GET', 'https://яндекс.рф/images', [
|
||||
RequestOptions::ALLOW_REDIRECTS => [
|
||||
'referer' => true,
|
||||
'track_redirects' => true
|
||||
],
|
||||
'idn_conversion' => true
|
||||
]);
|
||||
|
||||
$request = $mockHandler->getLastRequest();
|
||||
|
||||
self::assertSame('http://www.xn--tst-bma.com/whatever', (string) $request->getUri());
|
||||
self::assertSame('www.xn--tst-bma.com', (string) $request->getHeaderLine('Host'));
|
||||
|
||||
$request = $requests[0]['request'];
|
||||
self::assertSame('https://xn--d1acpjx3f.xn--p1ai/images', (string) $request->getUri());
|
||||
self::assertSame('xn--d1acpjx3f.xn--p1ai', (string) $request->getHeaderLine('Host'));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,449 @@
|
||||
<?php
|
||||
namespace GuzzleHttp\Tests\CookieJar;
|
||||
|
||||
use DateInterval;
|
||||
use DateTime;
|
||||
use DateTimeImmutable;
|
||||
use GuzzleHttp\Cookie\CookieJar;
|
||||
use GuzzleHttp\Cookie\SetCookie;
|
||||
use GuzzleHttp\Psr7\Request;
|
||||
use GuzzleHttp\Psr7\Response;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/**
|
||||
* @covers GuzzleHttp\Cookie\CookieJar
|
||||
*/
|
||||
class CookieJarTest extends TestCase
|
||||
{
|
||||
/** @var CookieJar */
|
||||
private $jar;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
$this->jar = new CookieJar();
|
||||
}
|
||||
|
||||
protected function getTestCookies()
|
||||
{
|
||||
return [
|
||||
new SetCookie(['Name' => 'foo', 'Value' => 'bar', 'Domain' => 'foo.com', 'Path' => '/', 'Discard' => true]),
|
||||
new SetCookie(['Name' => 'test', 'Value' => '123', 'Domain' => 'baz.com', 'Path' => '/foo', 'Expires' => 2]),
|
||||
new SetCookie(['Name' => 'you', 'Value' => '123', 'Domain' => 'bar.com', 'Path' => '/boo', 'Expires' => time() + 1000])
|
||||
];
|
||||
}
|
||||
|
||||
public function testCreatesFromArray()
|
||||
{
|
||||
$jar = CookieJar::fromArray([
|
||||
'foo' => 'bar',
|
||||
'baz' => 'bam'
|
||||
], 'example.com');
|
||||
self::assertCount(2, $jar);
|
||||
}
|
||||
|
||||
public function testEmptyJarIsCountable()
|
||||
{
|
||||
self::assertCount(0, new CookieJar());
|
||||
}
|
||||
|
||||
public function testGetsCookiesByName()
|
||||
{
|
||||
$cookies = $this->getTestCookies();
|
||||
foreach ($this->getTestCookies() as $cookie) {
|
||||
$this->jar->setCookie($cookie);
|
||||
}
|
||||
|
||||
$testCookie = $cookies[0];
|
||||
self::assertEquals($testCookie, $this->jar->getCookieByName($testCookie->getName()));
|
||||
self::assertNull($this->jar->getCookieByName("doesnotexist"));
|
||||
self::assertNull($this->jar->getCookieByName(""));
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides test data for cookie cookieJar retrieval
|
||||
*/
|
||||
public function getCookiesDataProvider()
|
||||
{
|
||||
return [
|
||||
[['foo', 'baz', 'test', 'muppet', 'googoo'], '', '', '', false],
|
||||
[['foo', 'baz', 'muppet', 'googoo'], '', '', '', true],
|
||||
[['googoo'], 'www.example.com', '', '', false],
|
||||
[['muppet', 'googoo'], 'test.y.example.com', '', '', false],
|
||||
[['foo', 'baz'], 'example.com', '', '', false],
|
||||
[['muppet'], 'x.y.example.com', '/acme/', '', false],
|
||||
[['muppet'], 'x.y.example.com', '/acme/test/', '', false],
|
||||
[['googoo'], 'x.y.example.com', '/test/acme/test/', '', false],
|
||||
[['foo', 'baz'], 'example.com', '', '', false],
|
||||
[['baz'], 'example.com', '', 'baz', false],
|
||||
];
|
||||
}
|
||||
|
||||
public function testStoresAndRetrievesCookies()
|
||||
{
|
||||
$cookies = $this->getTestCookies();
|
||||
foreach ($cookies as $cookie) {
|
||||
self::assertTrue($this->jar->setCookie($cookie));
|
||||
}
|
||||
|
||||
self::assertCount(3, $this->jar);
|
||||
self::assertCount(3, $this->jar->getIterator());
|
||||
self::assertEquals($cookies, $this->jar->getIterator()->getArrayCopy());
|
||||
}
|
||||
|
||||
public function testRemovesTemporaryCookies()
|
||||
{
|
||||
$cookies = $this->getTestCookies();
|
||||
foreach ($this->getTestCookies() as $cookie) {
|
||||
$this->jar->setCookie($cookie);
|
||||
}
|
||||
$this->jar->clearSessionCookies();
|
||||
self::assertEquals(
|
||||
[$cookies[1], $cookies[2]],
|
||||
$this->jar->getIterator()->getArrayCopy()
|
||||
);
|
||||
}
|
||||
|
||||
public function testRemovesSelectively()
|
||||
{
|
||||
foreach ($this->getTestCookies() as $cookie) {
|
||||
$this->jar->setCookie($cookie);
|
||||
}
|
||||
|
||||
// Remove foo.com cookies
|
||||
$this->jar->clear('foo.com');
|
||||
self::assertCount(2, $this->jar);
|
||||
// Try again, removing no further cookies
|
||||
$this->jar->clear('foo.com');
|
||||
self::assertCount(2, $this->jar);
|
||||
|
||||
// Remove bar.com cookies with path of /boo
|
||||
$this->jar->clear('bar.com', '/boo');
|
||||
self::assertCount(1, $this->jar);
|
||||
|
||||
// Remove cookie by name
|
||||
$this->jar->clear(null, null, 'test');
|
||||
self::assertCount(0, $this->jar);
|
||||
}
|
||||
|
||||
public function testDoesNotAddIncompleteCookies()
|
||||
{
|
||||
self::assertFalse($this->jar->setCookie(new SetCookie()));
|
||||
self::assertFalse($this->jar->setCookie(new SetCookie([
|
||||
'Name' => 'foo'
|
||||
])));
|
||||
self::assertFalse($this->jar->setCookie(new SetCookie([
|
||||
'Name' => false
|
||||
])));
|
||||
self::assertFalse($this->jar->setCookie(new SetCookie([
|
||||
'Name' => true
|
||||
])));
|
||||
self::assertFalse($this->jar->setCookie(new SetCookie([
|
||||
'Name' => 'foo',
|
||||
'Domain' => 'foo.com'
|
||||
])));
|
||||
}
|
||||
|
||||
public function testDoesNotAddEmptyCookies()
|
||||
{
|
||||
self::assertFalse($this->jar->setCookie(new SetCookie([
|
||||
'Name' => '',
|
||||
'Domain' => 'foo.com',
|
||||
'Value' => 0
|
||||
])));
|
||||
}
|
||||
|
||||
public function testDoesAddValidCookies()
|
||||
{
|
||||
self::assertTrue($this->jar->setCookie(new SetCookie([
|
||||
'Name' => '0',
|
||||
'Domain' => 'foo.com',
|
||||
'Value' => 0
|
||||
])));
|
||||
self::assertTrue($this->jar->setCookie(new SetCookie([
|
||||
'Name' => 'foo',
|
||||
'Domain' => 'foo.com',
|
||||
'Value' => 0
|
||||
])));
|
||||
self::assertTrue($this->jar->setCookie(new SetCookie([
|
||||
'Name' => 'foo',
|
||||
'Domain' => 'foo.com',
|
||||
'Value' => 0.0
|
||||
])));
|
||||
self::assertTrue($this->jar->setCookie(new SetCookie([
|
||||
'Name' => 'foo',
|
||||
'Domain' => 'foo.com',
|
||||
'Value' => '0'
|
||||
])));
|
||||
}
|
||||
|
||||
public function testOverwritesCookiesThatAreOlderOrDiscardable()
|
||||
{
|
||||
$t = time() + 1000;
|
||||
$data = [
|
||||
'Name' => 'foo',
|
||||
'Value' => 'bar',
|
||||
'Domain' => '.example.com',
|
||||
'Path' => '/',
|
||||
'Max-Age' => '86400',
|
||||
'Secure' => true,
|
||||
'Discard' => true,
|
||||
'Expires' => $t
|
||||
];
|
||||
|
||||
// Make sure that the discard cookie is overridden with the non-discard
|
||||
self::assertTrue($this->jar->setCookie(new SetCookie($data)));
|
||||
self::assertCount(1, $this->jar);
|
||||
|
||||
$data['Discard'] = false;
|
||||
self::assertTrue($this->jar->setCookie(new SetCookie($data)));
|
||||
self::assertCount(1, $this->jar);
|
||||
|
||||
$c = $this->jar->getIterator()->getArrayCopy();
|
||||
self::assertFalse($c[0]->getDiscard());
|
||||
|
||||
// Make sure it doesn't duplicate the cookie
|
||||
$this->jar->setCookie(new SetCookie($data));
|
||||
self::assertCount(1, $this->jar);
|
||||
|
||||
// Make sure the more future-ful expiration date supersede the other
|
||||
$data['Expires'] = time() + 2000;
|
||||
self::assertTrue($this->jar->setCookie(new SetCookie($data)));
|
||||
self::assertCount(1, $this->jar);
|
||||
$c = $this->jar->getIterator()->getArrayCopy();
|
||||
self::assertNotEquals($t, $c[0]->getExpires());
|
||||
}
|
||||
|
||||
public function testOverwritesCookiesThatHaveChanged()
|
||||
{
|
||||
$t = time() + 1000;
|
||||
$data = [
|
||||
'Name' => 'foo',
|
||||
'Value' => 'bar',
|
||||
'Domain' => '.example.com',
|
||||
'Path' => '/',
|
||||
'Max-Age' => '86400',
|
||||
'Secure' => true,
|
||||
'Discard' => true,
|
||||
'Expires' => $t
|
||||
];
|
||||
|
||||
// Make sure that the discard cookie is overridden with the non-discard
|
||||
self::assertTrue($this->jar->setCookie(new SetCookie($data)));
|
||||
|
||||
$data['Value'] = 'boo';
|
||||
self::assertTrue($this->jar->setCookie(new SetCookie($data)));
|
||||
self::assertCount(1, $this->jar);
|
||||
|
||||
// Changing the value plus a parameter also must overwrite the existing one
|
||||
$data['Value'] = 'zoo';
|
||||
$data['Secure'] = false;
|
||||
self::assertTrue($this->jar->setCookie(new SetCookie($data)));
|
||||
self::assertCount(1, $this->jar);
|
||||
|
||||
$c = $this->jar->getIterator()->getArrayCopy();
|
||||
self::assertSame('zoo', $c[0]->getValue());
|
||||
}
|
||||
|
||||
public function testAddsCookiesFromResponseWithRequest()
|
||||
{
|
||||
$response = new Response(200, [
|
||||
'Set-Cookie' => "fpc=d=.Hm.yh4.1XmJWjJfs4orLQzKzPImxklQoxXSHOZATHUSEFciRueW_7704iYUtsXNEXq0M92Px2glMdWypmJ7HIQl6XIUvrZimWjQ3vIdeuRbI.FNQMAfcxu_XN1zSx7l.AcPdKL6guHc2V7hIQFhnjRW0rxm2oHY1P4bGQxFNz7f.tHm12ZD3DbdMDiDy7TBXsuP4DM-&v=2; expires=Fri, 02-Mar-2019 02:17:40 GMT;"
|
||||
]);
|
||||
$request = new Request('GET', 'http://www.example.com');
|
||||
$this->jar->extractCookies($request, $response);
|
||||
self::assertCount(1, $this->jar);
|
||||
}
|
||||
|
||||
public function getMatchingCookiesDataProvider()
|
||||
{
|
||||
return [
|
||||
['https://example.com', 'foo=bar; baz=foobar'],
|
||||
['http://example.com', ''],
|
||||
['https://example.com:8912', 'foo=bar; baz=foobar'],
|
||||
['https://foo.example.com', 'foo=bar; baz=foobar'],
|
||||
['http://foo.example.com/test/acme/', 'googoo=gaga']
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider getMatchingCookiesDataProvider
|
||||
*/
|
||||
public function testReturnsCookiesMatchingRequests($url, $cookies)
|
||||
{
|
||||
$bag = [
|
||||
new SetCookie([
|
||||
'Name' => 'foo',
|
||||
'Value' => 'bar',
|
||||
'Domain' => 'example.com',
|
||||
'Path' => '/',
|
||||
'Max-Age' => '86400',
|
||||
'Secure' => true
|
||||
]),
|
||||
new SetCookie([
|
||||
'Name' => 'baz',
|
||||
'Value' => 'foobar',
|
||||
'Domain' => 'example.com',
|
||||
'Path' => '/',
|
||||
'Max-Age' => '86400',
|
||||
'Secure' => true
|
||||
]),
|
||||
new SetCookie([
|
||||
'Name' => 'test',
|
||||
'Value' => '123',
|
||||
'Domain' => 'www.foobar.com',
|
||||
'Path' => '/path/',
|
||||
'Discard' => true
|
||||
]),
|
||||
new SetCookie([
|
||||
'Name' => 'muppet',
|
||||
'Value' => 'cookie_monster',
|
||||
'Domain' => '.y.example.com',
|
||||
'Path' => '/acme/',
|
||||
'Expires' => time() + 86400
|
||||
]),
|
||||
new SetCookie([
|
||||
'Name' => 'googoo',
|
||||
'Value' => 'gaga',
|
||||
'Domain' => '.example.com',
|
||||
'Path' => '/test/acme/',
|
||||
'Max-Age' => 1500
|
||||
])
|
||||
];
|
||||
|
||||
foreach ($bag as $cookie) {
|
||||
$this->jar->setCookie($cookie);
|
||||
}
|
||||
|
||||
$request = new Request('GET', $url);
|
||||
$request = $this->jar->withCookieHeader($request);
|
||||
self::assertSame($cookies, $request->getHeaderLine('Cookie'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \RuntimeException
|
||||
* @expectedExceptionMessage Invalid cookie: Cookie name must not contain invalid characters: ASCII Control characters (0-31;127), space, tab and the following characters: ()<>@,;:\"/?={}
|
||||
*/
|
||||
public function testThrowsExceptionWithStrictMode()
|
||||
{
|
||||
$a = new CookieJar(true);
|
||||
$a->setCookie(new SetCookie(['Name' => "abc\n", 'Value' => 'foo', 'Domain' => 'bar']));
|
||||
}
|
||||
|
||||
public function testDeletesCookiesByName()
|
||||
{
|
||||
$cookies = $this->getTestCookies();
|
||||
$cookies[] = new SetCookie([
|
||||
'Name' => 'other',
|
||||
'Value' => '123',
|
||||
'Domain' => 'bar.com',
|
||||
'Path' => '/boo',
|
||||
'Expires' => time() + 1000
|
||||
]);
|
||||
$jar = new CookieJar();
|
||||
foreach ($cookies as $cookie) {
|
||||
$jar->setCookie($cookie);
|
||||
}
|
||||
self::assertCount(4, $jar);
|
||||
$jar->clear('bar.com', '/boo', 'other');
|
||||
self::assertCount(3, $jar);
|
||||
$names = array_map(function (SetCookie $c) {
|
||||
return $c->getName();
|
||||
}, $jar->getIterator()->getArrayCopy());
|
||||
self::assertSame(['foo', 'test', 'you'], $names);
|
||||
}
|
||||
|
||||
public function testCanConvertToAndLoadFromArray()
|
||||
{
|
||||
$jar = new CookieJar(true);
|
||||
foreach ($this->getTestCookies() as $cookie) {
|
||||
$jar->setCookie($cookie);
|
||||
}
|
||||
self::assertCount(3, $jar);
|
||||
$arr = $jar->toArray();
|
||||
self::assertCount(3, $arr);
|
||||
$newCookieJar = new CookieJar(false, $arr);
|
||||
self::assertCount(3, $newCookieJar);
|
||||
self::assertSame($jar->toArray(), $newCookieJar->toArray());
|
||||
}
|
||||
|
||||
public function testAddsCookiesWithEmptyPathFromResponse()
|
||||
{
|
||||
$response = new Response(200, [
|
||||
'Set-Cookie' => "fpc=foobar; expires={$this->futureExpirationDate()}; path=;"
|
||||
]);
|
||||
$request = new Request('GET', 'http://www.example.com');
|
||||
$this->jar->extractCookies($request, $response);
|
||||
$newRequest = $this->jar->withCookieHeader(new Request('GET', 'http://www.example.com/foo'));
|
||||
self::assertTrue($newRequest->hasHeader('Cookie'));
|
||||
}
|
||||
|
||||
public function getCookiePathsDataProvider()
|
||||
{
|
||||
return [
|
||||
['', '/'],
|
||||
['/', '/'],
|
||||
['/foo', '/'],
|
||||
['/foo/bar', '/foo'],
|
||||
['/foo/bar/', '/foo/bar'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider getCookiePathsDataProvider
|
||||
*/
|
||||
public function testCookiePathWithEmptySetCookiePath($uriPath, $cookiePath)
|
||||
{
|
||||
$response = (new Response(200))
|
||||
->withAddedHeader(
|
||||
'Set-Cookie',
|
||||
"foo=bar; expires={$this->futureExpirationDate()}; domain=www.example.com; path=;"
|
||||
)
|
||||
->withAddedHeader(
|
||||
'Set-Cookie',
|
||||
"bar=foo; expires={$this->futureExpirationDate()}; domain=www.example.com; path=foobar;"
|
||||
)
|
||||
;
|
||||
$request = (new Request('GET', "https://www.example.com{$uriPath}"));
|
||||
$this->jar->extractCookies($request, $response);
|
||||
|
||||
self::assertSame($cookiePath, $this->jar->toArray()[0]['Path']);
|
||||
self::assertSame($cookiePath, $this->jar->toArray()[1]['Path']);
|
||||
}
|
||||
|
||||
public function getDomainMatchesProvider()
|
||||
{
|
||||
return [
|
||||
['www.example.com', 'www.example.com', true],
|
||||
['www.example.com', 'www.EXAMPLE.com', true],
|
||||
['www.example.com', 'www.example.net', false],
|
||||
['www.example.com', 'ftp.example.com', false],
|
||||
['www.example.com', 'example.com', true],
|
||||
['www.example.com', 'EXAMPLE.com', true],
|
||||
['fra.de.example.com', 'EXAMPLE.com', true],
|
||||
['www.EXAMPLE.com', 'www.example.com', true],
|
||||
['www.EXAMPLE.com', 'www.example.COM', true],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider getDomainMatchesProvider
|
||||
*/
|
||||
public function testIgnoresCookiesForMismatchingDomains($requestHost, $domainAttribute, $matches)
|
||||
{
|
||||
$response = (new Response(200))
|
||||
->withAddedHeader(
|
||||
'Set-Cookie',
|
||||
"foo=bar; expires={$this->futureExpirationDate()}; domain={$domainAttribute}; path=/;"
|
||||
)
|
||||
;
|
||||
$request = (new Request('GET', "https://{$requestHost}/"));
|
||||
$this->jar->extractCookies($request, $response);
|
||||
|
||||
self::assertCount($matches ? 1 : 0, $this->jar->toArray());
|
||||
}
|
||||
|
||||
private function futureExpirationDate()
|
||||
{
|
||||
return (new DateTimeImmutable)->add(new DateInterval('P1D'))->format(DateTime::COOKIE);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,88 @@
|
||||
<?php
|
||||
namespace GuzzleHttp\Tests\CookieJar;
|
||||
|
||||
use GuzzleHttp\Cookie\FileCookieJar;
|
||||
use GuzzleHttp\Cookie\SetCookie;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/**
|
||||
* @covers GuzzleHttp\Cookie\FileCookieJar
|
||||
*/
|
||||
class FileCookieJarTest extends TestCase
|
||||
{
|
||||
private $file;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
$this->file = tempnam('/tmp', 'file-cookies');
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \RuntimeException
|
||||
*/
|
||||
public function testValidatesCookieFile()
|
||||
{
|
||||
file_put_contents($this->file, 'true');
|
||||
new FileCookieJar($this->file);
|
||||
}
|
||||
|
||||
public function testLoadsFromFile()
|
||||
{
|
||||
$jar = new FileCookieJar($this->file);
|
||||
self::assertSame([], $jar->getIterator()->getArrayCopy());
|
||||
unlink($this->file);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider providerPersistsToFileFileParameters
|
||||
*/
|
||||
public function testPersistsToFile($testSaveSessionCookie = false)
|
||||
{
|
||||
$jar = new FileCookieJar($this->file, $testSaveSessionCookie);
|
||||
$jar->setCookie(new SetCookie([
|
||||
'Name' => 'foo',
|
||||
'Value' => 'bar',
|
||||
'Domain' => 'foo.com',
|
||||
'Expires' => time() + 1000
|
||||
]));
|
||||
$jar->setCookie(new SetCookie([
|
||||
'Name' => 'baz',
|
||||
'Value' => 'bar',
|
||||
'Domain' => 'foo.com',
|
||||
'Expires' => time() + 1000
|
||||
]));
|
||||
$jar->setCookie(new SetCookie([
|
||||
'Name' => 'boo',
|
||||
'Value' => 'bar',
|
||||
'Domain' => 'foo.com',
|
||||
]));
|
||||
|
||||
self::assertCount(3, $jar);
|
||||
unset($jar);
|
||||
|
||||
// Make sure it wrote to the file
|
||||
$contents = file_get_contents($this->file);
|
||||
self::assertNotEmpty($contents);
|
||||
|
||||
// Load the cookieJar from the file
|
||||
$jar = new FileCookieJar($this->file);
|
||||
|
||||
if ($testSaveSessionCookie) {
|
||||
self::assertCount(3, $jar);
|
||||
} else {
|
||||
// Weeds out temporary and session cookies
|
||||
self::assertCount(2, $jar);
|
||||
}
|
||||
|
||||
unset($jar);
|
||||
unlink($this->file);
|
||||
}
|
||||
|
||||
public function providerPersistsToFileFileParameters()
|
||||
{
|
||||
return [
|
||||
[false],
|
||||
[true]
|
||||
];
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,92 @@
|
||||
<?php
|
||||
namespace GuzzleHttp\Tests\CookieJar;
|
||||
|
||||
use GuzzleHttp\Cookie\SessionCookieJar;
|
||||
use GuzzleHttp\Cookie\SetCookie;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/**
|
||||
* @covers GuzzleHttp\Cookie\SessionCookieJar
|
||||
*/
|
||||
class SessionCookieJarTest extends TestCase
|
||||
{
|
||||
private $sessionVar;
|
||||
|
||||
public function setUp()
|
||||
{
|
||||
$this->sessionVar = 'sessionKey';
|
||||
|
||||
if (!isset($_SESSION)) {
|
||||
$_SESSION = [];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \RuntimeException
|
||||
*/
|
||||
public function testValidatesCookieSession()
|
||||
{
|
||||
$_SESSION[$this->sessionVar] = 'true';
|
||||
new SessionCookieJar($this->sessionVar);
|
||||
}
|
||||
|
||||
public function testLoadsFromSession()
|
||||
{
|
||||
$jar = new SessionCookieJar($this->sessionVar);
|
||||
self::assertSame([], $jar->getIterator()->getArrayCopy());
|
||||
unset($_SESSION[$this->sessionVar]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider providerPersistsToSessionParameters
|
||||
*/
|
||||
public function testPersistsToSession($testSaveSessionCookie = false)
|
||||
{
|
||||
$jar = new SessionCookieJar($this->sessionVar, $testSaveSessionCookie);
|
||||
$jar->setCookie(new SetCookie([
|
||||
'Name' => 'foo',
|
||||
'Value' => 'bar',
|
||||
'Domain' => 'foo.com',
|
||||
'Expires' => time() + 1000
|
||||
]));
|
||||
$jar->setCookie(new SetCookie([
|
||||
'Name' => 'baz',
|
||||
'Value' => 'bar',
|
||||
'Domain' => 'foo.com',
|
||||
'Expires' => time() + 1000
|
||||
]));
|
||||
$jar->setCookie(new SetCookie([
|
||||
'Name' => 'boo',
|
||||
'Value' => 'bar',
|
||||
'Domain' => 'foo.com',
|
||||
]));
|
||||
|
||||
self::assertCount(3, $jar);
|
||||
unset($jar);
|
||||
|
||||
// Make sure it wrote to the sessionVar in $_SESSION
|
||||
$contents = $_SESSION[$this->sessionVar];
|
||||
self::assertNotEmpty($contents);
|
||||
|
||||
// Load the cookieJar from the file
|
||||
$jar = new SessionCookieJar($this->sessionVar);
|
||||
|
||||
if ($testSaveSessionCookie) {
|
||||
self::assertCount(3, $jar);
|
||||
} else {
|
||||
// Weeds out temporary and session cookies
|
||||
self::assertCount(2, $jar);
|
||||
}
|
||||
|
||||
unset($jar);
|
||||
unset($_SESSION[$this->sessionVar]);
|
||||
}
|
||||
|
||||
public function providerPersistsToSessionParameters()
|
||||
{
|
||||
return [
|
||||
[false],
|
||||
[true]
|
||||
];
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,445 @@
|
||||
<?php
|
||||
namespace GuzzleHttp\Tests\CookieJar;
|
||||
|
||||
use GuzzleHttp\Cookie\SetCookie;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/**
|
||||
* @covers GuzzleHttp\Cookie\SetCookie
|
||||
*/
|
||||
class SetCookieTest extends TestCase
|
||||
{
|
||||
public function testInitializesDefaultValues()
|
||||
{
|
||||
$cookie = new SetCookie();
|
||||
self::assertSame('/', $cookie->getPath());
|
||||
}
|
||||
|
||||
public function testConvertsDateTimeMaxAgeToUnixTimestamp()
|
||||
{
|
||||
$cookie = new SetCookie(['Expires' => 'November 20, 1984']);
|
||||
self::assertInternalType('integer', $cookie->getExpires());
|
||||
}
|
||||
|
||||
public function testAddsExpiresBasedOnMaxAge()
|
||||
{
|
||||
$t = time();
|
||||
$cookie = new SetCookie(['Max-Age' => 100]);
|
||||
self::assertEquals($t + 100, $cookie->getExpires());
|
||||
}
|
||||
|
||||
public function testHoldsValues()
|
||||
{
|
||||
$t = time();
|
||||
$data = [
|
||||
'Name' => 'foo',
|
||||
'Value' => 'baz',
|
||||
'Path' => '/bar',
|
||||
'Domain' => 'baz.com',
|
||||
'Expires' => $t,
|
||||
'Max-Age' => 100,
|
||||
'Secure' => true,
|
||||
'Discard' => true,
|
||||
'HttpOnly' => true,
|
||||
'foo' => 'baz',
|
||||
'bar' => 'bam'
|
||||
];
|
||||
|
||||
$cookie = new SetCookie($data);
|
||||
self::assertEquals($data, $cookie->toArray());
|
||||
|
||||
self::assertSame('foo', $cookie->getName());
|
||||
self::assertSame('baz', $cookie->getValue());
|
||||
self::assertSame('baz.com', $cookie->getDomain());
|
||||
self::assertSame('/bar', $cookie->getPath());
|
||||
self::assertSame($t, $cookie->getExpires());
|
||||
self::assertSame(100, $cookie->getMaxAge());
|
||||
self::assertTrue($cookie->getSecure());
|
||||
self::assertTrue($cookie->getDiscard());
|
||||
self::assertTrue($cookie->getHttpOnly());
|
||||
self::assertSame('baz', $cookie->toArray()['foo']);
|
||||
self::assertSame('bam', $cookie->toArray()['bar']);
|
||||
|
||||
$cookie->setName('a');
|
||||
$cookie->setValue('b');
|
||||
$cookie->setPath('c');
|
||||
$cookie->setDomain('bar.com');
|
||||
$cookie->setExpires(10);
|
||||
$cookie->setMaxAge(200);
|
||||
$cookie->setSecure(false);
|
||||
$cookie->setHttpOnly(false);
|
||||
$cookie->setDiscard(false);
|
||||
|
||||
self::assertSame('a', $cookie->getName());
|
||||
self::assertSame('b', $cookie->getValue());
|
||||
self::assertSame('c', $cookie->getPath());
|
||||
self::assertSame('bar.com', $cookie->getDomain());
|
||||
self::assertSame(10, $cookie->getExpires());
|
||||
self::assertSame(200, $cookie->getMaxAge());
|
||||
self::assertFalse($cookie->getSecure());
|
||||
self::assertFalse($cookie->getDiscard());
|
||||
self::assertFalse($cookie->getHttpOnly());
|
||||
}
|
||||
|
||||
public function testDeterminesIfExpired()
|
||||
{
|
||||
$c = new SetCookie();
|
||||
$c->setExpires(10);
|
||||
self::assertTrue($c->isExpired());
|
||||
$c->setExpires(time() + 10000);
|
||||
self::assertFalse($c->isExpired());
|
||||
}
|
||||
|
||||
public function testMatchesDomain()
|
||||
{
|
||||
$cookie = new SetCookie();
|
||||
self::assertTrue($cookie->matchesDomain('baz.com'));
|
||||
|
||||
$cookie->setDomain('baz.com');
|
||||
self::assertTrue($cookie->matchesDomain('baz.com'));
|
||||
self::assertFalse($cookie->matchesDomain('bar.com'));
|
||||
|
||||
$cookie->setDomain('.baz.com');
|
||||
self::assertTrue($cookie->matchesDomain('.baz.com'));
|
||||
self::assertTrue($cookie->matchesDomain('foo.baz.com'));
|
||||
self::assertFalse($cookie->matchesDomain('baz.bar.com'));
|
||||
self::assertTrue($cookie->matchesDomain('baz.com'));
|
||||
|
||||
$cookie->setDomain('.127.0.0.1');
|
||||
self::assertTrue($cookie->matchesDomain('127.0.0.1'));
|
||||
|
||||
$cookie->setDomain('127.0.0.1');
|
||||
self::assertTrue($cookie->matchesDomain('127.0.0.1'));
|
||||
|
||||
$cookie->setDomain('.com.');
|
||||
self::assertFalse($cookie->matchesDomain('baz.com'));
|
||||
|
||||
$cookie->setDomain('.local');
|
||||
self::assertTrue($cookie->matchesDomain('example.local'));
|
||||
|
||||
$cookie->setDomain('example.com/'); // malformed domain
|
||||
self::assertFalse($cookie->matchesDomain('example.com'));
|
||||
}
|
||||
|
||||
public function pathMatchProvider()
|
||||
{
|
||||
return [
|
||||
['/foo', '/foo', true],
|
||||
['/foo', '/Foo', false],
|
||||
['/foo', '/fo', false],
|
||||
['/foo', '/foo/bar', true],
|
||||
['/foo', '/foo/bar/baz', true],
|
||||
['/foo', '/foo/bar//baz', true],
|
||||
['/foo', '/foobar', false],
|
||||
['/foo/bar', '/foo', false],
|
||||
['/foo/bar', '/foobar', false],
|
||||
['/foo/bar', '/foo/bar', true],
|
||||
['/foo/bar', '/foo/bar/', true],
|
||||
['/foo/bar', '/foo/bar/baz', true],
|
||||
['/foo/bar/', '/foo/bar', false],
|
||||
['/foo/bar/', '/foo/bar/', true],
|
||||
['/foo/bar/', '/foo/bar/baz', true],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider pathMatchProvider
|
||||
*/
|
||||
public function testMatchesPath($cookiePath, $requestPath, $isMatch)
|
||||
{
|
||||
$cookie = new SetCookie();
|
||||
$cookie->setPath($cookiePath);
|
||||
self::assertSame($isMatch, $cookie->matchesPath($requestPath));
|
||||
}
|
||||
|
||||
public function cookieValidateProvider()
|
||||
{
|
||||
return [
|
||||
['foo', 'baz', 'bar', true],
|
||||
['0', '0', '0', true],
|
||||
['foo[bar]', 'baz', 'bar', true],
|
||||
['', 'baz', 'bar', 'The cookie name must not be empty'],
|
||||
['foo', '', 'bar', 'The cookie value must not be empty'],
|
||||
['foo', 'baz', '', 'The cookie domain must not be empty'],
|
||||
["foo\r", 'baz', '0', 'Cookie name must not contain invalid characters: ASCII Control characters (0-31;127), space, tab and the following characters: ()<>@,;:\"/?={}'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider cookieValidateProvider
|
||||
*/
|
||||
public function testValidatesCookies($name, $value, $domain, $result)
|
||||
{
|
||||
$cookie = new SetCookie([
|
||||
'Name' => $name,
|
||||
'Value' => $value,
|
||||
'Domain' => $domain,
|
||||
]);
|
||||
self::assertSame($result, $cookie->validate());
|
||||
}
|
||||
|
||||
public function testDoesNotMatchIp()
|
||||
{
|
||||
$cookie = new SetCookie(['Domain' => '192.168.16.']);
|
||||
self::assertFalse($cookie->matchesDomain('192.168.16.121'));
|
||||
}
|
||||
|
||||
public function testConvertsToString()
|
||||
{
|
||||
$t = 1382916008;
|
||||
$cookie = new SetCookie([
|
||||
'Name' => 'test',
|
||||
'Value' => '123',
|
||||
'Domain' => 'foo.com',
|
||||
'Expires' => $t,
|
||||
'Path' => '/abc',
|
||||
'HttpOnly' => true,
|
||||
'Secure' => true
|
||||
]);
|
||||
self::assertSame(
|
||||
'test=123; Domain=foo.com; Path=/abc; Expires=Sun, 27 Oct 2013 23:20:08 GMT; Secure; HttpOnly',
|
||||
(string) $cookie
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the parsed information from a cookie
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function cookieParserDataProvider()
|
||||
{
|
||||
return [
|
||||
[
|
||||
'ASIHTTPRequestTestCookie=This+is+the+value; expires=Sat, 26-Jul-2008 17:00:42 GMT; path=/tests; domain=allseeing-i.com; PHPSESSID=6c951590e7a9359bcedde25cda73e43c; path=/;',
|
||||
[
|
||||
'Domain' => 'allseeing-i.com',
|
||||
'Path' => '/',
|
||||
'PHPSESSID' => '6c951590e7a9359bcedde25cda73e43c',
|
||||
'Max-Age' => null,
|
||||
'Expires' => 'Sat, 26-Jul-2008 17:00:42 GMT',
|
||||
'Secure' => null,
|
||||
'Discard' => null,
|
||||
'Name' => 'ASIHTTPRequestTestCookie',
|
||||
'Value' => 'This+is+the+value',
|
||||
'HttpOnly' => false
|
||||
]
|
||||
],
|
||||
['', []],
|
||||
['foo', []],
|
||||
['; foo', []],
|
||||
[
|
||||
'foo="bar"',
|
||||
[
|
||||
'Name' => 'foo',
|
||||
'Value' => '"bar"',
|
||||
'Discard' => null,
|
||||
'Domain' => null,
|
||||
'Expires' => null,
|
||||
'Max-Age' => null,
|
||||
'Path' => '/',
|
||||
'Secure' => null,
|
||||
'HttpOnly' => false
|
||||
]
|
||||
],
|
||||
// Test setting a blank value for a cookie
|
||||
[[
|
||||
'foo=', 'foo =', 'foo =;', 'foo= ;', 'foo =', 'foo= '],
|
||||
[
|
||||
'Name' => 'foo',
|
||||
'Value' => '',
|
||||
'Discard' => null,
|
||||
'Domain' => null,
|
||||
'Expires' => null,
|
||||
'Max-Age' => null,
|
||||
'Path' => '/',
|
||||
'Secure' => null,
|
||||
'HttpOnly' => false
|
||||
]
|
||||
],
|
||||
// Test setting a value and removing quotes
|
||||
[[
|
||||
'foo=1', 'foo =1', 'foo =1;', 'foo=1 ;', 'foo =1', 'foo= 1', 'foo = 1 ;'],
|
||||
[
|
||||
'Name' => 'foo',
|
||||
'Value' => '1',
|
||||
'Discard' => null,
|
||||
'Domain' => null,
|
||||
'Expires' => null,
|
||||
'Max-Age' => null,
|
||||
'Path' => '/',
|
||||
'Secure' => null,
|
||||
'HttpOnly' => false
|
||||
]
|
||||
],
|
||||
// Some of the following tests are based on http://framework.zend.com/svn/framework/standard/trunk/tests/Zend/Http/CookieTest.php
|
||||
[
|
||||
'justacookie=foo; domain=example.com',
|
||||
[
|
||||
'Name' => 'justacookie',
|
||||
'Value' => 'foo',
|
||||
'Domain' => 'example.com',
|
||||
'Discard' => null,
|
||||
'Expires' => null,
|
||||
'Max-Age' => null,
|
||||
'Path' => '/',
|
||||
'Secure' => null,
|
||||
'HttpOnly' => false
|
||||
]
|
||||
],
|
||||
[
|
||||
'expires=tomorrow; secure; path=/Space Out/; expires=Tue, 21-Nov-2006 08:33:44 GMT; domain=.example.com',
|
||||
[
|
||||
'Name' => 'expires',
|
||||
'Value' => 'tomorrow',
|
||||
'Domain' => '.example.com',
|
||||
'Path' => '/Space Out/',
|
||||
'Expires' => 'Tue, 21-Nov-2006 08:33:44 GMT',
|
||||
'Discard' => null,
|
||||
'Secure' => true,
|
||||
'Max-Age' => null,
|
||||
'HttpOnly' => false
|
||||
]
|
||||
],
|
||||
[
|
||||
'domain=unittests; expires=Tue, 21-Nov-2006 08:33:44 GMT; domain=example.com; path=/some value/',
|
||||
[
|
||||
'Name' => 'domain',
|
||||
'Value' => 'unittests',
|
||||
'Domain' => 'example.com',
|
||||
'Path' => '/some value/',
|
||||
'Expires' => 'Tue, 21-Nov-2006 08:33:44 GMT',
|
||||
'Secure' => false,
|
||||
'Discard' => null,
|
||||
'Max-Age' => null,
|
||||
'HttpOnly' => false
|
||||
]
|
||||
],
|
||||
[
|
||||
'path=indexAction; path=/; domain=.foo.com; expires=Tue, 21-Nov-2006 08:33:44 GMT',
|
||||
[
|
||||
'Name' => 'path',
|
||||
'Value' => 'indexAction',
|
||||
'Domain' => '.foo.com',
|
||||
'Path' => '/',
|
||||
'Expires' => 'Tue, 21-Nov-2006 08:33:44 GMT',
|
||||
'Secure' => false,
|
||||
'Discard' => null,
|
||||
'Max-Age' => null,
|
||||
'HttpOnly' => false
|
||||
]
|
||||
],
|
||||
[
|
||||
'secure=sha1; secure; SECURE; domain=some.really.deep.domain.com; version=1; Max-Age=86400',
|
||||
[
|
||||
'Name' => 'secure',
|
||||
'Value' => 'sha1',
|
||||
'Domain' => 'some.really.deep.domain.com',
|
||||
'Path' => '/',
|
||||
'Secure' => true,
|
||||
'Discard' => null,
|
||||
'Expires' => time() + 86400,
|
||||
'Max-Age' => 86400,
|
||||
'HttpOnly' => false,
|
||||
'version' => '1'
|
||||
]
|
||||
],
|
||||
[
|
||||
'PHPSESSID=123456789+abcd%2Cef; secure; discard; domain=.localdomain; path=/foo/baz; expires=Tue, 21-Nov-2006 08:33:44 GMT;',
|
||||
[
|
||||
'Name' => 'PHPSESSID',
|
||||
'Value' => '123456789+abcd%2Cef',
|
||||
'Domain' => '.localdomain',
|
||||
'Path' => '/foo/baz',
|
||||
'Expires' => 'Tue, 21-Nov-2006 08:33:44 GMT',
|
||||
'Secure' => true,
|
||||
'Discard' => true,
|
||||
'Max-Age' => null,
|
||||
'HttpOnly' => false
|
||||
]
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider cookieParserDataProvider
|
||||
*/
|
||||
public function testParseCookie($cookie, $parsed)
|
||||
{
|
||||
foreach ((array) $cookie as $v) {
|
||||
$c = SetCookie::fromString($v);
|
||||
$p = $c->toArray();
|
||||
|
||||
if (isset($p['Expires'])) {
|
||||
// Remove expires values from the assertion if they are relatively equal
|
||||
if (abs($p['Expires'] != strtotime($parsed['Expires'])) < 40) {
|
||||
unset($p['Expires']);
|
||||
unset($parsed['Expires']);
|
||||
}
|
||||
}
|
||||
|
||||
if (!empty($parsed)) {
|
||||
foreach ($parsed as $key => $value) {
|
||||
self::assertEquals($parsed[$key], $p[$key], 'Comparing ' . $key . ' ' . var_export($value, true) . ' : ' . var_export($parsed, true) . ' | ' . var_export($p, true));
|
||||
}
|
||||
foreach ($p as $key => $value) {
|
||||
self::assertEquals($p[$key], $parsed[$key], 'Comparing ' . $key . ' ' . var_export($value, true) . ' : ' . var_export($parsed, true) . ' | ' . var_export($p, true));
|
||||
}
|
||||
} else {
|
||||
self::assertSame([
|
||||
'Name' => null,
|
||||
'Value' => null,
|
||||
'Domain' => null,
|
||||
'Path' => '/',
|
||||
'Max-Age' => null,
|
||||
'Expires' => null,
|
||||
'Secure' => false,
|
||||
'Discard' => false,
|
||||
'HttpOnly' => false,
|
||||
], $p);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides the data for testing isExpired
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function isExpiredProvider()
|
||||
{
|
||||
return [
|
||||
[
|
||||
'FOO=bar; expires=Thu, 01 Jan 1970 00:00:00 GMT;',
|
||||
true,
|
||||
],
|
||||
[
|
||||
'FOO=bar; expires=Thu, 01 Jan 1970 00:00:01 GMT;',
|
||||
true,
|
||||
],
|
||||
[
|
||||
'FOO=bar; expires=' . date(\DateTime::RFC1123, time()+10) . ';',
|
||||
false,
|
||||
],
|
||||
[
|
||||
'FOO=bar; expires=' . date(\DateTime::RFC1123, time()-10) . ';',
|
||||
true,
|
||||
],
|
||||
[
|
||||
'FOO=bar;',
|
||||
false,
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider isExpiredProvider
|
||||
*/
|
||||
public function testIsExpired($cookie, $expired)
|
||||
{
|
||||
self::assertSame(
|
||||
$expired,
|
||||
SetCookie::fromString($cookie)->isExpired()
|
||||
);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,25 @@
|
||||
<?php
|
||||
namespace GuzzleHttp\Tests\Exception;
|
||||
|
||||
use GuzzleHttp\Exception\ConnectException;
|
||||
use GuzzleHttp\Psr7\Request;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/**
|
||||
* @covers \GuzzleHttp\Exception\ConnectException
|
||||
*/
|
||||
class ConnectExceptionTest extends TestCase
|
||||
{
|
||||
public function testHasNoResponse()
|
||||
{
|
||||
$req = new Request('GET', '/');
|
||||
$prev = new \Exception();
|
||||
$e = new ConnectException('foo', $req, $prev, ['foo' => 'bar']);
|
||||
self::assertSame($req, $e->getRequest());
|
||||
self::assertNull($e->getResponse());
|
||||
self::assertFalse($e->hasResponse());
|
||||
self::assertSame('foo', $e->getMessage());
|
||||
self::assertSame('bar', $e->getHandlerContext()['foo']);
|
||||
self::assertSame($prev, $e->getPrevious());
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,195 @@
|
||||
<?php
|
||||
namespace GuzzleHttp\Tests\Exception;
|
||||
|
||||
use GuzzleHttp\Exception\RequestException;
|
||||
use GuzzleHttp\Psr7\Request;
|
||||
use GuzzleHttp\Psr7\Response;
|
||||
use GuzzleHttp\Psr7\Stream;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/**
|
||||
* @covers \GuzzleHttp\Exception\RequestException
|
||||
*/
|
||||
class RequestExceptionTest extends TestCase
|
||||
{
|
||||
public function testHasRequestAndResponse()
|
||||
{
|
||||
$req = new Request('GET', '/');
|
||||
$res = new Response(200);
|
||||
$e = new RequestException('foo', $req, $res);
|
||||
self::assertSame($req, $e->getRequest());
|
||||
self::assertSame($res, $e->getResponse());
|
||||
self::assertTrue($e->hasResponse());
|
||||
self::assertSame('foo', $e->getMessage());
|
||||
}
|
||||
|
||||
public function testCreatesGenerateException()
|
||||
{
|
||||
$e = RequestException::create(new Request('GET', '/'));
|
||||
self::assertSame('Error completing request', $e->getMessage());
|
||||
self::assertInstanceOf('GuzzleHttp\Exception\RequestException', $e);
|
||||
}
|
||||
|
||||
public function testCreatesClientErrorResponseException()
|
||||
{
|
||||
$e = RequestException::create(new Request('GET', '/'), new Response(400));
|
||||
self::assertContains(
|
||||
'GET /',
|
||||
$e->getMessage()
|
||||
);
|
||||
self::assertContains(
|
||||
'400 Bad Request',
|
||||
$e->getMessage()
|
||||
);
|
||||
self::assertInstanceOf('GuzzleHttp\Exception\ClientException', $e);
|
||||
}
|
||||
|
||||
public function testCreatesServerErrorResponseException()
|
||||
{
|
||||
$e = RequestException::create(new Request('GET', '/'), new Response(500));
|
||||
self::assertContains(
|
||||
'GET /',
|
||||
$e->getMessage()
|
||||
);
|
||||
self::assertContains(
|
||||
'500 Internal Server Error',
|
||||
$e->getMessage()
|
||||
);
|
||||
self::assertInstanceOf('GuzzleHttp\Exception\ServerException', $e);
|
||||
}
|
||||
|
||||
public function testCreatesGenericErrorResponseException()
|
||||
{
|
||||
$e = RequestException::create(new Request('GET', '/'), new Response(300));
|
||||
self::assertContains(
|
||||
'GET /',
|
||||
$e->getMessage()
|
||||
);
|
||||
self::assertContains(
|
||||
'300 ',
|
||||
$e->getMessage()
|
||||
);
|
||||
self::assertInstanceOf('GuzzleHttp\Exception\RequestException', $e);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException InvalidArgumentException
|
||||
* @expectedExceptionMessage Status code must be an integer value between 1xx and 5xx.
|
||||
*/
|
||||
public function testThrowsInvalidArgumentExceptionOnOutOfBoundsResponseCode()
|
||||
{
|
||||
throw RequestException::create(new Request('GET', '/'), new Response(600));
|
||||
}
|
||||
|
||||
public function dataPrintableResponses()
|
||||
{
|
||||
return [
|
||||
['You broke the test!'],
|
||||
['<h1>zlomený zkouška</h1>'],
|
||||
['{"tester": "Philépe Gonzalez"}'],
|
||||
["<xml>\n\t<text>Your friendly test</text>\n</xml>"],
|
||||
['document.body.write("here comes a test");'],
|
||||
["body:before {\n\tcontent: 'test style';\n}"],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dataPrintableResponses
|
||||
*/
|
||||
public function testCreatesExceptionWithPrintableBodySummary($content)
|
||||
{
|
||||
$response = new Response(
|
||||
500,
|
||||
[],
|
||||
$content
|
||||
);
|
||||
$e = RequestException::create(new Request('GET', '/'), $response);
|
||||
self::assertContains(
|
||||
$content,
|
||||
$e->getMessage()
|
||||
);
|
||||
self::assertInstanceOf('GuzzleHttp\Exception\RequestException', $e);
|
||||
}
|
||||
|
||||
public function testCreatesExceptionWithTruncatedSummary()
|
||||
{
|
||||
$content = str_repeat('+', 121);
|
||||
$response = new Response(500, [], $content);
|
||||
$e = RequestException::create(new Request('GET', '/'), $response);
|
||||
$expected = str_repeat('+', 120) . ' (truncated...)';
|
||||
self::assertContains($expected, $e->getMessage());
|
||||
}
|
||||
|
||||
public function testExceptionMessageIgnoresEmptyBody()
|
||||
{
|
||||
$e = RequestException::create(new Request('GET', '/'), new Response(500));
|
||||
self::assertStringEndsWith('response', $e->getMessage());
|
||||
}
|
||||
|
||||
public function testHasStatusCodeAsExceptionCode()
|
||||
{
|
||||
$e = RequestException::create(new Request('GET', '/'), new Response(442));
|
||||
self::assertSame(442, $e->getCode());
|
||||
}
|
||||
|
||||
public function testWrapsRequestExceptions()
|
||||
{
|
||||
$e = new \Exception('foo');
|
||||
$r = new Request('GET', 'http://www.oo.com');
|
||||
$ex = RequestException::wrapException($r, $e);
|
||||
self::assertInstanceOf('GuzzleHttp\Exception\RequestException', $ex);
|
||||
self::assertSame($e, $ex->getPrevious());
|
||||
}
|
||||
|
||||
public function testDoesNotWrapExistingRequestExceptions()
|
||||
{
|
||||
$r = new Request('GET', 'http://www.oo.com');
|
||||
$e = new RequestException('foo', $r);
|
||||
$e2 = RequestException::wrapException($r, $e);
|
||||
self::assertSame($e, $e2);
|
||||
}
|
||||
|
||||
public function testCanProvideHandlerContext()
|
||||
{
|
||||
$r = new Request('GET', 'http://www.oo.com');
|
||||
$e = new RequestException('foo', $r, null, null, ['bar' => 'baz']);
|
||||
self::assertSame(['bar' => 'baz'], $e->getHandlerContext());
|
||||
}
|
||||
|
||||
public function testObfuscateUrlWithUsername()
|
||||
{
|
||||
$r = new Request('GET', 'http://username@www.oo.com');
|
||||
$e = RequestException::create($r, new Response(500));
|
||||
self::assertContains('http://username@www.oo.com', $e->getMessage());
|
||||
}
|
||||
|
||||
public function testObfuscateUrlWithUsernameAndPassword()
|
||||
{
|
||||
$r = new Request('GET', 'http://user:password@www.oo.com');
|
||||
$e = RequestException::create($r, new Response(500));
|
||||
self::assertContains('http://user:***@www.oo.com', $e->getMessage());
|
||||
}
|
||||
|
||||
public function testGetResponseBodySummaryOfNonReadableStream()
|
||||
{
|
||||
self::assertNull(RequestException::getResponseBodySummary(new Response(500, [], new ReadSeekOnlyStream())));
|
||||
}
|
||||
}
|
||||
|
||||
final class ReadSeekOnlyStream extends Stream
|
||||
{
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct(fopen('php://memory', 'wb'));
|
||||
}
|
||||
|
||||
public function isSeekable()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
public function isReadable()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,17 @@
|
||||
<?php
|
||||
namespace GuzzleHttp\Tests\Exception;
|
||||
|
||||
use GuzzleHttp\Exception\SeekException;
|
||||
use GuzzleHttp\Psr7;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class SeekExceptionTest extends TestCase
|
||||
{
|
||||
public function testHasStream()
|
||||
{
|
||||
$s = Psr7\stream_for('foo');
|
||||
$e = new SeekException($s, 10);
|
||||
self::assertSame($s, $e->getStream());
|
||||
self::assertContains('10', $e->getMessage());
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,770 @@
|
||||
<?php
|
||||
namespace GuzzleHttp\Test\Handler;
|
||||
|
||||
use GuzzleHttp\Handler;
|
||||
use GuzzleHttp\Handler\CurlFactory;
|
||||
use GuzzleHttp\Handler\EasyHandle;
|
||||
use GuzzleHttp\Psr7;
|
||||
use GuzzleHttp\Tests\Server;
|
||||
use GuzzleHttp\TransferStats;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
/**
|
||||
* @covers \GuzzleHttp\Handler\CurlFactory
|
||||
*/
|
||||
class CurlFactoryTest extends TestCase
|
||||
{
|
||||
public static function setUpBeforeClass()
|
||||
{
|
||||
$_SERVER['curl_test'] = true;
|
||||
unset($_SERVER['_curl']);
|
||||
}
|
||||
|
||||
public static function tearDownAfterClass()
|
||||
{
|
||||
unset($_SERVER['_curl'], $_SERVER['curl_test']);
|
||||
}
|
||||
|
||||
public function testCreatesCurlHandle()
|
||||
{
|
||||
Server::flush();
|
||||
Server::enqueue([
|
||||
new Psr7\Response(200, [
|
||||
'Foo' => 'Bar',
|
||||
'Baz' => 'bam',
|
||||
'Content-Length' => 2,
|
||||
], 'hi')
|
||||
]);
|
||||
$stream = Psr7\stream_for();
|
||||
$request = new Psr7\Request('PUT', Server::$url, [
|
||||
'Hi' => ' 123',
|
||||
'Content-Length' => '7'
|
||||
], 'testing');
|
||||
$f = new Handler\CurlFactory(3);
|
||||
$result = $f->create($request, ['sink' => $stream]);
|
||||
self::assertInstanceOf(EasyHandle::class, $result);
|
||||
self::assertInternalType('resource', $result->handle);
|
||||
self::assertInternalType('array', $result->headers);
|
||||
self::assertSame($stream, $result->sink);
|
||||
curl_close($result->handle);
|
||||
self::assertSame('PUT', $_SERVER['_curl'][CURLOPT_CUSTOMREQUEST]);
|
||||
self::assertSame(
|
||||
'http://127.0.0.1:8126/',
|
||||
$_SERVER['_curl'][CURLOPT_URL]
|
||||
);
|
||||
// Sends via post fields when the request is small enough
|
||||
self::assertSame('testing', $_SERVER['_curl'][CURLOPT_POSTFIELDS]);
|
||||
self::assertEquals(0, $_SERVER['_curl'][CURLOPT_RETURNTRANSFER]);
|
||||
self::assertEquals(0, $_SERVER['_curl'][CURLOPT_HEADER]);
|
||||
self::assertSame(150, $_SERVER['_curl'][CURLOPT_CONNECTTIMEOUT]);
|
||||
self::assertInstanceOf('Closure', $_SERVER['_curl'][CURLOPT_HEADERFUNCTION]);
|
||||
if (defined('CURLOPT_PROTOCOLS')) {
|
||||
self::assertSame(
|
||||
CURLPROTO_HTTP | CURLPROTO_HTTPS,
|
||||
$_SERVER['_curl'][CURLOPT_PROTOCOLS]
|
||||
);
|
||||
}
|
||||
self::assertContains('Expect:', $_SERVER['_curl'][CURLOPT_HTTPHEADER]);
|
||||
self::assertContains('Accept:', $_SERVER['_curl'][CURLOPT_HTTPHEADER]);
|
||||
self::assertContains('Content-Type:', $_SERVER['_curl'][CURLOPT_HTTPHEADER]);
|
||||
self::assertContains('Hi: 123', $_SERVER['_curl'][CURLOPT_HTTPHEADER]);
|
||||
self::assertContains('Host: 127.0.0.1:8126', $_SERVER['_curl'][CURLOPT_HTTPHEADER]);
|
||||
}
|
||||
|
||||
public function testSendsHeadRequests()
|
||||
{
|
||||
Server::flush();
|
||||
Server::enqueue([new Psr7\Response()]);
|
||||
$a = new Handler\CurlMultiHandler();
|
||||
$response = $a(new Psr7\Request('HEAD', Server::$url), []);
|
||||
$response->wait();
|
||||
self::assertEquals(true, $_SERVER['_curl'][CURLOPT_NOBODY]);
|
||||
$checks = [CURLOPT_WRITEFUNCTION, CURLOPT_READFUNCTION, CURLOPT_INFILE];
|
||||
foreach ($checks as $check) {
|
||||
self::assertArrayNotHasKey($check, $_SERVER['_curl']);
|
||||
}
|
||||
self::assertEquals('HEAD', Server::received()[0]->getMethod());
|
||||
}
|
||||
|
||||
public function testCanAddCustomCurlOptions()
|
||||
{
|
||||
Server::flush();
|
||||
Server::enqueue([new Psr7\Response()]);
|
||||
$a = new Handler\CurlMultiHandler();
|
||||
$req = new Psr7\Request('GET', Server::$url);
|
||||
$a($req, ['curl' => [CURLOPT_LOW_SPEED_LIMIT => 10]]);
|
||||
self::assertEquals(10, $_SERVER['_curl'][CURLOPT_LOW_SPEED_LIMIT]);
|
||||
}
|
||||
|
||||
public function testCanChangeCurlOptions()
|
||||
{
|
||||
Server::flush();
|
||||
Server::enqueue([new Psr7\Response()]);
|
||||
$a = new Handler\CurlMultiHandler();
|
||||
$req = new Psr7\Request('GET', Server::$url);
|
||||
$a($req, ['curl' => [CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_0]]);
|
||||
self::assertEquals(CURL_HTTP_VERSION_1_0, $_SERVER['_curl'][CURLOPT_HTTP_VERSION]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \InvalidArgumentException
|
||||
* @expectedExceptionMessage SSL CA bundle not found: /does/not/exist
|
||||
*/
|
||||
public function testValidatesVerify()
|
||||
{
|
||||
$f = new Handler\CurlFactory(3);
|
||||
$f->create(new Psr7\Request('GET', Server::$url), ['verify' => '/does/not/exist']);
|
||||
}
|
||||
|
||||
public function testCanSetVerifyToFile()
|
||||
{
|
||||
$f = new Handler\CurlFactory(3);
|
||||
$f->create(new Psr7\Request('GET', 'http://foo.com'), ['verify' => __FILE__]);
|
||||
self::assertEquals(__FILE__, $_SERVER['_curl'][CURLOPT_CAINFO]);
|
||||
self::assertEquals(2, $_SERVER['_curl'][CURLOPT_SSL_VERIFYHOST]);
|
||||
self::assertEquals(true, $_SERVER['_curl'][CURLOPT_SSL_VERIFYPEER]);
|
||||
}
|
||||
|
||||
public function testCanSetVerifyToDir()
|
||||
{
|
||||
$f = new Handler\CurlFactory(3);
|
||||
$f->create(new Psr7\Request('GET', 'http://foo.com'), ['verify' => __DIR__]);
|
||||
self::assertEquals(__DIR__, $_SERVER['_curl'][CURLOPT_CAPATH]);
|
||||
self::assertEquals(2, $_SERVER['_curl'][CURLOPT_SSL_VERIFYHOST]);
|
||||
self::assertEquals(true, $_SERVER['_curl'][CURLOPT_SSL_VERIFYPEER]);
|
||||
}
|
||||
|
||||
public function testAddsVerifyAsTrue()
|
||||
{
|
||||
$f = new Handler\CurlFactory(3);
|
||||
$f->create(new Psr7\Request('GET', Server::$url), ['verify' => true]);
|
||||
self::assertEquals(2, $_SERVER['_curl'][CURLOPT_SSL_VERIFYHOST]);
|
||||
self::assertEquals(true, $_SERVER['_curl'][CURLOPT_SSL_VERIFYPEER]);
|
||||
self::assertArrayNotHasKey(CURLOPT_CAINFO, $_SERVER['_curl']);
|
||||
}
|
||||
|
||||
public function testCanDisableVerify()
|
||||
{
|
||||
$f = new Handler\CurlFactory(3);
|
||||
$f->create(new Psr7\Request('GET', Server::$url), ['verify' => false]);
|
||||
self::assertEquals(0, $_SERVER['_curl'][CURLOPT_SSL_VERIFYHOST]);
|
||||
self::assertEquals(false, $_SERVER['_curl'][CURLOPT_SSL_VERIFYPEER]);
|
||||
}
|
||||
|
||||
public function testAddsProxy()
|
||||
{
|
||||
$f = new Handler\CurlFactory(3);
|
||||
$f->create(new Psr7\Request('GET', Server::$url), ['proxy' => 'http://bar.com']);
|
||||
self::assertEquals('http://bar.com', $_SERVER['_curl'][CURLOPT_PROXY]);
|
||||
}
|
||||
|
||||
public function testAddsViaScheme()
|
||||
{
|
||||
$f = new Handler\CurlFactory(3);
|
||||
$f->create(new Psr7\Request('GET', Server::$url), [
|
||||
'proxy' => ['http' => 'http://bar.com', 'https' => 'https://t'],
|
||||
]);
|
||||
self::assertEquals('http://bar.com', $_SERVER['_curl'][CURLOPT_PROXY]);
|
||||
$this->checkNoProxyForHost('http://test.test.com', ['test.test.com'], false);
|
||||
$this->checkNoProxyForHost('http://test.test.com', ['.test.com'], false);
|
||||
$this->checkNoProxyForHost('http://test.test.com', ['*.test.com'], true);
|
||||
$this->checkNoProxyForHost('http://test.test.com', ['*'], false);
|
||||
$this->checkNoProxyForHost('http://127.0.0.1', ['127.0.0.*'], true);
|
||||
}
|
||||
|
||||
private function checkNoProxyForHost($url, $noProxy, $assertUseProxy)
|
||||
{
|
||||
$f = new Handler\CurlFactory(3);
|
||||
$f->create(new Psr7\Request('GET', $url), [
|
||||
'proxy' => [
|
||||
'http' => 'http://bar.com',
|
||||
'https' => 'https://t',
|
||||
'no' => $noProxy
|
||||
],
|
||||
]);
|
||||
if ($assertUseProxy) {
|
||||
self::assertArrayHasKey(CURLOPT_PROXY, $_SERVER['_curl']);
|
||||
} else {
|
||||
self::assertArrayNotHasKey(CURLOPT_PROXY, $_SERVER['_curl']);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @expectedException \InvalidArgumentException
|
||||
* @expectedExceptionMessage SSL private key not found: /does/not/exist
|
||||
*/
|
||||
public function testValidatesSslKey()
|
||||
{
|
||||
$f = new Handler\CurlFactory(3);
|
||||
$f->create(new Psr7\Request('GET', Server::$url), ['ssl_key' => '/does/not/exist']);
|
||||
}
|
||||
|
||||
public function testAddsSslKey()
|
||||
{
|
||||
$f = new Handler\CurlFactory(3);
|
||||
$f->create(new Psr7\Request('GET', Server::$url), ['ssl_key' => __FILE__]);
|
||||
self::assertEquals(__FILE__, $_SERVER['_curl'][CURLOPT_SSLKEY]);
|
||||
}
|
||||
|
||||
public function testAddsSslKeyWithPassword()
|
||||
{
|
||||
$f = new Handler\CurlFactory(3);
|
||||
$f->create(new Psr7\Request('GET', Server::$url), ['ssl_key' => [__FILE__, 'test']]);
|
||||
self::assertEquals(__FILE__, $_SERVER['_curl'][CURLOPT_SSLKEY]);
|
||||
self::assertEquals('test', $_SERVER['_curl'][CURLOPT_SSLKEYPASSWD]);
|
||||
}
|
||||
|
||||
public function testAddsSslKeyWhenUsingArraySyntaxButNoPassword()
|
||||
{
|
||||
$f = new Handler\CurlFactory(3);
|
||||
$f->create(new Psr7\Request('GET', Server::$url), ['ssl_key' => [__FILE__]]);
|
||||
|
||||
self::assertEquals(__FILE__, $_SERVER['_curl'][CURLOPT_SSLKEY]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \InvalidArgumentException
|
||||
* @expectedExceptionMessage SSL certificate not found: /does/not/exist
|
||||
*/
|
||||
public function testValidatesCert()
|
||||
{
|
||||
$f = new Handler\CurlFactory(3);
|
||||
$f->create(new Psr7\Request('GET', Server::$url), ['cert' => '/does/not/exist']);
|
||||
}
|
||||
|
||||
public function testAddsCert()
|
||||
{
|
||||
$f = new Handler\CurlFactory(3);
|
||||
$f->create(new Psr7\Request('GET', Server::$url), ['cert' => __FILE__]);
|
||||
self::assertEquals(__FILE__, $_SERVER['_curl'][CURLOPT_SSLCERT]);
|
||||
}
|
||||
|
||||
public function testAddsCertWithPassword()
|
||||
{
|
||||
$f = new Handler\CurlFactory(3);
|
||||
$f->create(new Psr7\Request('GET', Server::$url), ['cert' => [__FILE__, 'test']]);
|
||||
self::assertEquals(__FILE__, $_SERVER['_curl'][CURLOPT_SSLCERT]);
|
||||
self::assertEquals('test', $_SERVER['_curl'][CURLOPT_SSLCERTPASSWD]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \InvalidArgumentException
|
||||
* @expectedExceptionMessage progress client option must be callable
|
||||
*/
|
||||
public function testValidatesProgress()
|
||||
{
|
||||
$f = new Handler\CurlFactory(3);
|
||||
$f->create(new Psr7\Request('GET', Server::$url), ['progress' => 'foo']);
|
||||
}
|
||||
|
||||
public function testEmitsDebugInfoToStream()
|
||||
{
|
||||
$res = fopen('php://memory', 'r+');
|
||||
Server::flush();
|
||||
Server::enqueue([new Psr7\Response()]);
|
||||
$a = new Handler\CurlMultiHandler();
|
||||
$response = $a(new Psr7\Request('HEAD', Server::$url), ['debug' => $res]);
|
||||
$response->wait();
|
||||
rewind($res);
|
||||
$output = str_replace("\r", '', stream_get_contents($res));
|
||||
self::assertContains("> HEAD / HTTP/1.1", $output);
|
||||
self::assertContains("< HTTP/1.1 200", $output);
|
||||
fclose($res);
|
||||
}
|
||||
|
||||
public function testEmitsProgressToFunction()
|
||||
{
|
||||
Server::flush();
|
||||
Server::enqueue([new Psr7\Response()]);
|
||||
$a = new Handler\CurlMultiHandler();
|
||||
$called = [];
|
||||
$request = new Psr7\Request('HEAD', Server::$url);
|
||||
$response = $a($request, [
|
||||
'progress' => function () use (&$called) {
|
||||
$called[] = func_get_args();
|
||||
},
|
||||
]);
|
||||
$response->wait();
|
||||
self::assertNotEmpty($called);
|
||||
foreach ($called as $call) {
|
||||
self::assertCount(4, $call);
|
||||
}
|
||||
}
|
||||
|
||||
private function addDecodeResponse($withEncoding = true)
|
||||
{
|
||||
$content = gzencode('test');
|
||||
$headers = ['Content-Length' => strlen($content)];
|
||||
if ($withEncoding) {
|
||||
$headers['Content-Encoding'] = 'gzip';
|
||||
}
|
||||
$response = new Psr7\Response(200, $headers, $content);
|
||||
Server::flush();
|
||||
Server::enqueue([$response]);
|
||||
return $content;
|
||||
}
|
||||
|
||||
public function testDecodesGzippedResponses()
|
||||
{
|
||||
$this->addDecodeResponse();
|
||||
$handler = new Handler\CurlMultiHandler();
|
||||
$request = new Psr7\Request('GET', Server::$url);
|
||||
$response = $handler($request, ['decode_content' => true]);
|
||||
$response = $response->wait();
|
||||
self::assertEquals('test', (string) $response->getBody());
|
||||
self::assertEquals('', $_SERVER['_curl'][CURLOPT_ENCODING]);
|
||||
$sent = Server::received()[0];
|
||||
self::assertFalse($sent->hasHeader('Accept-Encoding'));
|
||||
}
|
||||
|
||||
public function testReportsOriginalSizeAndContentEncodingAfterDecoding()
|
||||
{
|
||||
$this->addDecodeResponse();
|
||||
$handler = new Handler\CurlMultiHandler();
|
||||
$request = new Psr7\Request('GET', Server::$url);
|
||||
$response = $handler($request, ['decode_content' => true]);
|
||||
$response = $response->wait();
|
||||
self::assertSame(
|
||||
'gzip',
|
||||
$response->getHeaderLine('x-encoded-content-encoding')
|
||||
);
|
||||
self::assertSame(
|
||||
strlen(gzencode('test')),
|
||||
(int) $response->getHeaderLine('x-encoded-content-length')
|
||||
);
|
||||
}
|
||||
|
||||
public function testDecodesGzippedResponsesWithHeader()
|
||||
{
|
||||
$this->addDecodeResponse();
|
||||
$handler = new Handler\CurlMultiHandler();
|
||||
$request = new Psr7\Request('GET', Server::$url, ['Accept-Encoding' => 'gzip']);
|
||||
$response = $handler($request, ['decode_content' => true]);
|
||||
$response = $response->wait();
|
||||
self::assertEquals('gzip', $_SERVER['_curl'][CURLOPT_ENCODING]);
|
||||
$sent = Server::received()[0];
|
||||
self::assertEquals('gzip', $sent->getHeaderLine('Accept-Encoding'));
|
||||
self::assertEquals('test', (string) $response->getBody());
|
||||
self::assertFalse($response->hasHeader('content-encoding'));
|
||||
self::assertTrue(
|
||||
!$response->hasHeader('content-length') ||
|
||||
$response->getHeaderLine('content-length') == $response->getBody()->getSize()
|
||||
);
|
||||
}
|
||||
|
||||
public function testDoesNotForceDecode()
|
||||
{
|
||||
$content = $this->addDecodeResponse();
|
||||
$handler = new Handler\CurlMultiHandler();
|
||||
$request = new Psr7\Request('GET', Server::$url);
|
||||
$response = $handler($request, ['decode_content' => false]);
|
||||
$response = $response->wait();
|
||||
$sent = Server::received()[0];
|
||||
self::assertFalse($sent->hasHeader('Accept-Encoding'));
|
||||
self::assertEquals($content, (string) $response->getBody());
|
||||
}
|
||||
|
||||
public function testProtocolVersion()
|
||||
{
|
||||
Server::flush();
|
||||
Server::enqueue([new Psr7\Response()]);
|
||||
$a = new Handler\CurlMultiHandler();
|
||||
$request = new Psr7\Request('GET', Server::$url, [], null, '1.0');
|
||||
$a($request, []);
|
||||
self::assertEquals(CURL_HTTP_VERSION_1_0, $_SERVER['_curl'][CURLOPT_HTTP_VERSION]);
|
||||
}
|
||||
|
||||
public function testSavesToStream()
|
||||
{
|
||||
$stream = fopen('php://memory', 'r+');
|
||||
$this->addDecodeResponse();
|
||||
$handler = new Handler\CurlMultiHandler();
|
||||
$request = new Psr7\Request('GET', Server::$url);
|
||||
$response = $handler($request, [
|
||||
'decode_content' => true,
|
||||
'sink' => $stream,
|
||||
]);
|
||||
$response->wait();
|
||||
rewind($stream);
|
||||
self::assertEquals('test', stream_get_contents($stream));
|
||||
}
|
||||
|
||||
public function testSavesToGuzzleStream()
|
||||
{
|
||||
$stream = Psr7\stream_for();
|
||||
$this->addDecodeResponse();
|
||||
$handler = new Handler\CurlMultiHandler();
|
||||
$request = new Psr7\Request('GET', Server::$url);
|
||||
$response = $handler($request, [
|
||||
'decode_content' => true,
|
||||
'sink' => $stream,
|
||||
]);
|
||||
$response->wait();
|
||||
self::assertEquals('test', (string) $stream);
|
||||
}
|
||||
|
||||
public function testSavesToFileOnDisk()
|
||||
{
|
||||
$tmpfile = tempnam(sys_get_temp_dir(), 'testfile');
|
||||
$this->addDecodeResponse();
|
||||
$handler = new Handler\CurlMultiHandler();
|
||||
$request = new Psr7\Request('GET', Server::$url);
|
||||
$response = $handler($request, [
|
||||
'decode_content' => true,
|
||||
'sink' => $tmpfile,
|
||||
]);
|
||||
$response->wait();
|
||||
self::assertStringEqualsFile($tmpfile, 'test');
|
||||
unlink($tmpfile);
|
||||
}
|
||||
|
||||
public function testDoesNotAddMultipleContentLengthHeaders()
|
||||
{
|
||||
$this->addDecodeResponse();
|
||||
$handler = new Handler\CurlMultiHandler();
|
||||
$request = new Psr7\Request('PUT', Server::$url, ['Content-Length' => 3], 'foo');
|
||||
$response = $handler($request, []);
|
||||
$response->wait();
|
||||
$sent = Server::received()[0];
|
||||
self::assertEquals(3, $sent->getHeaderLine('Content-Length'));
|
||||
self::assertFalse($sent->hasHeader('Transfer-Encoding'));
|
||||
self::assertEquals('foo', (string) $sent->getBody());
|
||||
}
|
||||
|
||||
public function testSendsPostWithNoBodyOrDefaultContentType()
|
||||
{
|
||||
Server::flush();
|
||||
Server::enqueue([new Psr7\Response()]);
|
||||
$handler = new Handler\CurlMultiHandler();
|
||||
$request = new Psr7\Request('POST', Server::$url);
|
||||
$response = $handler($request, []);
|
||||
$response->wait();
|
||||
$received = Server::received()[0];
|
||||
self::assertEquals('POST', $received->getMethod());
|
||||
self::assertFalse($received->hasHeader('content-type'));
|
||||
self::assertSame('0', $received->getHeaderLine('content-length'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \GuzzleHttp\Exception\RequestException
|
||||
* @expectedExceptionMessage but attempting to rewind the request body failed
|
||||
*/
|
||||
public function testFailsWhenCannotRewindRetryAfterNoResponse()
|
||||
{
|
||||
$factory = new Handler\CurlFactory(1);
|
||||
$stream = Psr7\stream_for('abc');
|
||||
$stream->read(1);
|
||||
$stream = new Psr7\NoSeekStream($stream);
|
||||
$request = new Psr7\Request('PUT', Server::$url, [], $stream);
|
||||
$fn = function ($request, $options) use (&$fn, $factory) {
|
||||
$easy = $factory->create($request, $options);
|
||||
return Handler\CurlFactory::finish($fn, $easy, $factory);
|
||||
};
|
||||
$fn($request, [])->wait();
|
||||
}
|
||||
|
||||
public function testRetriesWhenBodyCanBeRewound()
|
||||
{
|
||||
$callHandler = $called = false;
|
||||
|
||||
$fn = function ($r, $options) use (&$callHandler) {
|
||||
$callHandler = true;
|
||||
return \GuzzleHttp\Promise\promise_for(new Psr7\Response());
|
||||
};
|
||||
|
||||
$bd = Psr7\FnStream::decorate(Psr7\stream_for('test'), [
|
||||
'tell' => function () {
|
||||
return 1;
|
||||
},
|
||||
'rewind' => function () use (&$called) {
|
||||
$called = true;
|
||||
}
|
||||
]);
|
||||
|
||||
$factory = new Handler\CurlFactory(1);
|
||||
$req = new Psr7\Request('PUT', Server::$url, [], $bd);
|
||||
$easy = $factory->create($req, []);
|
||||
$res = Handler\CurlFactory::finish($fn, $easy, $factory);
|
||||
$res = $res->wait();
|
||||
self::assertTrue($callHandler);
|
||||
self::assertTrue($called);
|
||||
self::assertEquals('200', $res->getStatusCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \GuzzleHttp\Exception\RequestException
|
||||
* @expectedExceptionMessage The cURL request was retried 3 times
|
||||
*/
|
||||
public function testFailsWhenRetryMoreThanThreeTimes()
|
||||
{
|
||||
$factory = new Handler\CurlFactory(1);
|
||||
$call = 0;
|
||||
$fn = function ($request, $options) use (&$mock, &$call, $factory) {
|
||||
$call++;
|
||||
$easy = $factory->create($request, $options);
|
||||
return Handler\CurlFactory::finish($mock, $easy, $factory);
|
||||
};
|
||||
$mock = new Handler\MockHandler([$fn, $fn, $fn]);
|
||||
$p = $mock(new Psr7\Request('PUT', Server::$url, [], 'test'), []);
|
||||
$p->wait(false);
|
||||
self::assertEquals(3, $call);
|
||||
$p->wait(true);
|
||||
}
|
||||
|
||||
public function testHandles100Continue()
|
||||
{
|
||||
Server::flush();
|
||||
Server::enqueue([
|
||||
new Psr7\Response(200, ['Test' => 'Hello', 'Content-Length' => 4], 'test'),
|
||||
]);
|
||||
$request = new Psr7\Request('PUT', Server::$url, [
|
||||
'Expect' => '100-Continue'
|
||||
], 'test');
|
||||
$handler = new Handler\CurlMultiHandler();
|
||||
$response = $handler($request, [])->wait();
|
||||
self::assertSame(200, $response->getStatusCode());
|
||||
self::assertSame('OK', $response->getReasonPhrase());
|
||||
self::assertSame('Hello', $response->getHeaderLine('Test'));
|
||||
self::assertSame('4', $response->getHeaderLine('Content-Length'));
|
||||
self::assertSame('test', (string) $response->getBody());
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \GuzzleHttp\Exception\ConnectException
|
||||
*/
|
||||
public function testCreatesConnectException()
|
||||
{
|
||||
$m = new \ReflectionMethod(CurlFactory::class, 'finishError');
|
||||
$m->setAccessible(true);
|
||||
$factory = new Handler\CurlFactory(1);
|
||||
$easy = $factory->create(new Psr7\Request('GET', Server::$url), []);
|
||||
$easy->errno = CURLE_COULDNT_CONNECT;
|
||||
$response = $m->invoke(
|
||||
null,
|
||||
function () {
|
||||
},
|
||||
$easy,
|
||||
$factory
|
||||
);
|
||||
$response->wait();
|
||||
}
|
||||
|
||||
public function testAddsTimeouts()
|
||||
{
|
||||
$f = new Handler\CurlFactory(3);
|
||||
$f->create(new Psr7\Request('GET', Server::$url), [
|
||||
'timeout' => 0.1,
|
||||
'connect_timeout' => 0.2
|
||||
]);
|
||||
self::assertEquals(100, $_SERVER['_curl'][CURLOPT_TIMEOUT_MS]);
|
||||
self::assertEquals(200, $_SERVER['_curl'][CURLOPT_CONNECTTIMEOUT_MS]);
|
||||
}
|
||||
|
||||
public function testAddsStreamingBody()
|
||||
{
|
||||
$f = new Handler\CurlFactory(3);
|
||||
$bd = Psr7\FnStream::decorate(Psr7\stream_for('foo'), [
|
||||
'getSize' => function () {
|
||||
return null;
|
||||
}
|
||||
]);
|
||||
$request = new Psr7\Request('PUT', Server::$url, [], $bd);
|
||||
$f->create($request, []);
|
||||
self::assertEquals(1, $_SERVER['_curl'][CURLOPT_UPLOAD]);
|
||||
self::assertInternalType('callable', $_SERVER['_curl'][CURLOPT_READFUNCTION]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \RuntimeException
|
||||
* @expectedExceptionMessage Directory /does/not/exist/so does not exist for sink value of /does/not/exist/so/error.txt
|
||||
*/
|
||||
public function testEnsuresDirExistsBeforeThrowingWarning()
|
||||
{
|
||||
$f = new Handler\CurlFactory(3);
|
||||
$f->create(new Psr7\Request('GET', Server::$url), [
|
||||
'sink' => '/does/not/exist/so/error.txt'
|
||||
]);
|
||||
}
|
||||
|
||||
public function testClosesIdleHandles()
|
||||
{
|
||||
$f = new Handler\CurlFactory(3);
|
||||
$req = new Psr7\Request('GET', Server::$url);
|
||||
$easy = $f->create($req, []);
|
||||
$h1 = $easy->handle;
|
||||
$f->release($easy);
|
||||
self::assertCount(1, self::readAttribute($f, 'handles'));
|
||||
$easy = $f->create($req, []);
|
||||
self::assertSame($easy->handle, $h1);
|
||||
$easy2 = $f->create($req, []);
|
||||
$easy3 = $f->create($req, []);
|
||||
$easy4 = $f->create($req, []);
|
||||
$f->release($easy);
|
||||
self::assertCount(1, self::readAttribute($f, 'handles'));
|
||||
$f->release($easy2);
|
||||
self::assertCount(2, self::readAttribute($f, 'handles'));
|
||||
$f->release($easy3);
|
||||
self::assertCount(3, self::readAttribute($f, 'handles'));
|
||||
$f->release($easy4);
|
||||
self::assertCount(3, self::readAttribute($f, 'handles'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \InvalidArgumentException
|
||||
*/
|
||||
public function testEnsuresOnHeadersIsCallable()
|
||||
{
|
||||
$req = new Psr7\Request('GET', Server::$url);
|
||||
$handler = new Handler\CurlHandler();
|
||||
$handler($req, ['on_headers' => 'error!']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \GuzzleHttp\Exception\RequestException
|
||||
* @expectedExceptionMessage An error was encountered during the on_headers event
|
||||
* @expectedExceptionMessage test
|
||||
*/
|
||||
public function testRejectsPromiseWhenOnHeadersFails()
|
||||
{
|
||||
Server::flush();
|
||||
Server::enqueue([
|
||||
new Psr7\Response(200, ['X-Foo' => 'bar'], 'abc 123')
|
||||
]);
|
||||
$req = new Psr7\Request('GET', Server::$url);
|
||||
$handler = new Handler\CurlHandler();
|
||||
$promise = $handler($req, [
|
||||
'on_headers' => function () {
|
||||
throw new \Exception('test');
|
||||
}
|
||||
]);
|
||||
$promise->wait();
|
||||
}
|
||||
|
||||
public function testSuccessfullyCallsOnHeadersBeforeWritingToSink()
|
||||
{
|
||||
Server::flush();
|
||||
Server::enqueue([
|
||||
new Psr7\Response(200, ['X-Foo' => 'bar'], 'abc 123')
|
||||
]);
|
||||
$req = new Psr7\Request('GET', Server::$url);
|
||||
$got = null;
|
||||
|
||||
$stream = Psr7\stream_for();
|
||||
$stream = Psr7\FnStream::decorate($stream, [
|
||||
'write' => function ($data) use ($stream, &$got) {
|
||||
self::assertNotNull($got);
|
||||
return $stream->write($data);
|
||||
}
|
||||
]);
|
||||
|
||||
$handler = new Handler\CurlHandler();
|
||||
$promise = $handler($req, [
|
||||
'sink' => $stream,
|
||||
'on_headers' => function (ResponseInterface $res) use (&$got) {
|
||||
$got = $res;
|
||||
self::assertEquals('bar', $res->getHeaderLine('X-Foo'));
|
||||
}
|
||||
]);
|
||||
|
||||
$response = $promise->wait();
|
||||
self::assertSame(200, $response->getStatusCode());
|
||||
self::assertSame('bar', $response->getHeaderLine('X-Foo'));
|
||||
self::assertSame('abc 123', (string) $response->getBody());
|
||||
}
|
||||
|
||||
public function testInvokesOnStatsOnSuccess()
|
||||
{
|
||||
Server::flush();
|
||||
Server::enqueue([new Psr7\Response(200)]);
|
||||
$req = new Psr7\Request('GET', Server::$url);
|
||||
$gotStats = null;
|
||||
$handler = new Handler\CurlHandler();
|
||||
$promise = $handler($req, [
|
||||
'on_stats' => function (TransferStats $stats) use (&$gotStats) {
|
||||
$gotStats = $stats;
|
||||
}
|
||||
]);
|
||||
$response = $promise->wait();
|
||||
self::assertSame(200, $response->getStatusCode());
|
||||
self::assertSame(200, $gotStats->getResponse()->getStatusCode());
|
||||
self::assertSame(
|
||||
Server::$url,
|
||||
(string) $gotStats->getEffectiveUri()
|
||||
);
|
||||
self::assertSame(
|
||||
Server::$url,
|
||||
(string) $gotStats->getRequest()->getUri()
|
||||
);
|
||||
self::assertGreaterThan(0, $gotStats->getTransferTime());
|
||||
self::assertArrayHasKey('appconnect_time', $gotStats->getHandlerStats());
|
||||
}
|
||||
|
||||
public function testInvokesOnStatsOnError()
|
||||
{
|
||||
$req = new Psr7\Request('GET', 'http://127.0.0.1:123');
|
||||
$gotStats = null;
|
||||
$handler = new Handler\CurlHandler();
|
||||
$promise = $handler($req, [
|
||||
'connect_timeout' => 0.001,
|
||||
'timeout' => 0.001,
|
||||
'on_stats' => function (TransferStats $stats) use (&$gotStats) {
|
||||
$gotStats = $stats;
|
||||
}
|
||||
]);
|
||||
$promise->wait(false);
|
||||
self::assertFalse($gotStats->hasResponse());
|
||||
self::assertSame(
|
||||
'http://127.0.0.1:123',
|
||||
(string) $gotStats->getEffectiveUri()
|
||||
);
|
||||
self::assertSame(
|
||||
'http://127.0.0.1:123',
|
||||
(string) $gotStats->getRequest()->getUri()
|
||||
);
|
||||
self::assertInternalType('float', $gotStats->getTransferTime());
|
||||
self::assertInternalType('int', $gotStats->getHandlerErrorData());
|
||||
self::assertArrayHasKey('appconnect_time', $gotStats->getHandlerStats());
|
||||
}
|
||||
|
||||
public function testRewindsBodyIfPossible()
|
||||
{
|
||||
$body = Psr7\stream_for(str_repeat('x', 1024 * 1024 * 2));
|
||||
$body->seek(1024 * 1024);
|
||||
self::assertSame(1024 * 1024, $body->tell());
|
||||
|
||||
$req = new Psr7\Request('POST', 'https://www.example.com', [
|
||||
'Content-Length' => 1024 * 1024 * 2,
|
||||
], $body);
|
||||
$factory = new CurlFactory(1);
|
||||
$factory->create($req, []);
|
||||
|
||||
self::assertSame(0, $body->tell());
|
||||
}
|
||||
|
||||
public function testDoesNotRewindUnseekableBody()
|
||||
{
|
||||
$body = Psr7\stream_for(str_repeat('x', 1024 * 1024 * 2));
|
||||
$body->seek(1024 * 1024);
|
||||
$body = new Psr7\NoSeekStream($body);
|
||||
self::assertSame(1024 * 1024, $body->tell());
|
||||
|
||||
$req = new Psr7\Request('POST', 'https://www.example.com', [
|
||||
'Content-Length' => 1024 * 1024,
|
||||
], $body);
|
||||
$factory = new CurlFactory(1);
|
||||
$factory->create($req, []);
|
||||
|
||||
self::assertSame(1024 * 1024, $body->tell());
|
||||
}
|
||||
|
||||
public function testRelease()
|
||||
{
|
||||
$factory = new CurlFactory(1);
|
||||
$easyHandle = new EasyHandle();
|
||||
$easyHandle->handle = curl_init();
|
||||
|
||||
self::assertEmpty($factory->release($easyHandle));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,87 @@
|
||||
<?php
|
||||
namespace GuzzleHttp\Test\Handler;
|
||||
|
||||
use GuzzleHttp\Exception\ConnectException;
|
||||
use GuzzleHttp\Handler\CurlHandler;
|
||||
use GuzzleHttp\Psr7;
|
||||
use GuzzleHttp\Psr7\Request;
|
||||
use GuzzleHttp\Psr7\Response;
|
||||
use GuzzleHttp\Tests\Server;
|
||||
use GuzzleHttp\Utils;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/**
|
||||
* @covers \GuzzleHttp\Handler\CurlHandler
|
||||
*/
|
||||
class CurlHandlerTest extends TestCase
|
||||
{
|
||||
protected function getHandler($options = [])
|
||||
{
|
||||
return new CurlHandler($options);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \GuzzleHttp\Exception\ConnectException
|
||||
* @expectedExceptionMessage cURL
|
||||
*/
|
||||
public function testCreatesCurlErrors()
|
||||
{
|
||||
$handler = new CurlHandler();
|
||||
$request = new Request('GET', 'http://localhost:123');
|
||||
$handler($request, ['timeout' => 0.001, 'connect_timeout' => 0.001])->wait();
|
||||
}
|
||||
|
||||
public function testReusesHandles()
|
||||
{
|
||||
Server::flush();
|
||||
$response = new response(200);
|
||||
Server::enqueue([$response, $response]);
|
||||
$a = new CurlHandler();
|
||||
$request = new Request('GET', Server::$url);
|
||||
self::assertInstanceOf('GuzzleHttp\Promise\FulfilledPromise', $a($request, []));
|
||||
self::assertInstanceOf('GuzzleHttp\Promise\FulfilledPromise', $a($request, []));
|
||||
}
|
||||
|
||||
public function testDoesSleep()
|
||||
{
|
||||
$response = new response(200);
|
||||
Server::enqueue([$response]);
|
||||
$a = new CurlHandler();
|
||||
$request = new Request('GET', Server::$url);
|
||||
$s = Utils::currentTime();
|
||||
$a($request, ['delay' => 0.1])->wait();
|
||||
self::assertGreaterThan(0.0001, Utils::currentTime() - $s);
|
||||
}
|
||||
|
||||
public function testCreatesCurlErrorsWithContext()
|
||||
{
|
||||
$handler = new CurlHandler();
|
||||
$request = new Request('GET', 'http://localhost:123');
|
||||
$called = false;
|
||||
$p = $handler($request, ['timeout' => 0.001, 'connect_timeout' => 0.001])
|
||||
->otherwise(function (ConnectException $e) use (&$called) {
|
||||
$called = true;
|
||||
self::assertArrayHasKey('errno', $e->getHandlerContext());
|
||||
});
|
||||
$p->wait();
|
||||
self::assertTrue($called);
|
||||
}
|
||||
|
||||
public function testUsesContentLengthWhenOverInMemorySize()
|
||||
{
|
||||
Server::flush();
|
||||
Server::enqueue([new Response()]);
|
||||
$stream = Psr7\stream_for(str_repeat('.', 1000000));
|
||||
$handler = new CurlHandler();
|
||||
$request = new Request(
|
||||
'PUT',
|
||||
Server::$url,
|
||||
['Content-Length' => 1000000],
|
||||
$stream
|
||||
);
|
||||
$handler($request, [])->wait();
|
||||
$received = Server::received()[0];
|
||||
self::assertEquals(1000000, $received->getHeaderLine('Content-Length'));
|
||||
self::assertFalse($received->hasHeader('Transfer-Encoding'));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,123 @@
|
||||
<?php
|
||||
namespace GuzzleHttp\Tests\Handler;
|
||||
|
||||
use GuzzleHttp\Handler\CurlMultiHandler;
|
||||
use GuzzleHttp\Psr7\Request;
|
||||
use GuzzleHttp\Psr7\Response;
|
||||
use GuzzleHttp\Tests\Server;
|
||||
use GuzzleHttp\Utils;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class CurlMultiHandlerTest extends TestCase
|
||||
{
|
||||
public function setUp()
|
||||
{
|
||||
$_SERVER['curl_test'] = true;
|
||||
unset($_SERVER['_curl_multi']);
|
||||
}
|
||||
|
||||
public function tearDown()
|
||||
{
|
||||
unset($_SERVER['_curl_multi'], $_SERVER['curl_test']);
|
||||
}
|
||||
|
||||
public function testCanAddCustomCurlOptions()
|
||||
{
|
||||
Server::flush();
|
||||
Server::enqueue([new Response()]);
|
||||
$a = new CurlMultiHandler(['options' => [
|
||||
CURLMOPT_MAXCONNECTS => 5,
|
||||
]]);
|
||||
$request = new Request('GET', Server::$url);
|
||||
$a($request, []);
|
||||
self::assertEquals(5, $_SERVER['_curl_multi'][CURLMOPT_MAXCONNECTS]);
|
||||
}
|
||||
|
||||
public function testSendsRequest()
|
||||
{
|
||||
Server::enqueue([new Response()]);
|
||||
$a = new CurlMultiHandler();
|
||||
$request = new Request('GET', Server::$url);
|
||||
$response = $a($request, [])->wait();
|
||||
self::assertSame(200, $response->getStatusCode());
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \GuzzleHttp\Exception\ConnectException
|
||||
* @expectedExceptionMessage cURL error
|
||||
*/
|
||||
public function testCreatesExceptions()
|
||||
{
|
||||
$a = new CurlMultiHandler();
|
||||
$a(new Request('GET', 'http://localhost:123'), [])->wait();
|
||||
}
|
||||
|
||||
public function testCanSetSelectTimeout()
|
||||
{
|
||||
$a = new CurlMultiHandler(['select_timeout' => 2]);
|
||||
self::assertEquals(2, self::readAttribute($a, 'selectTimeout'));
|
||||
}
|
||||
|
||||
public function testCanCancel()
|
||||
{
|
||||
Server::flush();
|
||||
$response = new Response(200);
|
||||
Server::enqueue(array_fill_keys(range(0, 10), $response));
|
||||
$a = new CurlMultiHandler();
|
||||
$responses = [];
|
||||
for ($i = 0; $i < 10; $i++) {
|
||||
$response = $a(new Request('GET', Server::$url), []);
|
||||
$response->cancel();
|
||||
$responses[] = $response;
|
||||
}
|
||||
|
||||
foreach ($responses as $r) {
|
||||
self::assertSame('rejected', $response->getState());
|
||||
}
|
||||
}
|
||||
|
||||
public function testCannotCancelFinished()
|
||||
{
|
||||
Server::flush();
|
||||
Server::enqueue([new Response(200)]);
|
||||
$a = new CurlMultiHandler();
|
||||
$response = $a(new Request('GET', Server::$url), []);
|
||||
$response->wait();
|
||||
$response->cancel();
|
||||
self::assertSame('fulfilled', $response->getState());
|
||||
}
|
||||
|
||||
public function testDelaysConcurrently()
|
||||
{
|
||||
Server::flush();
|
||||
Server::enqueue([new Response()]);
|
||||
$a = new CurlMultiHandler();
|
||||
$expected = Utils::currentTime() + (100 / 1000);
|
||||
$response = $a(new Request('GET', Server::$url), ['delay' => 100]);
|
||||
$response->wait();
|
||||
self::assertGreaterThanOrEqual($expected, Utils::currentTime());
|
||||
}
|
||||
|
||||
public function testUsesTimeoutEnvironmentVariables()
|
||||
{
|
||||
$a = new CurlMultiHandler();
|
||||
|
||||
//default if no options are given and no environment variable is set
|
||||
self::assertEquals(1, self::readAttribute($a, 'selectTimeout'));
|
||||
|
||||
putenv("GUZZLE_CURL_SELECT_TIMEOUT=3");
|
||||
$a = new CurlMultiHandler();
|
||||
$selectTimeout = getenv('GUZZLE_CURL_SELECT_TIMEOUT');
|
||||
//Handler reads from the environment if no options are given
|
||||
self::assertEquals($selectTimeout, self::readAttribute($a, 'selectTimeout'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \BadMethodCallException
|
||||
*/
|
||||
public function throwsWhenAccessingInvalidProperty()
|
||||
{
|
||||
$h = new CurlMultiHandler();
|
||||
$h->foo;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,23 @@
|
||||
<?php
|
||||
namespace GuzzleHttp\Test\Handler;
|
||||
|
||||
use GuzzleHttp\Handler\EasyHandle;
|
||||
use GuzzleHttp\Psr7;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/**
|
||||
* @covers \GuzzleHttp\Handler\EasyHandle
|
||||
*/
|
||||
class EasyHandleTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @expectedException \BadMethodCallException
|
||||
* @expectedExceptionMessage The EasyHandle has been released
|
||||
*/
|
||||
public function testEnsuresHandleExists()
|
||||
{
|
||||
$easy = new EasyHandle;
|
||||
unset($easy->handle);
|
||||
$easy->handle;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,261 @@
|
||||
<?php
|
||||
namespace GuzzleHttp\Test\Handler;
|
||||
|
||||
use GuzzleHttp\Handler\MockHandler;
|
||||
use GuzzleHttp\Promise\PromiseInterface;
|
||||
use GuzzleHttp\Psr7\Request;
|
||||
use GuzzleHttp\Psr7\Response;
|
||||
use GuzzleHttp\TransferStats;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/**
|
||||
* @covers \GuzzleHttp\Handler\MockHandler
|
||||
*/
|
||||
class MockHandlerTest extends TestCase
|
||||
{
|
||||
public function testReturnsMockResponse()
|
||||
{
|
||||
$res = new Response();
|
||||
$mock = new MockHandler([$res]);
|
||||
$request = new Request('GET', 'http://example.com');
|
||||
$p = $mock($request, []);
|
||||
self::assertSame($res, $p->wait());
|
||||
}
|
||||
|
||||
public function testIsCountable()
|
||||
{
|
||||
$res = new Response();
|
||||
$mock = new MockHandler([$res, $res]);
|
||||
self::assertCount(2, $mock);
|
||||
}
|
||||
|
||||
public function testEmptyHandlerIsCountable()
|
||||
{
|
||||
self::assertCount(0, new MockHandler());
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \InvalidArgumentException
|
||||
*/
|
||||
public function testEnsuresEachAppendIsValid()
|
||||
{
|
||||
$mock = new MockHandler(['a']);
|
||||
$request = new Request('GET', 'http://example.com');
|
||||
$mock($request, []);
|
||||
}
|
||||
|
||||
public function testCanQueueExceptions()
|
||||
{
|
||||
$e = new \Exception('a');
|
||||
$mock = new MockHandler([$e]);
|
||||
$request = new Request('GET', 'http://example.com');
|
||||
$p = $mock($request, []);
|
||||
try {
|
||||
$p->wait();
|
||||
self::fail();
|
||||
} catch (\Exception $e2) {
|
||||
self::assertSame($e, $e2);
|
||||
}
|
||||
}
|
||||
|
||||
public function testCanGetLastRequestAndOptions()
|
||||
{
|
||||
$res = new Response();
|
||||
$mock = new MockHandler([$res]);
|
||||
$request = new Request('GET', 'http://example.com');
|
||||
$mock($request, ['foo' => 'bar']);
|
||||
self::assertSame($request, $mock->getLastRequest());
|
||||
self::assertSame(['foo' => 'bar'], $mock->getLastOptions());
|
||||
}
|
||||
|
||||
public function testSinkFilename()
|
||||
{
|
||||
$filename = sys_get_temp_dir() . '/mock_test_' . uniqid();
|
||||
$res = new Response(200, [], 'TEST CONTENT');
|
||||
$mock = new MockHandler([$res]);
|
||||
$request = new Request('GET', '/');
|
||||
$p = $mock($request, ['sink' => $filename]);
|
||||
$p->wait();
|
||||
|
||||
self::assertFileExists($filename);
|
||||
self::assertStringEqualsFile($filename, 'TEST CONTENT');
|
||||
|
||||
unlink($filename);
|
||||
}
|
||||
|
||||
public function testSinkResource()
|
||||
{
|
||||
$file = tmpfile();
|
||||
$meta = stream_get_meta_data($file);
|
||||
$res = new Response(200, [], 'TEST CONTENT');
|
||||
$mock = new MockHandler([$res]);
|
||||
$request = new Request('GET', '/');
|
||||
$p = $mock($request, ['sink' => $file]);
|
||||
$p->wait();
|
||||
|
||||
self::assertFileExists($meta['uri']);
|
||||
self::assertStringEqualsFile($meta['uri'], 'TEST CONTENT');
|
||||
}
|
||||
|
||||
public function testSinkStream()
|
||||
{
|
||||
$stream = new \GuzzleHttp\Psr7\Stream(tmpfile());
|
||||
$res = new Response(200, [], 'TEST CONTENT');
|
||||
$mock = new MockHandler([$res]);
|
||||
$request = new Request('GET', '/');
|
||||
$p = $mock($request, ['sink' => $stream]);
|
||||
$p->wait();
|
||||
|
||||
self::assertFileExists($stream->getMetadata('uri'));
|
||||
self::assertStringEqualsFile($stream->getMetadata('uri'), 'TEST CONTENT');
|
||||
}
|
||||
|
||||
public function testCanEnqueueCallables()
|
||||
{
|
||||
$r = new Response();
|
||||
$fn = function ($req, $o) use ($r) {
|
||||
return $r;
|
||||
};
|
||||
$mock = new MockHandler([$fn]);
|
||||
$request = new Request('GET', 'http://example.com');
|
||||
$p = $mock($request, ['foo' => 'bar']);
|
||||
self::assertSame($r, $p->wait());
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \InvalidArgumentException
|
||||
*/
|
||||
public function testEnsuresOnHeadersIsCallable()
|
||||
{
|
||||
$res = new Response();
|
||||
$mock = new MockHandler([$res]);
|
||||
$request = new Request('GET', 'http://example.com');
|
||||
$mock($request, ['on_headers' => 'error!']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \GuzzleHttp\Exception\RequestException
|
||||
* @expectedExceptionMessage An error was encountered during the on_headers event
|
||||
* @expectedExceptionMessage test
|
||||
*/
|
||||
public function testRejectsPromiseWhenOnHeadersFails()
|
||||
{
|
||||
$res = new Response();
|
||||
$mock = new MockHandler([$res]);
|
||||
$request = new Request('GET', 'http://example.com');
|
||||
$promise = $mock($request, [
|
||||
'on_headers' => function () {
|
||||
throw new \Exception('test');
|
||||
}
|
||||
]);
|
||||
|
||||
$promise->wait();
|
||||
}
|
||||
public function testInvokesOnFulfilled()
|
||||
{
|
||||
$res = new Response();
|
||||
$mock = new MockHandler([$res], function ($v) use (&$c) {
|
||||
$c = $v;
|
||||
});
|
||||
$request = new Request('GET', 'http://example.com');
|
||||
$mock($request, [])->wait();
|
||||
self::assertSame($res, $c);
|
||||
}
|
||||
|
||||
public function testInvokesOnRejected()
|
||||
{
|
||||
$e = new \Exception('a');
|
||||
$c = null;
|
||||
$mock = new MockHandler([$e], null, function ($v) use (&$c) {
|
||||
$c = $v;
|
||||
});
|
||||
$request = new Request('GET', 'http://example.com');
|
||||
$mock($request, [])->wait(false);
|
||||
self::assertSame($e, $c);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \OutOfBoundsException
|
||||
*/
|
||||
public function testThrowsWhenNoMoreResponses()
|
||||
{
|
||||
$mock = new MockHandler();
|
||||
$request = new Request('GET', 'http://example.com');
|
||||
$mock($request, []);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \GuzzleHttp\Exception\BadResponseException
|
||||
*/
|
||||
public function testCanCreateWithDefaultMiddleware()
|
||||
{
|
||||
$r = new Response(500);
|
||||
$mock = MockHandler::createWithMiddleware([$r]);
|
||||
$request = new Request('GET', 'http://example.com');
|
||||
$mock($request, ['http_errors' => true])->wait();
|
||||
}
|
||||
|
||||
public function testInvokesOnStatsFunctionForResponse()
|
||||
{
|
||||
$res = new Response();
|
||||
$mock = new MockHandler([$res]);
|
||||
$request = new Request('GET', 'http://example.com');
|
||||
/** @var TransferStats|null $stats */
|
||||
$stats = null;
|
||||
$onStats = function (TransferStats $s) use (&$stats) {
|
||||
$stats = $s;
|
||||
};
|
||||
$p = $mock($request, ['on_stats' => $onStats]);
|
||||
$p->wait();
|
||||
self::assertSame($res, $stats->getResponse());
|
||||
self::assertSame($request, $stats->getRequest());
|
||||
}
|
||||
|
||||
public function testInvokesOnStatsFunctionForError()
|
||||
{
|
||||
$e = new \Exception('a');
|
||||
$c = null;
|
||||
$mock = new MockHandler([$e], null, function ($v) use (&$c) {
|
||||
$c = $v;
|
||||
});
|
||||
$request = new Request('GET', 'http://example.com');
|
||||
|
||||
/** @var TransferStats|null $stats */
|
||||
$stats = null;
|
||||
$onStats = function (TransferStats $s) use (&$stats) {
|
||||
$stats = $s;
|
||||
};
|
||||
$mock($request, ['on_stats' => $onStats])->wait(false);
|
||||
self::assertSame($e, $stats->getHandlerErrorData());
|
||||
self::assertNull($stats->getResponse());
|
||||
self::assertSame($request, $stats->getRequest());
|
||||
}
|
||||
|
||||
public function testTransferTime()
|
||||
{
|
||||
$e = new \Exception('a');
|
||||
$c = null;
|
||||
$mock = new MockHandler([$e], null, function ($v) use (&$c) {
|
||||
$c = $v;
|
||||
});
|
||||
$request = new Request('GET', 'http://example.com');
|
||||
$stats = null;
|
||||
$onStats = function (TransferStats $s) use (&$stats) {
|
||||
$stats = $s;
|
||||
};
|
||||
$mock($request, [ 'on_stats' => $onStats, 'transfer_time' => 0.4 ])->wait(false);
|
||||
self::assertEquals(0.4, $stats->getTransferTime());
|
||||
}
|
||||
|
||||
public function testResetQueue()
|
||||
{
|
||||
$mock = new MockHandler([new Response(200), new Response(204)]);
|
||||
self::assertCount(2, $mock);
|
||||
|
||||
$mock->reset();
|
||||
self::assertEmpty($mock);
|
||||
|
||||
$mock->append(new Response(500));
|
||||
self::assertCount(1, $mock);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,74 @@
|
||||
<?php
|
||||
namespace GuzzleHttp\Test\Handler;
|
||||
|
||||
use GuzzleHttp\Handler\MockHandler;
|
||||
use GuzzleHttp\Handler\Proxy;
|
||||
use GuzzleHttp\Psr7\Request;
|
||||
use GuzzleHttp\RequestOptions;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/**
|
||||
* @covers \GuzzleHttp\Handler\Proxy
|
||||
*/
|
||||
class ProxyTest extends TestCase
|
||||
{
|
||||
public function testSendsToNonSync()
|
||||
{
|
||||
$a = $b = null;
|
||||
$m1 = new MockHandler([function ($v) use (&$a) {
|
||||
$a = $v;
|
||||
}]);
|
||||
$m2 = new MockHandler([function ($v) use (&$b) {
|
||||
$b = $v;
|
||||
}]);
|
||||
$h = Proxy::wrapSync($m1, $m2);
|
||||
$h(new Request('GET', 'http://foo.com'), []);
|
||||
self::assertNotNull($a);
|
||||
self::assertNull($b);
|
||||
}
|
||||
|
||||
public function testSendsToSync()
|
||||
{
|
||||
$a = $b = null;
|
||||
$m1 = new MockHandler([function ($v) use (&$a) {
|
||||
$a = $v;
|
||||
}]);
|
||||
$m2 = new MockHandler([function ($v) use (&$b) {
|
||||
$b = $v;
|
||||
}]);
|
||||
$h = Proxy::wrapSync($m1, $m2);
|
||||
$h(new Request('GET', 'http://foo.com'), [RequestOptions::SYNCHRONOUS => true]);
|
||||
self::assertNull($a);
|
||||
self::assertNotNull($b);
|
||||
}
|
||||
|
||||
public function testSendsToStreaming()
|
||||
{
|
||||
$a = $b = null;
|
||||
$m1 = new MockHandler([function ($v) use (&$a) {
|
||||
$a = $v;
|
||||
}]);
|
||||
$m2 = new MockHandler([function ($v) use (&$b) {
|
||||
$b = $v;
|
||||
}]);
|
||||
$h = Proxy::wrapStreaming($m1, $m2);
|
||||
$h(new Request('GET', 'http://foo.com'), []);
|
||||
self::assertNotNull($a);
|
||||
self::assertNull($b);
|
||||
}
|
||||
|
||||
public function testSendsToNonStreaming()
|
||||
{
|
||||
$a = $b = null;
|
||||
$m1 = new MockHandler([function ($v) use (&$a) {
|
||||
$a = $v;
|
||||
}]);
|
||||
$m2 = new MockHandler([function ($v) use (&$b) {
|
||||
$b = $v;
|
||||
}]);
|
||||
$h = Proxy::wrapStreaming($m1, $m2);
|
||||
$h(new Request('GET', 'http://foo.com'), ['stream' => true]);
|
||||
self::assertNull($a);
|
||||
self::assertNotNull($b);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,689 @@
|
||||
<?php
|
||||
namespace GuzzleHttp\Test\Handler;
|
||||
|
||||
use GuzzleHttp\Exception\ConnectException;
|
||||
use GuzzleHttp\Handler\StreamHandler;
|
||||
use GuzzleHttp\Psr7;
|
||||
use GuzzleHttp\Psr7\FnStream;
|
||||
use GuzzleHttp\Psr7\Request;
|
||||
use GuzzleHttp\Psr7\Response;
|
||||
use GuzzleHttp\RequestOptions;
|
||||
use GuzzleHttp\Tests\Server;
|
||||
use GuzzleHttp\TransferStats;
|
||||
use GuzzleHttp\Utils;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
/**
|
||||
* @covers \GuzzleHttp\Handler\StreamHandler
|
||||
*/
|
||||
class StreamHandlerTest extends TestCase
|
||||
{
|
||||
private function queueRes()
|
||||
{
|
||||
Server::flush();
|
||||
Server::enqueue([
|
||||
new Response(200, [
|
||||
'Foo' => 'Bar',
|
||||
'Content-Length' => 8,
|
||||
], 'hi there')
|
||||
]);
|
||||
}
|
||||
|
||||
public function testReturnsResponseForSuccessfulRequest()
|
||||
{
|
||||
$this->queueRes();
|
||||
$handler = new StreamHandler();
|
||||
$response = $handler(
|
||||
new Request('GET', Server::$url, ['Foo' => 'Bar']),
|
||||
[]
|
||||
)->wait();
|
||||
self::assertSame(200, $response->getStatusCode());
|
||||
self::assertSame('OK', $response->getReasonPhrase());
|
||||
self::assertSame('Bar', $response->getHeaderLine('Foo'));
|
||||
self::assertSame('8', $response->getHeaderLine('Content-Length'));
|
||||
self::assertSame('hi there', (string) $response->getBody());
|
||||
$sent = Server::received()[0];
|
||||
self::assertSame('GET', $sent->getMethod());
|
||||
self::assertSame('/', $sent->getUri()->getPath());
|
||||
self::assertSame('127.0.0.1:8126', $sent->getHeaderLine('Host'));
|
||||
self::assertSame('Bar', $sent->getHeaderLine('foo'));
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \GuzzleHttp\Exception\RequestException
|
||||
*/
|
||||
public function testAddsErrorToResponse()
|
||||
{
|
||||
$handler = new StreamHandler();
|
||||
$handler(
|
||||
new Request('GET', 'http://localhost:123'),
|
||||
['timeout' => 0.01]
|
||||
)->wait();
|
||||
}
|
||||
|
||||
public function testStreamAttributeKeepsStreamOpen()
|
||||
{
|
||||
$this->queueRes();
|
||||
$handler = new StreamHandler();
|
||||
$request = new Request(
|
||||
'PUT',
|
||||
Server::$url . 'foo?baz=bar',
|
||||
['Foo' => 'Bar'],
|
||||
'test'
|
||||
);
|
||||
$response = $handler($request, ['stream' => true])->wait();
|
||||
self::assertSame(200, $response->getStatusCode());
|
||||
self::assertSame('OK', $response->getReasonPhrase());
|
||||
self::assertSame('8', $response->getHeaderLine('Content-Length'));
|
||||
$body = $response->getBody();
|
||||
$stream = $body->detach();
|
||||
self::assertInternalType('resource', $stream);
|
||||
self::assertSame('http', stream_get_meta_data($stream)['wrapper_type']);
|
||||
self::assertSame('hi there', stream_get_contents($stream));
|
||||
fclose($stream);
|
||||
$sent = Server::received()[0];
|
||||
self::assertSame('PUT', $sent->getMethod());
|
||||
self::assertSame('http://127.0.0.1:8126/foo?baz=bar', (string) $sent->getUri());
|
||||
self::assertSame('Bar', $sent->getHeaderLine('Foo'));
|
||||
self::assertSame('test', (string) $sent->getBody());
|
||||
}
|
||||
|
||||
public function testDrainsResponseIntoTempStream()
|
||||
{
|
||||
$this->queueRes();
|
||||
$handler = new StreamHandler();
|
||||
$request = new Request('GET', Server::$url);
|
||||
$response = $handler($request, [])->wait();
|
||||
$body = $response->getBody();
|
||||
$stream = $body->detach();
|
||||
self::assertSame('php://temp', stream_get_meta_data($stream)['uri']);
|
||||
self::assertSame('hi', fread($stream, 2));
|
||||
fclose($stream);
|
||||
}
|
||||
|
||||
public function testDrainsResponseIntoSaveToBody()
|
||||
{
|
||||
$r = fopen('php://temp', 'r+');
|
||||
$this->queueRes();
|
||||
$handler = new StreamHandler();
|
||||
$request = new Request('GET', Server::$url);
|
||||
$response = $handler($request, ['sink' => $r])->wait();
|
||||
$body = $response->getBody()->detach();
|
||||
self::assertSame('php://temp', stream_get_meta_data($body)['uri']);
|
||||
self::assertSame('hi', fread($body, 2));
|
||||
self::assertSame(' there', stream_get_contents($r));
|
||||
fclose($r);
|
||||
}
|
||||
|
||||
public function testDrainsResponseIntoSaveToBodyAtPath()
|
||||
{
|
||||
$tmpfname = tempnam('/tmp', 'save_to_path');
|
||||
$this->queueRes();
|
||||
$handler = new StreamHandler();
|
||||
$request = new Request('GET', Server::$url);
|
||||
$response = $handler($request, ['sink' => $tmpfname])->wait();
|
||||
$body = $response->getBody();
|
||||
self::assertSame($tmpfname, $body->getMetadata('uri'));
|
||||
self::assertSame('hi', $body->read(2));
|
||||
$body->close();
|
||||
unlink($tmpfname);
|
||||
}
|
||||
|
||||
public function testDrainsResponseIntoSaveToBodyAtNonExistentPath()
|
||||
{
|
||||
$tmpfname = tempnam('/tmp', 'save_to_path');
|
||||
unlink($tmpfname);
|
||||
$this->queueRes();
|
||||
$handler = new StreamHandler();
|
||||
$request = new Request('GET', Server::$url);
|
||||
$response = $handler($request, ['sink' => $tmpfname])->wait();
|
||||
$body = $response->getBody();
|
||||
self::assertSame($tmpfname, $body->getMetadata('uri'));
|
||||
self::assertSame('hi', $body->read(2));
|
||||
$body->close();
|
||||
unlink($tmpfname);
|
||||
}
|
||||
|
||||
public function testDrainsResponseAndReadsOnlyContentLengthBytes()
|
||||
{
|
||||
Server::flush();
|
||||
Server::enqueue([
|
||||
new Response(200, [
|
||||
'Foo' => 'Bar',
|
||||
'Content-Length' => 8,
|
||||
], 'hi there... This has way too much data!')
|
||||
]);
|
||||
$handler = new StreamHandler();
|
||||
$request = new Request('GET', Server::$url);
|
||||
$response = $handler($request, [])->wait();
|
||||
$body = $response->getBody();
|
||||
$stream = $body->detach();
|
||||
self::assertSame('hi there', stream_get_contents($stream));
|
||||
fclose($stream);
|
||||
}
|
||||
|
||||
public function testDoesNotDrainWhenHeadRequest()
|
||||
{
|
||||
Server::flush();
|
||||
// Say the content-length is 8, but return no response.
|
||||
Server::enqueue([
|
||||
new Response(200, [
|
||||
'Foo' => 'Bar',
|
||||
'Content-Length' => 8,
|
||||
], '')
|
||||
]);
|
||||
$handler = new StreamHandler();
|
||||
$request = new Request('HEAD', Server::$url);
|
||||
$response = $handler($request, [])->wait();
|
||||
$body = $response->getBody();
|
||||
$stream = $body->detach();
|
||||
self::assertSame('', stream_get_contents($stream));
|
||||
fclose($stream);
|
||||
}
|
||||
|
||||
public function testAutomaticallyDecompressGzip()
|
||||
{
|
||||
Server::flush();
|
||||
$content = gzencode('test');
|
||||
Server::enqueue([
|
||||
new Response(200, [
|
||||
'Content-Encoding' => 'gzip',
|
||||
'Content-Length' => strlen($content),
|
||||
], $content)
|
||||
]);
|
||||
$handler = new StreamHandler();
|
||||
$request = new Request('GET', Server::$url);
|
||||
$response = $handler($request, ['decode_content' => true])->wait();
|
||||
self::assertSame('test', (string) $response->getBody());
|
||||
self::assertFalse($response->hasHeader('content-encoding'));
|
||||
self::assertTrue(!$response->hasHeader('content-length') || $response->getHeaderLine('content-length') == $response->getBody()->getSize());
|
||||
}
|
||||
|
||||
public function testReportsOriginalSizeAndContentEncodingAfterDecoding()
|
||||
{
|
||||
Server::flush();
|
||||
$content = gzencode('test');
|
||||
Server::enqueue([
|
||||
new Response(200, [
|
||||
'Content-Encoding' => 'gzip',
|
||||
'Content-Length' => strlen($content),
|
||||
], $content)
|
||||
]);
|
||||
$handler = new StreamHandler();
|
||||
$request = new Request('GET', Server::$url);
|
||||
$response = $handler($request, ['decode_content' => true])->wait();
|
||||
|
||||
self::assertSame(
|
||||
'gzip',
|
||||
$response->getHeaderLine('x-encoded-content-encoding')
|
||||
);
|
||||
self::assertSame(
|
||||
strlen($content),
|
||||
(int) $response->getHeaderLine('x-encoded-content-length')
|
||||
);
|
||||
}
|
||||
|
||||
public function testDoesNotForceGzipDecode()
|
||||
{
|
||||
Server::flush();
|
||||
$content = gzencode('test');
|
||||
Server::enqueue([
|
||||
new Response(200, [
|
||||
'Content-Encoding' => 'gzip',
|
||||
'Content-Length' => strlen($content),
|
||||
], $content)
|
||||
]);
|
||||
$handler = new StreamHandler();
|
||||
$request = new Request('GET', Server::$url);
|
||||
$response = $handler($request, ['decode_content' => false])->wait();
|
||||
self::assertSame($content, (string) $response->getBody());
|
||||
self::assertSame('gzip', $response->getHeaderLine('content-encoding'));
|
||||
self::assertEquals(strlen($content), $response->getHeaderLine('content-length'));
|
||||
}
|
||||
|
||||
public function testProtocolVersion()
|
||||
{
|
||||
$this->queueRes();
|
||||
$handler = new StreamHandler();
|
||||
$request = new Request('GET', Server::$url, [], null, '1.0');
|
||||
$handler($request, []);
|
||||
self::assertSame('1.0', Server::received()[0]->getProtocolVersion());
|
||||
}
|
||||
|
||||
protected function getSendResult(array $opts)
|
||||
{
|
||||
$this->queueRes();
|
||||
$handler = new StreamHandler();
|
||||
$opts['stream'] = true;
|
||||
$request = new Request('GET', Server::$url);
|
||||
return $handler($request, $opts)->wait();
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \GuzzleHttp\Exception\ConnectException
|
||||
* @expectedExceptionMessage Connection refused
|
||||
*/
|
||||
public function testAddsProxy()
|
||||
{
|
||||
$this->getSendResult(['proxy' => '127.0.0.1:8125']);
|
||||
}
|
||||
|
||||
public function testAddsProxyByProtocol()
|
||||
{
|
||||
$url = str_replace('http', 'tcp', Server::$url);
|
||||
// Workaround until #1823 is fixed properly
|
||||
$url = rtrim($url, '/');
|
||||
$res = $this->getSendResult(['proxy' => ['http' => $url]]);
|
||||
$opts = stream_context_get_options($res->getBody()->detach());
|
||||
self::assertSame($url, $opts['http']['proxy']);
|
||||
}
|
||||
|
||||
public function testAddsProxyButHonorsNoProxy()
|
||||
{
|
||||
$url = str_replace('http', 'tcp', Server::$url);
|
||||
$res = $this->getSendResult(['proxy' => [
|
||||
'http' => $url,
|
||||
'no' => ['*']
|
||||
]]);
|
||||
$opts = stream_context_get_options($res->getBody()->detach());
|
||||
self::assertArrayNotHasKey('proxy', $opts['http']);
|
||||
}
|
||||
|
||||
public function testAddsTimeout()
|
||||
{
|
||||
$res = $this->getSendResult(['stream' => true, 'timeout' => 200]);
|
||||
$opts = stream_context_get_options($res->getBody()->detach());
|
||||
self::assertEquals(200, $opts['http']['timeout']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \GuzzleHttp\Exception\RequestException
|
||||
* @expectedExceptionMessage SSL CA bundle not found: /does/not/exist
|
||||
*/
|
||||
public function testVerifiesVerifyIsValidIfPath()
|
||||
{
|
||||
$this->getSendResult(['verify' => '/does/not/exist']);
|
||||
}
|
||||
|
||||
public function testVerifyCanBeDisabled()
|
||||
{
|
||||
$handler = $this->getSendResult(['verify' => false]);
|
||||
self::assertInstanceOf('GuzzleHttp\Psr7\Response', $handler);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \GuzzleHttp\Exception\RequestException
|
||||
* @expectedExceptionMessage SSL certificate not found: /does/not/exist
|
||||
*/
|
||||
public function testVerifiesCertIfValidPath()
|
||||
{
|
||||
$this->getSendResult(['cert' => '/does/not/exist']);
|
||||
}
|
||||
|
||||
public function testVerifyCanBeSetToPath()
|
||||
{
|
||||
$path = $path = \GuzzleHttp\default_ca_bundle();
|
||||
$res = $this->getSendResult(['verify' => $path]);
|
||||
$opts = stream_context_get_options($res->getBody()->detach());
|
||||
self::assertTrue($opts['ssl']['verify_peer']);
|
||||
self::assertTrue($opts['ssl']['verify_peer_name']);
|
||||
self::assertSame($path, $opts['ssl']['cafile']);
|
||||
self::assertFileExists($opts['ssl']['cafile']);
|
||||
}
|
||||
|
||||
public function testUsesSystemDefaultBundle()
|
||||
{
|
||||
$path = $path = \GuzzleHttp\default_ca_bundle();
|
||||
$res = $this->getSendResult(['verify' => true]);
|
||||
$opts = stream_context_get_options($res->getBody()->detach());
|
||||
if (PHP_VERSION_ID < 50600) {
|
||||
self::assertSame($path, $opts['ssl']['cafile']);
|
||||
} else {
|
||||
self::assertArrayNotHasKey('cafile', $opts['ssl']);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \InvalidArgumentException
|
||||
* @expectedExceptionMessage Invalid verify request option
|
||||
*/
|
||||
public function testEnsuresVerifyOptionIsValid()
|
||||
{
|
||||
$this->getSendResult(['verify' => 10]);
|
||||
}
|
||||
|
||||
public function testCanSetPasswordWhenSettingCert()
|
||||
{
|
||||
$path = __FILE__;
|
||||
$res = $this->getSendResult(['cert' => [$path, 'foo']]);
|
||||
$opts = stream_context_get_options($res->getBody()->detach());
|
||||
self::assertSame($path, $opts['ssl']['local_cert']);
|
||||
self::assertSame('foo', $opts['ssl']['passphrase']);
|
||||
}
|
||||
|
||||
public function testDebugAttributeWritesToStream()
|
||||
{
|
||||
$this->queueRes();
|
||||
$f = fopen('php://temp', 'w+');
|
||||
$this->getSendResult(['debug' => $f]);
|
||||
fseek($f, 0);
|
||||
$contents = stream_get_contents($f);
|
||||
self::assertContains('<GET http://127.0.0.1:8126/> [CONNECT]', $contents);
|
||||
self::assertContains('<GET http://127.0.0.1:8126/> [FILE_SIZE_IS]', $contents);
|
||||
self::assertContains('<GET http://127.0.0.1:8126/> [PROGRESS]', $contents);
|
||||
}
|
||||
|
||||
public function testDebugAttributeWritesStreamInfoToBuffer()
|
||||
{
|
||||
$called = false;
|
||||
$this->queueRes();
|
||||
$buffer = fopen('php://temp', 'r+');
|
||||
$this->getSendResult([
|
||||
'progress' => function () use (&$called) {
|
||||
$called = true;
|
||||
},
|
||||
'debug' => $buffer,
|
||||
]);
|
||||
fseek($buffer, 0);
|
||||
$contents = stream_get_contents($buffer);
|
||||
self::assertContains('<GET http://127.0.0.1:8126/> [CONNECT]', $contents);
|
||||
self::assertContains('<GET http://127.0.0.1:8126/> [FILE_SIZE_IS] message: "Content-Length: 8"', $contents);
|
||||
self::assertContains('<GET http://127.0.0.1:8126/> [PROGRESS] bytes_max: "8"', $contents);
|
||||
self::assertTrue($called);
|
||||
}
|
||||
|
||||
public function testEmitsProgressInformation()
|
||||
{
|
||||
$called = [];
|
||||
$this->queueRes();
|
||||
$this->getSendResult([
|
||||
'progress' => function () use (&$called) {
|
||||
$called[] = func_get_args();
|
||||
},
|
||||
]);
|
||||
self::assertNotEmpty($called);
|
||||
self::assertEquals(8, $called[0][0]);
|
||||
self::assertEquals(0, $called[0][1]);
|
||||
}
|
||||
|
||||
public function testEmitsProgressInformationAndDebugInformation()
|
||||
{
|
||||
$called = [];
|
||||
$this->queueRes();
|
||||
$buffer = fopen('php://memory', 'w+');
|
||||
$this->getSendResult([
|
||||
'debug' => $buffer,
|
||||
'progress' => function () use (&$called) {
|
||||
$called[] = func_get_args();
|
||||
},
|
||||
]);
|
||||
self::assertNotEmpty($called);
|
||||
self::assertEquals(8, $called[0][0]);
|
||||
self::assertEquals(0, $called[0][1]);
|
||||
rewind($buffer);
|
||||
self::assertNotEmpty(stream_get_contents($buffer));
|
||||
fclose($buffer);
|
||||
}
|
||||
|
||||
public function testPerformsShallowMergeOfCustomContextOptions()
|
||||
{
|
||||
$res = $this->getSendResult([
|
||||
'stream_context' => [
|
||||
'http' => [
|
||||
'request_fulluri' => true,
|
||||
'method' => 'HEAD',
|
||||
],
|
||||
'socket' => [
|
||||
'bindto' => '127.0.0.1:0',
|
||||
],
|
||||
'ssl' => [
|
||||
'verify_peer' => false,
|
||||
],
|
||||
],
|
||||
]);
|
||||
$opts = stream_context_get_options($res->getBody()->detach());
|
||||
self::assertSame('HEAD', $opts['http']['method']);
|
||||
self::assertTrue($opts['http']['request_fulluri']);
|
||||
self::assertSame('127.0.0.1:0', $opts['socket']['bindto']);
|
||||
self::assertFalse($opts['ssl']['verify_peer']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \InvalidArgumentException
|
||||
* @expectedExceptionMessage stream_context must be an array
|
||||
*/
|
||||
public function testEnsuresThatStreamContextIsAnArray()
|
||||
{
|
||||
$this->getSendResult(['stream_context' => 'foo']);
|
||||
}
|
||||
|
||||
public function testDoesNotAddContentTypeByDefault()
|
||||
{
|
||||
$this->queueRes();
|
||||
$handler = new StreamHandler();
|
||||
$request = new Request('PUT', Server::$url, ['Content-Length' => 3], 'foo');
|
||||
$handler($request, []);
|
||||
$req = Server::received()[0];
|
||||
self::assertEquals('', $req->getHeaderLine('Content-Type'));
|
||||
self::assertEquals(3, $req->getHeaderLine('Content-Length'));
|
||||
}
|
||||
|
||||
public function testAddsContentLengthByDefault()
|
||||
{
|
||||
$this->queueRes();
|
||||
$handler = new StreamHandler();
|
||||
$request = new Request('PUT', Server::$url, [], 'foo');
|
||||
$handler($request, []);
|
||||
$req = Server::received()[0];
|
||||
self::assertEquals(3, $req->getHeaderLine('Content-Length'));
|
||||
}
|
||||
|
||||
public function testAddsContentLengthEvenWhenEmpty()
|
||||
{
|
||||
$this->queueRes();
|
||||
$handler = new StreamHandler();
|
||||
$request = new Request('PUT', Server::$url, [], '');
|
||||
$handler($request, []);
|
||||
$req = Server::received()[0];
|
||||
self::assertEquals(0, $req->getHeaderLine('Content-Length'));
|
||||
}
|
||||
|
||||
public function testSupports100Continue()
|
||||
{
|
||||
Server::flush();
|
||||
$response = new Response(200, ['Test' => 'Hello', 'Content-Length' => '4'], 'test');
|
||||
Server::enqueue([$response]);
|
||||
$request = new Request('PUT', Server::$url, ['Expect' => '100-Continue'], 'test');
|
||||
$handler = new StreamHandler();
|
||||
$response = $handler($request, [])->wait();
|
||||
self::assertSame(200, $response->getStatusCode());
|
||||
self::assertSame('Hello', $response->getHeaderLine('Test'));
|
||||
self::assertSame('4', $response->getHeaderLine('Content-Length'));
|
||||
self::assertSame('test', (string) $response->getBody());
|
||||
}
|
||||
|
||||
public function testDoesSleep()
|
||||
{
|
||||
$response = new response(200);
|
||||
Server::enqueue([$response]);
|
||||
$a = new StreamHandler();
|
||||
$request = new Request('GET', Server::$url);
|
||||
$s = Utils::currentTime();
|
||||
$a($request, ['delay' => 0.1])->wait();
|
||||
self::assertGreaterThan(0.0001, Utils::currentTime() - $s);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \InvalidArgumentException
|
||||
*/
|
||||
public function testEnsuresOnHeadersIsCallable()
|
||||
{
|
||||
$req = new Request('GET', Server::$url);
|
||||
$handler = new StreamHandler();
|
||||
$handler($req, ['on_headers' => 'error!']);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \GuzzleHttp\Exception\RequestException
|
||||
* @expectedExceptionMessage An error was encountered during the on_headers event
|
||||
* @expectedExceptionMessage test
|
||||
*/
|
||||
public function testRejectsPromiseWhenOnHeadersFails()
|
||||
{
|
||||
Server::flush();
|
||||
Server::enqueue([
|
||||
new Response(200, ['X-Foo' => 'bar'], 'abc 123')
|
||||
]);
|
||||
$req = new Request('GET', Server::$url);
|
||||
$handler = new StreamHandler();
|
||||
$promise = $handler($req, [
|
||||
'on_headers' => function () {
|
||||
throw new \Exception('test');
|
||||
}
|
||||
]);
|
||||
$promise->wait();
|
||||
}
|
||||
|
||||
public function testSuccessfullyCallsOnHeadersBeforeWritingToSink()
|
||||
{
|
||||
Server::flush();
|
||||
Server::enqueue([
|
||||
new Response(200, ['X-Foo' => 'bar'], 'abc 123')
|
||||
]);
|
||||
$req = new Request('GET', Server::$url);
|
||||
$got = null;
|
||||
|
||||
$stream = Psr7\stream_for();
|
||||
$stream = FnStream::decorate($stream, [
|
||||
'write' => function ($data) use ($stream, &$got) {
|
||||
self::assertNotNull($got);
|
||||
return $stream->write($data);
|
||||
}
|
||||
]);
|
||||
|
||||
$handler = new StreamHandler();
|
||||
$promise = $handler($req, [
|
||||
'sink' => $stream,
|
||||
'on_headers' => function (ResponseInterface $res) use (&$got) {
|
||||
$got = $res;
|
||||
self::assertSame('bar', $res->getHeaderLine('X-Foo'));
|
||||
}
|
||||
]);
|
||||
|
||||
$response = $promise->wait();
|
||||
self::assertSame(200, $response->getStatusCode());
|
||||
self::assertSame('bar', $response->getHeaderLine('X-Foo'));
|
||||
self::assertSame('abc 123', (string) $response->getBody());
|
||||
}
|
||||
|
||||
public function testInvokesOnStatsOnSuccess()
|
||||
{
|
||||
Server::flush();
|
||||
Server::enqueue([new Psr7\Response(200)]);
|
||||
$req = new Psr7\Request('GET', Server::$url);
|
||||
$gotStats = null;
|
||||
$handler = new StreamHandler();
|
||||
$promise = $handler($req, [
|
||||
'on_stats' => function (TransferStats $stats) use (&$gotStats) {
|
||||
$gotStats = $stats;
|
||||
}
|
||||
]);
|
||||
$response = $promise->wait();
|
||||
self::assertSame(200, $response->getStatusCode());
|
||||
self::assertSame(200, $gotStats->getResponse()->getStatusCode());
|
||||
self::assertSame(
|
||||
Server::$url,
|
||||
(string) $gotStats->getEffectiveUri()
|
||||
);
|
||||
self::assertSame(
|
||||
Server::$url,
|
||||
(string) $gotStats->getRequest()->getUri()
|
||||
);
|
||||
self::assertGreaterThan(0, $gotStats->getTransferTime());
|
||||
}
|
||||
|
||||
public function testInvokesOnStatsOnError()
|
||||
{
|
||||
$req = new Psr7\Request('GET', 'http://127.0.0.1:123');
|
||||
$gotStats = null;
|
||||
$handler = new StreamHandler();
|
||||
$promise = $handler($req, [
|
||||
'connect_timeout' => 0.001,
|
||||
'timeout' => 0.001,
|
||||
'on_stats' => function (TransferStats $stats) use (&$gotStats) {
|
||||
$gotStats = $stats;
|
||||
}
|
||||
]);
|
||||
$promise->wait(false);
|
||||
self::assertFalse($gotStats->hasResponse());
|
||||
self::assertSame(
|
||||
'http://127.0.0.1:123',
|
||||
(string) $gotStats->getEffectiveUri()
|
||||
);
|
||||
self::assertSame(
|
||||
'http://127.0.0.1:123',
|
||||
(string) $gotStats->getRequest()->getUri()
|
||||
);
|
||||
self::assertInternalType('float', $gotStats->getTransferTime());
|
||||
self::assertInstanceOf(
|
||||
ConnectException::class,
|
||||
$gotStats->getHandlerErrorData()
|
||||
);
|
||||
}
|
||||
|
||||
public function testStreamIgnoresZeroTimeout()
|
||||
{
|
||||
Server::flush();
|
||||
Server::enqueue([new Psr7\Response(200)]);
|
||||
$req = new Psr7\Request('GET', Server::$url);
|
||||
$gotStats = null;
|
||||
$handler = new StreamHandler();
|
||||
$promise = $handler($req, [
|
||||
'connect_timeout' => 10,
|
||||
'timeout' => 0
|
||||
]);
|
||||
$response = $promise->wait();
|
||||
self::assertSame(200, $response->getStatusCode());
|
||||
}
|
||||
|
||||
public function testDrainsResponseAndReadsAllContentWhenContentLengthIsZero()
|
||||
{
|
||||
Server::flush();
|
||||
Server::enqueue([
|
||||
new Response(200, [
|
||||
'Foo' => 'Bar',
|
||||
'Content-Length' => '0',
|
||||
], 'hi there... This has a lot of data!')
|
||||
]);
|
||||
$handler = new StreamHandler();
|
||||
$request = new Request('GET', Server::$url);
|
||||
$response = $handler($request, [])->wait();
|
||||
$body = $response->getBody();
|
||||
$stream = $body->detach();
|
||||
self::assertSame('hi there... This has a lot of data!', stream_get_contents($stream));
|
||||
fclose($stream);
|
||||
}
|
||||
|
||||
public function testHonorsReadTimeout()
|
||||
{
|
||||
Server::flush();
|
||||
$handler = new StreamHandler();
|
||||
$response = $handler(
|
||||
new Request('GET', Server::$url . 'guzzle-server/read-timeout'),
|
||||
[
|
||||
RequestOptions::READ_TIMEOUT => 1,
|
||||
RequestOptions::STREAM => true,
|
||||
]
|
||||
)->wait();
|
||||
self::assertSame(200, $response->getStatusCode());
|
||||
self::assertSame('OK', $response->getReasonPhrase());
|
||||
$body = $response->getBody()->detach();
|
||||
$line = fgets($body);
|
||||
self::assertSame("sleeping 60 seconds ...\n", $line);
|
||||
$line = fgets($body);
|
||||
self::assertFalse($line);
|
||||
self::assertTrue(stream_get_meta_data($body)['timed_out']);
|
||||
self::assertFalse(feof($body));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,214 @@
|
||||
<?php
|
||||
namespace GuzzleHttp\Tests;
|
||||
|
||||
use GuzzleHttp\Cookie\CookieJar;
|
||||
use GuzzleHttp\Handler\MockHandler;
|
||||
use GuzzleHttp\HandlerStack;
|
||||
use GuzzleHttp\Psr7\Request;
|
||||
use GuzzleHttp\Psr7\Response;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class HandlerStackTest extends TestCase
|
||||
{
|
||||
public function testSetsHandlerInCtor()
|
||||
{
|
||||
$f = function () {
|
||||
};
|
||||
$m1 = function () {
|
||||
};
|
||||
$h = new HandlerStack($f, [$m1]);
|
||||
self::assertTrue($h->hasHandler());
|
||||
}
|
||||
|
||||
/**
|
||||
* @doesNotPerformAssertions
|
||||
*/
|
||||
public function testCanSetDifferentHandlerAfterConstruction()
|
||||
{
|
||||
$f = function () {
|
||||
};
|
||||
$h = new HandlerStack();
|
||||
$h->setHandler($f);
|
||||
$h->resolve();
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \LogicException
|
||||
*/
|
||||
public function testEnsuresHandlerIsSet()
|
||||
{
|
||||
$h = new HandlerStack();
|
||||
$h->resolve();
|
||||
}
|
||||
|
||||
public function testPushInOrder()
|
||||
{
|
||||
$meths = $this->getFunctions();
|
||||
$builder = new HandlerStack();
|
||||
$builder->setHandler($meths[1]);
|
||||
$builder->push($meths[2]);
|
||||
$builder->push($meths[3]);
|
||||
$builder->push($meths[4]);
|
||||
$composed = $builder->resolve();
|
||||
self::assertSame('Hello - test123', $composed('test'));
|
||||
self::assertSame(
|
||||
[['a', 'test'], ['b', 'test1'], ['c', 'test12']],
|
||||
$meths[0]
|
||||
);
|
||||
}
|
||||
|
||||
public function testUnshiftsInReverseOrder()
|
||||
{
|
||||
$meths = $this->getFunctions();
|
||||
$builder = new HandlerStack();
|
||||
$builder->setHandler($meths[1]);
|
||||
$builder->unshift($meths[2]);
|
||||
$builder->unshift($meths[3]);
|
||||
$builder->unshift($meths[4]);
|
||||
$composed = $builder->resolve();
|
||||
self::assertSame('Hello - test321', $composed('test'));
|
||||
self::assertSame(
|
||||
[['c', 'test'], ['b', 'test3'], ['a', 'test32']],
|
||||
$meths[0]
|
||||
);
|
||||
}
|
||||
|
||||
public function testCanRemoveMiddlewareByInstance()
|
||||
{
|
||||
$meths = $this->getFunctions();
|
||||
$builder = new HandlerStack();
|
||||
$builder->setHandler($meths[1]);
|
||||
$builder->push($meths[2]);
|
||||
$builder->push($meths[2]);
|
||||
$builder->push($meths[3]);
|
||||
$builder->push($meths[4]);
|
||||
$builder->push($meths[2]);
|
||||
$builder->remove($meths[3]);
|
||||
$composed = $builder->resolve();
|
||||
self::assertSame('Hello - test1131', $composed('test'));
|
||||
}
|
||||
|
||||
public function testCanPrintMiddleware()
|
||||
{
|
||||
$meths = $this->getFunctions();
|
||||
$builder = new HandlerStack();
|
||||
$builder->setHandler($meths[1]);
|
||||
$builder->push($meths[2], 'a');
|
||||
$builder->push([__CLASS__, 'foo']);
|
||||
$builder->push([$this, 'bar']);
|
||||
$builder->push(__CLASS__ . '::' . 'foo');
|
||||
$lines = explode("\n", (string) $builder);
|
||||
self::assertContains("> 4) Name: 'a', Function: callable(", $lines[0]);
|
||||
self::assertContains("> 3) Name: '', Function: callable(GuzzleHttp\\Tests\\HandlerStackTest::foo)", $lines[1]);
|
||||
self::assertContains("> 2) Name: '', Function: callable(['GuzzleHttp\\Tests\\HandlerStackTest', 'bar'])", $lines[2]);
|
||||
self::assertContains("> 1) Name: '', Function: callable(GuzzleHttp\\Tests\\HandlerStackTest::foo)", $lines[3]);
|
||||
self::assertContains("< 0) Handler: callable(", $lines[4]);
|
||||
self::assertContains("< 1) Name: '', Function: callable(GuzzleHttp\\Tests\\HandlerStackTest::foo)", $lines[5]);
|
||||
self::assertContains("< 2) Name: '', Function: callable(['GuzzleHttp\\Tests\\HandlerStackTest', 'bar'])", $lines[6]);
|
||||
self::assertContains("< 3) Name: '', Function: callable(GuzzleHttp\\Tests\\HandlerStackTest::foo)", $lines[7]);
|
||||
self::assertContains("< 4) Name: 'a', Function: callable(", $lines[8]);
|
||||
}
|
||||
|
||||
public function testCanAddBeforeByName()
|
||||
{
|
||||
$meths = $this->getFunctions();
|
||||
$builder = new HandlerStack();
|
||||
$builder->setHandler($meths[1]);
|
||||
$builder->push($meths[2], 'foo');
|
||||
$builder->before('foo', $meths[3], 'baz');
|
||||
$builder->before('baz', $meths[4], 'bar');
|
||||
$builder->before('baz', $meths[4], 'qux');
|
||||
$lines = explode("\n", (string) $builder);
|
||||
self::assertContains('> 4) Name: \'bar\'', $lines[0]);
|
||||
self::assertContains('> 3) Name: \'qux\'', $lines[1]);
|
||||
self::assertContains('> 2) Name: \'baz\'', $lines[2]);
|
||||
self::assertContains('> 1) Name: \'foo\'', $lines[3]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \InvalidArgumentException
|
||||
*/
|
||||
public function testEnsuresHandlerExistsByName()
|
||||
{
|
||||
$builder = new HandlerStack();
|
||||
$builder->before('foo', function () {
|
||||
});
|
||||
}
|
||||
|
||||
public function testCanAddAfterByName()
|
||||
{
|
||||
$meths = $this->getFunctions();
|
||||
$builder = new HandlerStack();
|
||||
$builder->setHandler($meths[1]);
|
||||
$builder->push($meths[2], 'a');
|
||||
$builder->push($meths[3], 'b');
|
||||
$builder->after('a', $meths[4], 'c');
|
||||
$builder->after('b', $meths[4], 'd');
|
||||
$lines = explode("\n", (string) $builder);
|
||||
self::assertContains('4) Name: \'a\'', $lines[0]);
|
||||
self::assertContains('3) Name: \'c\'', $lines[1]);
|
||||
self::assertContains('2) Name: \'b\'', $lines[2]);
|
||||
self::assertContains('1) Name: \'d\'', $lines[3]);
|
||||
}
|
||||
|
||||
public function testPicksUpCookiesFromRedirects()
|
||||
{
|
||||
$mock = new MockHandler([
|
||||
new Response(301, [
|
||||
'Location' => 'http://foo.com/baz',
|
||||
'Set-Cookie' => 'foo=bar; Domain=foo.com'
|
||||
]),
|
||||
new Response(200)
|
||||
]);
|
||||
$handler = HandlerStack::create($mock);
|
||||
$request = new Request('GET', 'http://foo.com/bar');
|
||||
$jar = new CookieJar();
|
||||
$response = $handler($request, [
|
||||
'allow_redirects' => true,
|
||||
'cookies' => $jar
|
||||
])->wait();
|
||||
self::assertSame(200, $response->getStatusCode());
|
||||
$lastRequest = $mock->getLastRequest();
|
||||
self::assertSame('http://foo.com/baz', (string) $lastRequest->getUri());
|
||||
self::assertSame('foo=bar', $lastRequest->getHeaderLine('Cookie'));
|
||||
}
|
||||
|
||||
private function getFunctions()
|
||||
{
|
||||
$calls = [];
|
||||
|
||||
$a = function (callable $next) use (&$calls) {
|
||||
return function ($v) use ($next, &$calls) {
|
||||
$calls[] = ['a', $v];
|
||||
return $next($v . '1');
|
||||
};
|
||||
};
|
||||
|
||||
$b = function (callable $next) use (&$calls) {
|
||||
return function ($v) use ($next, &$calls) {
|
||||
$calls[] = ['b', $v];
|
||||
return $next($v . '2');
|
||||
};
|
||||
};
|
||||
|
||||
$c = function (callable $next) use (&$calls) {
|
||||
return function ($v) use ($next, &$calls) {
|
||||
$calls[] = ['c', $v];
|
||||
return $next($v . '3');
|
||||
};
|
||||
};
|
||||
|
||||
$handler = function ($v) {
|
||||
return 'Hello - ' . $v;
|
||||
};
|
||||
|
||||
return [&$calls, $handler, $a, $b, $c];
|
||||
}
|
||||
|
||||
public static function foo()
|
||||
{
|
||||
}
|
||||
public function bar()
|
||||
{
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,21 @@
|
||||
<?php
|
||||
namespace GuzzleHttp\Test;
|
||||
|
||||
use GuzzleHttp\Psr7;
|
||||
use GuzzleHttp\Utils;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class InternalUtilsTest extends TestCase
|
||||
{
|
||||
public function testCurrentTime()
|
||||
{
|
||||
self::assertGreaterThan(0, Utils::currentTime());
|
||||
}
|
||||
|
||||
public function testIdnConvert()
|
||||
{
|
||||
$uri = Psr7\uri_for('https://яндекс.рф/images');
|
||||
$uri = Utils::idnUriConvert($uri);
|
||||
self::assertSame('xn--d1acpjx3f.xn--p1ai', $uri->getHost());
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,93 @@
|
||||
<?php
|
||||
namespace GuzzleHttp\Tests;
|
||||
|
||||
use GuzzleHttp\Exception\RequestException;
|
||||
use GuzzleHttp\MessageFormatter;
|
||||
use GuzzleHttp\Psr7;
|
||||
use GuzzleHttp\Psr7\Request;
|
||||
use GuzzleHttp\Psr7\Response;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
/**
|
||||
* @covers GuzzleHttp\MessageFormatter
|
||||
*/
|
||||
class MessageFormatterTest extends TestCase
|
||||
{
|
||||
public function testCreatesWithClfByDefault()
|
||||
{
|
||||
$f = new MessageFormatter();
|
||||
self::assertEquals(MessageFormatter::CLF, self::readAttribute($f, 'template'));
|
||||
$f = new MessageFormatter(null);
|
||||
self::assertEquals(MessageFormatter::CLF, self::readAttribute($f, 'template'));
|
||||
}
|
||||
|
||||
public function dateProvider()
|
||||
{
|
||||
return [
|
||||
['{ts}', '/^[0-9]{4}\-[0-9]{2}\-[0-9]{2}/'],
|
||||
['{date_iso_8601}', '/^[0-9]{4}\-[0-9]{2}\-[0-9]{2}/'],
|
||||
['{date_common_log}', '/^\d\d\/[A-Z][a-z]{2}\/[0-9]{4}/']
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider dateProvider
|
||||
*/
|
||||
public function testFormatsTimestamps($format, $pattern)
|
||||
{
|
||||
$f = new MessageFormatter($format);
|
||||
$request = new Request('GET', '/');
|
||||
$result = $f->format($request);
|
||||
self::assertRegExp($pattern, $result);
|
||||
}
|
||||
|
||||
public function formatProvider()
|
||||
{
|
||||
$request = new Request('PUT', '/', ['x-test' => 'abc'], Psr7\stream_for('foo'));
|
||||
$response = new Response(200, ['X-Baz' => 'Bar'], Psr7\stream_for('baz'));
|
||||
$err = new RequestException('Test', $request, $response);
|
||||
|
||||
return [
|
||||
['{request}', [$request], Psr7\str($request)],
|
||||
['{response}', [$request, $response], Psr7\str($response)],
|
||||
['{request} {response}', [$request, $response], Psr7\str($request) . ' ' . Psr7\str($response)],
|
||||
// Empty response yields no value
|
||||
['{request} {response}', [$request], Psr7\str($request) . ' '],
|
||||
['{req_headers}', [$request], "PUT / HTTP/1.1\r\nx-test: abc"],
|
||||
['{res_headers}', [$request, $response], "HTTP/1.1 200 OK\r\nX-Baz: Bar"],
|
||||
['{res_headers}', [$request], 'NULL'],
|
||||
['{req_body}', [$request], 'foo'],
|
||||
['{res_body}', [$request, $response], 'baz'],
|
||||
['{res_body}', [$request], 'NULL'],
|
||||
['{method}', [$request], $request->getMethod()],
|
||||
['{url}', [$request], $request->getUri()],
|
||||
['{target}', [$request], $request->getRequestTarget()],
|
||||
['{req_version}', [$request], $request->getProtocolVersion()],
|
||||
['{res_version}', [$request, $response], $response->getProtocolVersion()],
|
||||
['{res_version}', [$request], 'NULL'],
|
||||
['{host}', [$request], $request->getHeaderLine('Host')],
|
||||
['{hostname}', [$request, $response], gethostname()],
|
||||
['{hostname}{hostname}', [$request, $response], gethostname() . gethostname()],
|
||||
['{code}', [$request, $response], $response->getStatusCode()],
|
||||
['{code}', [$request], 'NULL'],
|
||||
['{phrase}', [$request, $response], $response->getReasonPhrase()],
|
||||
['{phrase}', [$request], 'NULL'],
|
||||
['{error}', [$request, $response, $err], 'Test'],
|
||||
['{error}', [$request], 'NULL'],
|
||||
['{req_header_x-test}', [$request], 'abc'],
|
||||
['{req_header_x-not}', [$request], ''],
|
||||
['{res_header_X-Baz}', [$request, $response], 'Bar'],
|
||||
['{res_header_x-not}', [$request, $response], ''],
|
||||
['{res_header_X-Baz}', [$request], 'NULL'],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider formatProvider
|
||||
*/
|
||||
public function testFormatsMessages($template, $args, $result)
|
||||
{
|
||||
$f = new MessageFormatter($template);
|
||||
self::assertSame((string) $result, call_user_func_array([$f, 'format'], $args));
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,217 @@
|
||||
<?php
|
||||
namespace GuzzleHttp\Tests;
|
||||
|
||||
use GuzzleHttp\Cookie\CookieJar;
|
||||
use GuzzleHttp\Cookie\SetCookie;
|
||||
use GuzzleHttp\Exception\RequestException;
|
||||
use GuzzleHttp\Handler\MockHandler;
|
||||
use GuzzleHttp\HandlerStack;
|
||||
use GuzzleHttp\MessageFormatter;
|
||||
use GuzzleHttp\Middleware;
|
||||
use GuzzleHttp\Promise\PromiseInterface;
|
||||
use GuzzleHttp\Psr7\Request;
|
||||
use GuzzleHttp\Psr7\Response;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
use Psr\Log\Test\TestLogger;
|
||||
|
||||
class MiddlewareTest extends TestCase
|
||||
{
|
||||
public function testAddsCookiesToRequests()
|
||||
{
|
||||
$jar = new CookieJar();
|
||||
$m = Middleware::cookies($jar);
|
||||
$h = new MockHandler(
|
||||
[
|
||||
function (RequestInterface $request) {
|
||||
return new Response(200, [
|
||||
'Set-Cookie' => (string) new SetCookie([
|
||||
'Name' => 'name',
|
||||
'Value' => 'value',
|
||||
'Domain' => 'foo.com'
|
||||
])
|
||||
]);
|
||||
}
|
||||
]
|
||||
);
|
||||
$f = $m($h);
|
||||
$f(new Request('GET', 'http://foo.com'), ['cookies' => $jar])->wait();
|
||||
self::assertCount(1, $jar);
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \GuzzleHttp\Exception\ClientException
|
||||
*/
|
||||
public function testThrowsExceptionOnHttpClientError()
|
||||
{
|
||||
$m = Middleware::httpErrors();
|
||||
$h = new MockHandler([new Response(404)]);
|
||||
$f = $m($h);
|
||||
$p = $f(new Request('GET', 'http://foo.com'), ['http_errors' => true]);
|
||||
self::assertSame('pending', $p->getState());
|
||||
$p->wait();
|
||||
self::assertSame('rejected', $p->getState());
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \GuzzleHttp\Exception\ServerException
|
||||
*/
|
||||
public function testThrowsExceptionOnHttpServerError()
|
||||
{
|
||||
$m = Middleware::httpErrors();
|
||||
$h = new MockHandler([new Response(500)]);
|
||||
$f = $m($h);
|
||||
$p = $f(new Request('GET', 'http://foo.com'), ['http_errors' => true]);
|
||||
self::assertSame('pending', $p->getState());
|
||||
$p->wait();
|
||||
self::assertSame('rejected', $p->getState());
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider getHistoryUseCases
|
||||
*/
|
||||
public function testTracksHistory($container)
|
||||
{
|
||||
$m = Middleware::history($container);
|
||||
$h = new MockHandler([new Response(200), new Response(201)]);
|
||||
$f = $m($h);
|
||||
$p1 = $f(new Request('GET', 'http://foo.com'), ['headers' => ['foo' => 'bar']]);
|
||||
$p2 = $f(new Request('HEAD', 'http://foo.com'), ['headers' => ['foo' => 'baz']]);
|
||||
$p1->wait();
|
||||
$p2->wait();
|
||||
self::assertCount(2, $container);
|
||||
self::assertSame(200, $container[0]['response']->getStatusCode());
|
||||
self::assertSame(201, $container[1]['response']->getStatusCode());
|
||||
self::assertSame('GET', $container[0]['request']->getMethod());
|
||||
self::assertSame('HEAD', $container[1]['request']->getMethod());
|
||||
self::assertSame('bar', $container[0]['options']['headers']['foo']);
|
||||
self::assertSame('baz', $container[1]['options']['headers']['foo']);
|
||||
}
|
||||
|
||||
public function getHistoryUseCases()
|
||||
{
|
||||
return [
|
||||
[[]], // 1. Container is an array
|
||||
[new \ArrayObject()] // 2. Container is an ArrayObject
|
||||
];
|
||||
}
|
||||
|
||||
public function testTracksHistoryForFailures()
|
||||
{
|
||||
$container = [];
|
||||
$m = Middleware::history($container);
|
||||
$request = new Request('GET', 'http://foo.com');
|
||||
$h = new MockHandler([new RequestException('error', $request)]);
|
||||
$f = $m($h);
|
||||
$f($request, [])->wait(false);
|
||||
self::assertCount(1, $container);
|
||||
self::assertSame('GET', $container[0]['request']->getMethod());
|
||||
self::assertInstanceOf(RequestException::class, $container[0]['error']);
|
||||
}
|
||||
|
||||
public function testTapsBeforeAndAfter()
|
||||
{
|
||||
$calls = [];
|
||||
$m = function ($handler) use (&$calls) {
|
||||
return function ($request, $options) use ($handler, &$calls) {
|
||||
$calls[] = '2';
|
||||
return $handler($request, $options);
|
||||
};
|
||||
};
|
||||
|
||||
$m2 = Middleware::tap(
|
||||
function (RequestInterface $request, array $options) use (&$calls) {
|
||||
$calls[] = '1';
|
||||
},
|
||||
function (RequestInterface $request, array $options, PromiseInterface $p) use (&$calls) {
|
||||
$calls[] = '3';
|
||||
}
|
||||
);
|
||||
|
||||
$h = new MockHandler([new Response()]);
|
||||
$b = new HandlerStack($h);
|
||||
$b->push($m2);
|
||||
$b->push($m);
|
||||
$comp = $b->resolve();
|
||||
$p = $comp(new Request('GET', 'http://foo.com'), []);
|
||||
self::assertSame('123', implode('', $calls));
|
||||
self::assertInstanceOf(PromiseInterface::class, $p);
|
||||
self::assertSame(200, $p->wait()->getStatusCode());
|
||||
}
|
||||
|
||||
public function testMapsRequest()
|
||||
{
|
||||
$h = new MockHandler([
|
||||
function (RequestInterface $request, array $options) {
|
||||
self::assertSame('foo', $request->getHeaderLine('Bar'));
|
||||
return new Response(200);
|
||||
}
|
||||
]);
|
||||
$stack = new HandlerStack($h);
|
||||
$stack->push(Middleware::mapRequest(function (RequestInterface $request) {
|
||||
return $request->withHeader('Bar', 'foo');
|
||||
}));
|
||||
$comp = $stack->resolve();
|
||||
$p = $comp(new Request('PUT', 'http://www.google.com'), []);
|
||||
self::assertInstanceOf(PromiseInterface::class, $p);
|
||||
}
|
||||
|
||||
public function testMapsResponse()
|
||||
{
|
||||
$h = new MockHandler([new Response(200)]);
|
||||
$stack = new HandlerStack($h);
|
||||
$stack->push(Middleware::mapResponse(function (ResponseInterface $response) {
|
||||
return $response->withHeader('Bar', 'foo');
|
||||
}));
|
||||
$comp = $stack->resolve();
|
||||
$p = $comp(new Request('PUT', 'http://www.google.com'), []);
|
||||
$p->wait();
|
||||
self::assertSame('foo', $p->wait()->getHeaderLine('Bar'));
|
||||
}
|
||||
|
||||
public function testLogsRequestsAndResponses()
|
||||
{
|
||||
$h = new MockHandler([new Response(200)]);
|
||||
$stack = new HandlerStack($h);
|
||||
$logger = new TestLogger();
|
||||
$formatter = new MessageFormatter();
|
||||
$stack->push(Middleware::log($logger, $formatter));
|
||||
$comp = $stack->resolve();
|
||||
$p = $comp(new Request('PUT', 'http://www.google.com'), []);
|
||||
$p->wait();
|
||||
self::assertCount(1, $logger->records);
|
||||
self::assertContains('"PUT / HTTP/1.1" 200', $logger->records[0]['message']);
|
||||
}
|
||||
|
||||
public function testLogsRequestsAndResponsesCustomLevel()
|
||||
{
|
||||
$h = new MockHandler([new Response(200)]);
|
||||
$stack = new HandlerStack($h);
|
||||
$logger = new TestLogger();
|
||||
$formatter = new MessageFormatter();
|
||||
$stack->push(Middleware::log($logger, $formatter, 'debug'));
|
||||
$comp = $stack->resolve();
|
||||
$p = $comp(new Request('PUT', 'http://www.google.com'), []);
|
||||
$p->wait();
|
||||
self::assertCount(1, $logger->records);
|
||||
self::assertContains('"PUT / HTTP/1.1" 200', $logger->records[0]['message']);
|
||||
self::assertSame('debug', $logger->records[0]['level']);
|
||||
}
|
||||
|
||||
public function testLogsRequestsAndErrors()
|
||||
{
|
||||
$h = new MockHandler([new Response(404)]);
|
||||
$stack = new HandlerStack($h);
|
||||
$logger = new TestLogger();
|
||||
$formatter = new MessageFormatter('{code} {error}');
|
||||
$stack->push(Middleware::log($logger, $formatter));
|
||||
$stack->push(Middleware::httpErrors());
|
||||
$comp = $stack->resolve();
|
||||
$p = $comp(new Request('PUT', 'http://www.google.com'), ['http_errors' => true]);
|
||||
$p->wait(false);
|
||||
self::assertCount(1, $logger->records);
|
||||
self::assertContains('PUT http://www.google.com', $logger->records[0]['message']);
|
||||
self::assertContains('404 Not Found', $logger->records[0]['message']);
|
||||
}
|
||||
}
|
||||
193
wp-content/upgrade-temp-backup/plugins/w3-total-cache/vendor/guzzlehttp/guzzle/tests/PoolTest.php
vendored
Normal file
193
wp-content/upgrade-temp-backup/plugins/w3-total-cache/vendor/guzzlehttp/guzzle/tests/PoolTest.php
vendored
Normal file
@ -0,0 +1,193 @@
|
||||
<?php
|
||||
namespace GuzzleHttp\Tests;
|
||||
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\Exception\ClientException;
|
||||
use GuzzleHttp\Handler\MockHandler;
|
||||
use GuzzleHttp\HandlerStack;
|
||||
use GuzzleHttp\Pool;
|
||||
use GuzzleHttp\Promise\Promise;
|
||||
use GuzzleHttp\Psr7\Request;
|
||||
use GuzzleHttp\Psr7\Response;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
|
||||
class PoolTest extends TestCase
|
||||
{
|
||||
/**
|
||||
* @expectedException \InvalidArgumentException
|
||||
*/
|
||||
public function testValidatesIterable()
|
||||
{
|
||||
$p = new Pool(new Client(), 'foo');
|
||||
$p->promise()->wait();
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \InvalidArgumentException
|
||||
*/
|
||||
public function testValidatesEachElement()
|
||||
{
|
||||
$c = new Client();
|
||||
$requests = ['foo'];
|
||||
$p = new Pool($c, new \ArrayIterator($requests));
|
||||
$p->promise()->wait();
|
||||
}
|
||||
|
||||
/**
|
||||
* @doesNotPerformAssertions
|
||||
*/
|
||||
public function testSendsAndRealizesFuture()
|
||||
{
|
||||
$c = $this->getClient();
|
||||
$p = new Pool($c, [new Request('GET', 'http://example.com')]);
|
||||
$p->promise()->wait();
|
||||
}
|
||||
|
||||
/**
|
||||
* @doesNotPerformAssertions
|
||||
*/
|
||||
public function testExecutesPendingWhenWaiting()
|
||||
{
|
||||
$r1 = new Promise(function () use (&$r1) {
|
||||
$r1->resolve(new Response());
|
||||
});
|
||||
$r2 = new Promise(function () use (&$r2) {
|
||||
$r2->resolve(new Response());
|
||||
});
|
||||
$r3 = new Promise(function () use (&$r3) {
|
||||
$r3->resolve(new Response());
|
||||
});
|
||||
$handler = new MockHandler([$r1, $r2, $r3]);
|
||||
$c = new Client(['handler' => $handler]);
|
||||
$p = new Pool($c, [
|
||||
new Request('GET', 'http://example.com'),
|
||||
new Request('GET', 'http://example.com'),
|
||||
new Request('GET', 'http://example.com'),
|
||||
], ['pool_size' => 2]);
|
||||
$p->promise()->wait();
|
||||
}
|
||||
|
||||
public function testUsesRequestOptions()
|
||||
{
|
||||
$h = [];
|
||||
$handler = new MockHandler([
|
||||
function (RequestInterface $request) use (&$h) {
|
||||
$h[] = $request;
|
||||
return new Response();
|
||||
}
|
||||
]);
|
||||
$c = new Client(['handler' => $handler]);
|
||||
$opts = ['options' => ['headers' => ['x-foo' => 'bar']]];
|
||||
$p = new Pool($c, [new Request('GET', 'http://example.com')], $opts);
|
||||
$p->promise()->wait();
|
||||
self::assertCount(1, $h);
|
||||
self::assertTrue($h[0]->hasHeader('x-foo'));
|
||||
}
|
||||
|
||||
public function testCanProvideCallablesThatReturnResponses()
|
||||
{
|
||||
$h = [];
|
||||
$handler = new MockHandler([
|
||||
function (RequestInterface $request) use (&$h) {
|
||||
$h[] = $request;
|
||||
return new Response();
|
||||
}
|
||||
]);
|
||||
$c = new Client(['handler' => $handler]);
|
||||
$optHistory = [];
|
||||
$fn = function (array $opts) use (&$optHistory, $c) {
|
||||
$optHistory = $opts;
|
||||
return $c->request('GET', 'http://example.com', $opts);
|
||||
};
|
||||
$opts = ['options' => ['headers' => ['x-foo' => 'bar']]];
|
||||
$p = new Pool($c, [$fn], $opts);
|
||||
$p->promise()->wait();
|
||||
self::assertCount(1, $h);
|
||||
self::assertTrue($h[0]->hasHeader('x-foo'));
|
||||
}
|
||||
|
||||
public function testBatchesResults()
|
||||
{
|
||||
$requests = [
|
||||
new Request('GET', 'http://foo.com/200'),
|
||||
new Request('GET', 'http://foo.com/201'),
|
||||
new Request('GET', 'http://foo.com/202'),
|
||||
new Request('GET', 'http://foo.com/404'),
|
||||
];
|
||||
$fn = function (RequestInterface $request) {
|
||||
return new Response(substr($request->getUri()->getPath(), 1));
|
||||
};
|
||||
$mock = new MockHandler([$fn, $fn, $fn, $fn]);
|
||||
$handler = HandlerStack::create($mock);
|
||||
$client = new Client(['handler' => $handler]);
|
||||
$results = Pool::batch($client, $requests);
|
||||
self::assertCount(4, $results);
|
||||
self::assertSame([0, 1, 2, 3], array_keys($results));
|
||||
self::assertSame(200, $results[0]->getStatusCode());
|
||||
self::assertSame(201, $results[1]->getStatusCode());
|
||||
self::assertSame(202, $results[2]->getStatusCode());
|
||||
self::assertInstanceOf(ClientException::class, $results[3]);
|
||||
}
|
||||
|
||||
public function testBatchesResultsWithCallbacks()
|
||||
{
|
||||
$requests = [
|
||||
new Request('GET', 'http://foo.com/200'),
|
||||
new Request('GET', 'http://foo.com/201')
|
||||
];
|
||||
$mock = new MockHandler([
|
||||
function (RequestInterface $request) {
|
||||
return new Response(substr($request->getUri()->getPath(), 1));
|
||||
}
|
||||
]);
|
||||
$client = new Client(['handler' => $mock]);
|
||||
$results = Pool::batch($client, $requests, [
|
||||
'fulfilled' => function ($value) use (&$called) {
|
||||
$called = true;
|
||||
}
|
||||
]);
|
||||
self::assertCount(2, $results);
|
||||
self::assertTrue($called);
|
||||
}
|
||||
|
||||
public function testUsesYieldedKeyInFulfilledCallback()
|
||||
{
|
||||
$r1 = new Promise(function () use (&$r1) {
|
||||
$r1->resolve(new Response());
|
||||
});
|
||||
$r2 = new Promise(function () use (&$r2) {
|
||||
$r2->resolve(new Response());
|
||||
});
|
||||
$r3 = new Promise(function () use (&$r3) {
|
||||
$r3->resolve(new Response());
|
||||
});
|
||||
$handler = new MockHandler([$r1, $r2, $r3]);
|
||||
$c = new Client(['handler' => $handler]);
|
||||
$keys = [];
|
||||
$requests = [
|
||||
'request_1' => new Request('GET', 'http://example.com'),
|
||||
'request_2' => new Request('GET', 'http://example.com'),
|
||||
'request_3' => new Request('GET', 'http://example.com'),
|
||||
];
|
||||
$p = new Pool($c, $requests, [
|
||||
'pool_size' => 2,
|
||||
'fulfilled' => function ($res, $index) use (&$keys) {
|
||||
$keys[] = $index;
|
||||
}
|
||||
]);
|
||||
$p->promise()->wait();
|
||||
self::assertCount(3, $keys);
|
||||
self::assertSame($keys, array_keys($requests));
|
||||
}
|
||||
|
||||
private function getClient($total = 1)
|
||||
{
|
||||
$queue = [];
|
||||
for ($i = 0; $i < $total; $i++) {
|
||||
$queue[] = new Response();
|
||||
}
|
||||
$handler = new MockHandler($queue);
|
||||
return new Client(['handler' => $handler]);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,155 @@
|
||||
<?php
|
||||
namespace GuzzleHttp\Tests;
|
||||
|
||||
use GuzzleHttp\Handler\MockHandler;
|
||||
use GuzzleHttp\HandlerStack;
|
||||
use GuzzleHttp\Middleware;
|
||||
use GuzzleHttp\Promise\PromiseInterface;
|
||||
use GuzzleHttp\Psr7;
|
||||
use GuzzleHttp\Psr7\FnStream;
|
||||
use GuzzleHttp\Psr7\Request;
|
||||
use GuzzleHttp\Psr7\Response;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
|
||||
class PrepareBodyMiddlewareTest extends TestCase
|
||||
{
|
||||
public function methodProvider()
|
||||
{
|
||||
$methods = ['GET', 'PUT', 'POST'];
|
||||
$bodies = ['Test', ''];
|
||||
foreach ($methods as $method) {
|
||||
foreach ($bodies as $body) {
|
||||
yield [$method, $body];
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @dataProvider methodProvider
|
||||
*/
|
||||
public function testAddsContentLengthWhenMissingAndPossible($method, $body)
|
||||
{
|
||||
$h = new MockHandler([
|
||||
function (RequestInterface $request) use ($body) {
|
||||
$length = strlen($body);
|
||||
if ($length > 0) {
|
||||
self::assertEquals($length, $request->getHeaderLine('Content-Length'));
|
||||
} else {
|
||||
self::assertFalse($request->hasHeader('Content-Length'));
|
||||
}
|
||||
return new Response(200);
|
||||
}
|
||||
]);
|
||||
$m = Middleware::prepareBody();
|
||||
$stack = new HandlerStack($h);
|
||||
$stack->push($m);
|
||||
$comp = $stack->resolve();
|
||||
$p = $comp(new Request($method, 'http://www.google.com', [], $body), []);
|
||||
self::assertInstanceOf(PromiseInterface::class, $p);
|
||||
$response = $p->wait();
|
||||
self::assertSame(200, $response->getStatusCode());
|
||||
}
|
||||
|
||||
public function testAddsTransferEncodingWhenNoContentLength()
|
||||
{
|
||||
$body = FnStream::decorate(Psr7\stream_for('foo'), [
|
||||
'getSize' => function () {
|
||||
return null;
|
||||
}
|
||||
]);
|
||||
$h = new MockHandler([
|
||||
function (RequestInterface $request) {
|
||||
self::assertFalse($request->hasHeader('Content-Length'));
|
||||
self::assertSame('chunked', $request->getHeaderLine('Transfer-Encoding'));
|
||||
return new Response(200);
|
||||
}
|
||||
]);
|
||||
$m = Middleware::prepareBody();
|
||||
$stack = new HandlerStack($h);
|
||||
$stack->push($m);
|
||||
$comp = $stack->resolve();
|
||||
$p = $comp(new Request('PUT', 'http://www.google.com', [], $body), []);
|
||||
self::assertInstanceOf(PromiseInterface::class, $p);
|
||||
$response = $p->wait();
|
||||
self::assertSame(200, $response->getStatusCode());
|
||||
}
|
||||
|
||||
public function testAddsContentTypeWhenMissingAndPossible()
|
||||
{
|
||||
$bd = Psr7\stream_for(fopen(__DIR__ . '/../composer.json', 'r'));
|
||||
$h = new MockHandler([
|
||||
function (RequestInterface $request) {
|
||||
self::assertSame('application/json', $request->getHeaderLine('Content-Type'));
|
||||
self::assertTrue($request->hasHeader('Content-Length'));
|
||||
return new Response(200);
|
||||
}
|
||||
]);
|
||||
$m = Middleware::prepareBody();
|
||||
$stack = new HandlerStack($h);
|
||||
$stack->push($m);
|
||||
$comp = $stack->resolve();
|
||||
$p = $comp(new Request('PUT', 'http://www.google.com', [], $bd), []);
|
||||
self::assertInstanceOf(PromiseInterface::class, $p);
|
||||
$response = $p->wait();
|
||||
self::assertSame(200, $response->getStatusCode());
|
||||
}
|
||||
|
||||
public function expectProvider()
|
||||
{
|
||||
return [
|
||||
[true, ['100-Continue']],
|
||||
[false, []],
|
||||
[10, ['100-Continue']],
|
||||
[500000, []]
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider expectProvider
|
||||
*/
|
||||
public function testAddsExpect($value, $result)
|
||||
{
|
||||
$bd = Psr7\stream_for(fopen(__DIR__ . '/../composer.json', 'r'));
|
||||
|
||||
$h = new MockHandler([
|
||||
function (RequestInterface $request) use ($result) {
|
||||
self::assertSame($result, $request->getHeader('Expect'));
|
||||
return new Response(200);
|
||||
}
|
||||
]);
|
||||
|
||||
$m = Middleware::prepareBody();
|
||||
$stack = new HandlerStack($h);
|
||||
$stack->push($m);
|
||||
$comp = $stack->resolve();
|
||||
$p = $comp(new Request('PUT', 'http://www.google.com', [], $bd), [
|
||||
'expect' => $value
|
||||
]);
|
||||
self::assertInstanceOf(PromiseInterface::class, $p);
|
||||
$response = $p->wait();
|
||||
self::assertSame(200, $response->getStatusCode());
|
||||
}
|
||||
|
||||
public function testIgnoresIfExpectIsPresent()
|
||||
{
|
||||
$bd = Psr7\stream_for(fopen(__DIR__ . '/../composer.json', 'r'));
|
||||
$h = new MockHandler([
|
||||
function (RequestInterface $request) {
|
||||
self::assertSame(['Foo'], $request->getHeader('Expect'));
|
||||
return new Response(200);
|
||||
}
|
||||
]);
|
||||
|
||||
$m = Middleware::prepareBody();
|
||||
$stack = new HandlerStack($h);
|
||||
$stack->push($m);
|
||||
$comp = $stack->resolve();
|
||||
$p = $comp(
|
||||
new Request('PUT', 'http://www.google.com', ['Expect' => 'Foo'], $bd),
|
||||
['expect' => true]
|
||||
);
|
||||
self::assertInstanceOf(PromiseInterface::class, $p);
|
||||
$response = $p->wait();
|
||||
self::assertSame(200, $response->getStatusCode());
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,439 @@
|
||||
<?php
|
||||
namespace GuzzleHttp\Tests;
|
||||
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\Handler\MockHandler;
|
||||
use GuzzleHttp\HandlerStack;
|
||||
use GuzzleHttp\Middleware;
|
||||
use GuzzleHttp\Psr7\Request;
|
||||
use GuzzleHttp\Psr7\Response;
|
||||
use GuzzleHttp\RedirectMiddleware;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
use Psr\Http\Message\RequestInterface;
|
||||
|
||||
/**
|
||||
* @covers GuzzleHttp\RedirectMiddleware
|
||||
*/
|
||||
class RedirectMiddlewareTest extends TestCase
|
||||
{
|
||||
public function testIgnoresNonRedirects()
|
||||
{
|
||||
$response = new Response(200);
|
||||
$stack = new HandlerStack(new MockHandler([$response]));
|
||||
$stack->push(Middleware::redirect());
|
||||
$handler = $stack->resolve();
|
||||
$request = new Request('GET', 'http://example.com');
|
||||
$promise = $handler($request, []);
|
||||
$response = $promise->wait();
|
||||
self::assertSame(200, $response->getStatusCode());
|
||||
}
|
||||
|
||||
public function testIgnoresWhenNoLocation()
|
||||
{
|
||||
$response = new Response(304);
|
||||
$stack = new HandlerStack(new MockHandler([$response]));
|
||||
$stack->push(Middleware::redirect());
|
||||
$handler = $stack->resolve();
|
||||
$request = new Request('GET', 'http://example.com');
|
||||
$promise = $handler($request, []);
|
||||
$response = $promise->wait();
|
||||
self::assertSame(304, $response->getStatusCode());
|
||||
}
|
||||
|
||||
public function testRedirectsWithAbsoluteUri()
|
||||
{
|
||||
$mock = new MockHandler([
|
||||
new Response(302, ['Location' => 'http://test.com']),
|
||||
new Response(200)
|
||||
]);
|
||||
$stack = new HandlerStack($mock);
|
||||
$stack->push(Middleware::redirect());
|
||||
$handler = $stack->resolve();
|
||||
$request = new Request('GET', 'http://example.com?a=b');
|
||||
$promise = $handler($request, [
|
||||
'allow_redirects' => ['max' => 2]
|
||||
]);
|
||||
$response = $promise->wait();
|
||||
self::assertSame(200, $response->getStatusCode());
|
||||
self::assertSame('http://test.com', (string)$mock->getLastRequest()->getUri());
|
||||
}
|
||||
|
||||
public function testRedirectsWithRelativeUri()
|
||||
{
|
||||
$mock = new MockHandler([
|
||||
new Response(302, ['Location' => '/foo']),
|
||||
new Response(200)
|
||||
]);
|
||||
$stack = new HandlerStack($mock);
|
||||
$stack->push(Middleware::redirect());
|
||||
$handler = $stack->resolve();
|
||||
$request = new Request('GET', 'http://example.com?a=b');
|
||||
$promise = $handler($request, [
|
||||
'allow_redirects' => ['max' => 2]
|
||||
]);
|
||||
$response = $promise->wait();
|
||||
self::assertSame(200, $response->getStatusCode());
|
||||
self::assertSame('http://example.com/foo', (string)$mock->getLastRequest()->getUri());
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \GuzzleHttp\Exception\TooManyRedirectsException
|
||||
* @expectedExceptionMessage Will not follow more than 3 redirects
|
||||
*/
|
||||
public function testLimitsToMaxRedirects()
|
||||
{
|
||||
$mock = new MockHandler([
|
||||
new Response(301, ['Location' => 'http://test.com']),
|
||||
new Response(302, ['Location' => 'http://test.com']),
|
||||
new Response(303, ['Location' => 'http://test.com']),
|
||||
new Response(304, ['Location' => 'http://test.com'])
|
||||
]);
|
||||
$stack = new HandlerStack($mock);
|
||||
$stack->push(Middleware::redirect());
|
||||
$handler = $stack->resolve();
|
||||
$request = new Request('GET', 'http://example.com');
|
||||
$promise = $handler($request, ['allow_redirects' => ['max' => 3]]);
|
||||
$promise->wait();
|
||||
}
|
||||
|
||||
/**
|
||||
* @expectedException \GuzzleHttp\Exception\BadResponseException
|
||||
* @expectedExceptionMessage Redirect URI,
|
||||
*/
|
||||
public function testEnsuresProtocolIsValid()
|
||||
{
|
||||
$mock = new MockHandler([
|
||||
new Response(301, ['Location' => 'ftp://test.com'])
|
||||
]);
|
||||
$stack = new HandlerStack($mock);
|
||||
$stack->push(Middleware::redirect());
|
||||
$handler = $stack->resolve();
|
||||
$request = new Request('GET', 'http://example.com');
|
||||
$handler($request, ['allow_redirects' => ['max' => 3]])->wait();
|
||||
}
|
||||
|
||||
public function testAddsRefererHeader()
|
||||
{
|
||||
$mock = new MockHandler([
|
||||
new Response(302, ['Location' => 'http://test.com']),
|
||||
new Response(200)
|
||||
]);
|
||||
$stack = new HandlerStack($mock);
|
||||
$stack->push(Middleware::redirect());
|
||||
$handler = $stack->resolve();
|
||||
$request = new Request('GET', 'http://example.com?a=b');
|
||||
$promise = $handler($request, [
|
||||
'allow_redirects' => ['max' => 2, 'referer' => true]
|
||||
]);
|
||||
$promise->wait();
|
||||
self::assertSame(
|
||||
'http://example.com?a=b',
|
||||
$mock->getLastRequest()->getHeaderLine('Referer')
|
||||
);
|
||||
}
|
||||
|
||||
public function testAddsRefererHeaderButClearsUserInfo()
|
||||
{
|
||||
$mock = new MockHandler([
|
||||
new Response(302, ['Location' => 'http://test.com']),
|
||||
new Response(200)
|
||||
]);
|
||||
$stack = new HandlerStack($mock);
|
||||
$stack->push(Middleware::redirect());
|
||||
$handler = $stack->resolve();
|
||||
$request = new Request('GET', 'http://foo:bar@example.com?a=b');
|
||||
$promise = $handler($request, [
|
||||
'allow_redirects' => ['max' => 2, 'referer' => true]
|
||||
]);
|
||||
$promise->wait();
|
||||
self::assertSame(
|
||||
'http://example.com?a=b',
|
||||
$mock->getLastRequest()->getHeaderLine('Referer')
|
||||
);
|
||||
}
|
||||
|
||||
public function testAddsGuzzleRedirectHeader()
|
||||
{
|
||||
$mock = new MockHandler([
|
||||
new Response(302, ['Location' => 'http://example.com']),
|
||||
new Response(302, ['Location' => 'http://example.com/foo']),
|
||||
new Response(302, ['Location' => 'http://example.com/bar']),
|
||||
new Response(200)
|
||||
]);
|
||||
|
||||
$stack = new HandlerStack($mock);
|
||||
$stack->push(Middleware::redirect());
|
||||
$handler = $stack->resolve();
|
||||
$request = new Request('GET', 'http://example.com?a=b');
|
||||
$promise = $handler($request, [
|
||||
'allow_redirects' => ['track_redirects' => true]
|
||||
]);
|
||||
$response = $promise->wait(true);
|
||||
self::assertSame(
|
||||
[
|
||||
'http://example.com',
|
||||
'http://example.com/foo',
|
||||
'http://example.com/bar',
|
||||
],
|
||||
$response->getHeader(RedirectMiddleware::HISTORY_HEADER)
|
||||
);
|
||||
}
|
||||
|
||||
public function testAddsGuzzleRedirectStatusHeader()
|
||||
{
|
||||
$mock = new MockHandler([
|
||||
new Response(301, ['Location' => 'http://example.com']),
|
||||
new Response(302, ['Location' => 'http://example.com/foo']),
|
||||
new Response(301, ['Location' => 'http://example.com/bar']),
|
||||
new Response(302, ['Location' => 'http://example.com/baz']),
|
||||
new Response(200)
|
||||
]);
|
||||
|
||||
$stack = new HandlerStack($mock);
|
||||
$stack->push(Middleware::redirect());
|
||||
$handler = $stack->resolve();
|
||||
$request = new Request('GET', 'http://example.com?a=b');
|
||||
$promise = $handler($request, [
|
||||
'allow_redirects' => ['track_redirects' => true]
|
||||
]);
|
||||
$response = $promise->wait(true);
|
||||
self::assertSame(
|
||||
[
|
||||
'301',
|
||||
'302',
|
||||
'301',
|
||||
'302',
|
||||
],
|
||||
$response->getHeader(RedirectMiddleware::STATUS_HISTORY_HEADER)
|
||||
);
|
||||
}
|
||||
|
||||
public function testDoesNotAddRefererWhenGoingFromHttpsToHttp()
|
||||
{
|
||||
$mock = new MockHandler([
|
||||
new Response(302, ['Location' => 'http://test.com']),
|
||||
new Response(200)
|
||||
]);
|
||||
$stack = new HandlerStack($mock);
|
||||
$stack->push(Middleware::redirect());
|
||||
$handler = $stack->resolve();
|
||||
$request = new Request('GET', 'https://example.com?a=b');
|
||||
$promise = $handler($request, [
|
||||
'allow_redirects' => ['max' => 2, 'referer' => true]
|
||||
]);
|
||||
$promise->wait();
|
||||
self::assertFalse($mock->getLastRequest()->hasHeader('Referer'));
|
||||
}
|
||||
|
||||
public function testInvokesOnRedirectForRedirects()
|
||||
{
|
||||
$mock = new MockHandler([
|
||||
new Response(302, ['Location' => 'http://test.com']),
|
||||
new Response(200)
|
||||
]);
|
||||
$stack = new HandlerStack($mock);
|
||||
$stack->push(Middleware::redirect());
|
||||
$handler = $stack->resolve();
|
||||
$request = new Request('GET', 'http://example.com?a=b');
|
||||
$call = false;
|
||||
$promise = $handler($request, [
|
||||
'allow_redirects' => [
|
||||
'max' => 2,
|
||||
'on_redirect' => function ($request, $response, $uri) use (&$call) {
|
||||
self::assertSame(302, $response->getStatusCode());
|
||||
self::assertSame('GET', $request->getMethod());
|
||||
self::assertSame('http://test.com', (string) $uri);
|
||||
$call = true;
|
||||
}
|
||||
]
|
||||
]);
|
||||
$promise->wait();
|
||||
self::assertTrue($call);
|
||||
}
|
||||
|
||||
/**
|
||||
* @testWith ["digest"]
|
||||
* ["ntlm"]
|
||||
*/
|
||||
public function testRemoveCurlAuthorizationOptionsOnRedirectCrossHost($auth)
|
||||
{
|
||||
if (!defined('\CURLOPT_HTTPAUTH')) {
|
||||
self::markTestSkipped('ext-curl is required for this test');
|
||||
}
|
||||
|
||||
$mock = new MockHandler([
|
||||
new Response(302, ['Location' => 'http://test.com']),
|
||||
static function (RequestInterface $request, $options) {
|
||||
self::assertFalse(
|
||||
isset($options['curl'][\CURLOPT_HTTPAUTH]),
|
||||
'curl options still contain CURLOPT_HTTPAUTH entry'
|
||||
);
|
||||
self::assertFalse(
|
||||
isset($options['curl'][\CURLOPT_USERPWD]),
|
||||
'curl options still contain CURLOPT_USERPWD entry'
|
||||
);
|
||||
return new Response(200);
|
||||
}
|
||||
]);
|
||||
$handler = HandlerStack::create($mock);
|
||||
$client = new Client(['handler' => $handler]);
|
||||
$client->get('http://example.com?a=b', ['auth' => ['testuser', 'testpass', $auth]]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @testWith ["digest"]
|
||||
* ["ntlm"]
|
||||
*/
|
||||
public function testRemoveCurlAuthorizationOptionsOnRedirectCrossPort($auth)
|
||||
{
|
||||
if (!defined('\CURLOPT_HTTPAUTH')) {
|
||||
self::markTestSkipped('ext-curl is required for this test');
|
||||
}
|
||||
|
||||
$mock = new MockHandler([
|
||||
new Response(302, ['Location' => 'http://example.com:81/']),
|
||||
static function (RequestInterface $request, $options) {
|
||||
self::assertFalse(
|
||||
isset($options['curl'][\CURLOPT_HTTPAUTH]),
|
||||
'curl options still contain CURLOPT_HTTPAUTH entry'
|
||||
);
|
||||
self::assertFalse(
|
||||
isset($options['curl'][\CURLOPT_USERPWD]),
|
||||
'curl options still contain CURLOPT_USERPWD entry'
|
||||
);
|
||||
return new Response(200);
|
||||
}
|
||||
]);
|
||||
$handler = HandlerStack::create($mock);
|
||||
$client = new Client(['handler' => $handler]);
|
||||
$client->get('http://example.com?a=b', ['auth' => ['testuser', 'testpass', $auth]]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @testWith ["digest"]
|
||||
* ["ntlm"]
|
||||
*/
|
||||
public function testRemoveCurlAuthorizationOptionsOnRedirectCrossScheme($auth)
|
||||
{
|
||||
if (!defined('\CURLOPT_HTTPAUTH')) {
|
||||
self::markTestSkipped('ext-curl is required for this test');
|
||||
}
|
||||
|
||||
$mock = new MockHandler([
|
||||
new Response(302, ['Location' => 'http://example.com?a=b']),
|
||||
static function (RequestInterface $request, $options) {
|
||||
self::assertFalse(
|
||||
isset($options['curl'][\CURLOPT_HTTPAUTH]),
|
||||
'curl options still contain CURLOPT_HTTPAUTH entry'
|
||||
);
|
||||
self::assertFalse(
|
||||
isset($options['curl'][\CURLOPT_USERPWD]),
|
||||
'curl options still contain CURLOPT_USERPWD entry'
|
||||
);
|
||||
return new Response(200);
|
||||
}
|
||||
]);
|
||||
$handler = HandlerStack::create($mock);
|
||||
$client = new Client(['handler' => $handler]);
|
||||
$client->get('https://example.com?a=b', ['auth' => ['testuser', 'testpass', $auth]]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @testWith ["digest"]
|
||||
* ["ntlm"]
|
||||
*/
|
||||
public function testRemoveCurlAuthorizationOptionsOnRedirectCrossSchemeSamePort($auth)
|
||||
{
|
||||
if (!defined('\CURLOPT_HTTPAUTH')) {
|
||||
self::markTestSkipped('ext-curl is required for this test');
|
||||
}
|
||||
|
||||
$mock = new MockHandler([
|
||||
new Response(302, ['Location' => 'http://example.com:80?a=b']),
|
||||
static function (RequestInterface $request, $options) {
|
||||
self::assertFalse(
|
||||
isset($options['curl'][\CURLOPT_HTTPAUTH]),
|
||||
'curl options still contain CURLOPT_HTTPAUTH entry'
|
||||
);
|
||||
self::assertFalse(
|
||||
isset($options['curl'][\CURLOPT_USERPWD]),
|
||||
'curl options still contain CURLOPT_USERPWD entry'
|
||||
);
|
||||
return new Response(200);
|
||||
}
|
||||
]);
|
||||
$handler = HandlerStack::create($mock);
|
||||
$client = new Client(['handler' => $handler]);
|
||||
$client->get('https://example.com?a=b', ['auth' => ['testuser', 'testpass', $auth]]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @testWith ["digest"]
|
||||
* ["ntlm"]
|
||||
*/
|
||||
public function testNotRemoveCurlAuthorizationOptionsOnRedirect($auth)
|
||||
{
|
||||
if (!defined('\CURLOPT_HTTPAUTH') || !defined('\CURLOPT_USERPWD')) {
|
||||
self::markTestSkipped('ext-curl is required for this test');
|
||||
}
|
||||
|
||||
$mock = new MockHandler([
|
||||
new Response(302, ['Location' => 'http://example.com/2']),
|
||||
static function (RequestInterface $request, $options) {
|
||||
self::assertTrue(
|
||||
isset($options['curl'][\CURLOPT_HTTPAUTH]),
|
||||
'curl options does not contain expected CURLOPT_HTTPAUTH entry'
|
||||
);
|
||||
self::assertTrue(
|
||||
isset($options['curl'][\CURLOPT_USERPWD]),
|
||||
'curl options does not contain expected CURLOPT_USERPWD entry'
|
||||
);
|
||||
return new Response(200);
|
||||
}
|
||||
]);
|
||||
$handler = HandlerStack::create($mock);
|
||||
$client = new Client(['handler' => $handler]);
|
||||
$client->get('http://example.com?a=b', ['auth' => ['testuser', 'testpass', $auth]]);
|
||||
}
|
||||
|
||||
public function crossOriginRedirectProvider()
|
||||
{
|
||||
return [
|
||||
['http://example.com/123', 'http://example.com/', false],
|
||||
['http://example.com/123', 'http://example.com:80/', false],
|
||||
['http://example.com:80/123', 'http://example.com/', false],
|
||||
['http://example.com:80/123', 'http://example.com:80/', false],
|
||||
['http://example.com/123', 'https://example.com/', true],
|
||||
['http://example.com/123', 'http://www.example.com/', true],
|
||||
['http://example.com/123', 'http://example.com:81/', true],
|
||||
['http://example.com:80/123', 'http://example.com:81/', true],
|
||||
['https://example.com/123', 'https://example.com/', false],
|
||||
['https://example.com/123', 'https://example.com:443/', false],
|
||||
['https://example.com:443/123', 'https://example.com/', false],
|
||||
['https://example.com:443/123', 'https://example.com:443/', false],
|
||||
['https://example.com/123', 'http://example.com/', true],
|
||||
['https://example.com/123', 'https://www.example.com/', true],
|
||||
['https://example.com/123', 'https://example.com:444/', true],
|
||||
['https://example.com:443/123', 'https://example.com:444/', true],
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @dataProvider crossOriginRedirectProvider
|
||||
*/
|
||||
public function testHeadersTreatmentOnRedirect($originalUri, $targetUri, $isCrossOrigin)
|
||||
{
|
||||
$mock = new MockHandler([
|
||||
new Response(302, ['Location' => $targetUri]),
|
||||
function (RequestInterface $request) use ($isCrossOrigin) {
|
||||
self::assertSame(!$isCrossOrigin, $request->hasHeader('Authorization'));
|
||||
self::assertSame(!$isCrossOrigin, $request->hasHeader('Cookie'));
|
||||
|
||||
return new Response(200);
|
||||
}
|
||||
]);
|
||||
$handler = HandlerStack::create($mock);
|
||||
$client = new Client(['handler' => $handler]);
|
||||
$client->get($originalUri, ['auth' => ['testuser', 'testpass'], 'headers' => ['Cookie' => 'foo=bar']]);
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,81 @@
|
||||
<?php
|
||||
namespace GuzzleHttp\Tests;
|
||||
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\Handler\MockHandler;
|
||||
use GuzzleHttp\Middleware;
|
||||
use GuzzleHttp\Psr7;
|
||||
use GuzzleHttp\Psr7\Request;
|
||||
use GuzzleHttp\Psr7\Response;
|
||||
use GuzzleHttp\RetryMiddleware;
|
||||
use PHPUnit\Framework\TestCase;
|
||||
|
||||
class RetryMiddlewareTest extends TestCase
|
||||
{
|
||||
public function testRetriesWhenDeciderReturnsTrue()
|
||||
{
|
||||
$delayCalls = 0;
|
||||
$calls = [];
|
||||
$decider = function ($retries, $request, $response, $error) use (&$calls) {
|
||||
$calls[] = func_get_args();
|
||||
return count($calls) < 3;
|
||||
};
|
||||
$delay = function ($retries, $response) use (&$delayCalls) {
|
||||
$delayCalls++;
|
||||
self::assertSame($retries, $delayCalls);
|
||||
self::assertInstanceOf(Response::class, $response);
|
||||
return 1;
|
||||
};
|
||||
$m = Middleware::retry($decider, $delay);
|
||||
$h = new MockHandler([new Response(200), new Response(201), new Response(202)]);
|
||||
$f = $m($h);
|
||||
$c = new Client(['handler' => $f]);
|
||||
$p = $c->sendAsync(new Request('GET', 'http://test.com'), []);
|
||||
$p->wait();
|
||||
self::assertCount(3, $calls);
|
||||
self::assertSame(2, $delayCalls);
|
||||
self::assertSame(202, $p->wait()->getStatusCode());
|
||||
}
|
||||
|
||||
public function testDoesNotRetryWhenDeciderReturnsFalse()
|
||||
{
|
||||
$decider = function () {
|
||||
return false;
|
||||
};
|
||||
$m = Middleware::retry($decider);
|
||||
$h = new MockHandler([new Response(200)]);
|
||||
$c = new Client(['handler' => $m($h)]);
|
||||
$p = $c->sendAsync(new Request('GET', 'http://test.com'), []);
|
||||
self::assertSame(200, $p->wait()->getStatusCode());
|
||||
}
|
||||
|
||||
public function testCanRetryExceptions()
|
||||
{
|
||||
$calls = [];
|
||||
$decider = function ($retries, $request, $response, $error) use (&$calls) {
|
||||
$calls[] = func_get_args();
|
||||
return $error instanceof \Exception;
|
||||
};
|
||||
$m = Middleware::retry($decider);
|
||||
$h = new MockHandler([new \Exception(), new Response(201)]);
|
||||
$c = new Client(['handler' => $m($h)]);
|
||||
$p = $c->sendAsync(new Request('GET', 'http://test.com'), []);
|
||||
self::assertSame(201, $p->wait()->getStatusCode());
|
||||
self::assertCount(2, $calls);
|
||||
self::assertSame(0, $calls[0][0]);
|
||||
self::assertNull($calls[0][2]);
|
||||
self::assertInstanceOf('Exception', $calls[0][3]);
|
||||
self::assertSame(1, $calls[1][0]);
|
||||
self::assertInstanceOf(Response::class, $calls[1][2]);
|
||||
self::assertNull($calls[1][3]);
|
||||
}
|
||||
|
||||
public function testBackoffCalculateDelay()
|
||||
{
|
||||
self::assertSame(0, RetryMiddleware::exponentialDelay(0));
|
||||
self::assertSame(1000, RetryMiddleware::exponentialDelay(1));
|
||||
self::assertSame(2000, RetryMiddleware::exponentialDelay(2));
|
||||
self::assertSame(4000, RetryMiddleware::exponentialDelay(3));
|
||||
self::assertSame(8000, RetryMiddleware::exponentialDelay(4));
|
||||
}
|
||||
}
|
||||
174
wp-content/upgrade-temp-backup/plugins/w3-total-cache/vendor/guzzlehttp/guzzle/tests/Server.php
vendored
Normal file
174
wp-content/upgrade-temp-backup/plugins/w3-total-cache/vendor/guzzlehttp/guzzle/tests/Server.php
vendored
Normal file
@ -0,0 +1,174 @@
|
||||
<?php
|
||||
namespace GuzzleHttp\Tests;
|
||||
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\Psr7;
|
||||
use Psr\Http\Message\ResponseInterface;
|
||||
|
||||
/**
|
||||
* The Server class is used to control a scripted webserver using node.js that
|
||||
* will respond to HTTP requests with queued responses.
|
||||
*
|
||||
* Queued responses will be served to requests using a FIFO order. All requests
|
||||
* received by the server are stored on the node.js server and can be retrieved
|
||||
* by calling {@see Server::received()}.
|
||||
*
|
||||
* Mock responses that don't require data to be transmitted over HTTP a great
|
||||
* for testing. Mock response, however, cannot test the actual sending of an
|
||||
* HTTP request using cURL. This test server allows the simulation of any
|
||||
* number of HTTP request response transactions to test the actual sending of
|
||||
* requests over the wire without having to leave an internal network.
|
||||
*/
|
||||
class Server
|
||||
{
|
||||
/** @var Client */
|
||||
private static $client;
|
||||
private static $started = false;
|
||||
public static $url = 'http://127.0.0.1:8126/';
|
||||
public static $port = 8126;
|
||||
|
||||
/**
|
||||
* Flush the received requests from the server
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public static function flush()
|
||||
{
|
||||
return self::getClient()->request('DELETE', 'guzzle-server/requests');
|
||||
}
|
||||
|
||||
/**
|
||||
* Queue an array of responses or a single response on the server.
|
||||
*
|
||||
* Any currently queued responses will be overwritten. Subsequent requests
|
||||
* on the server will return queued responses in FIFO order.
|
||||
*
|
||||
* @param array|ResponseInterface $responses A single or array of Responses
|
||||
* to queue.
|
||||
* @throws \Exception
|
||||
*/
|
||||
public static function enqueue($responses)
|
||||
{
|
||||
$data = [];
|
||||
foreach ((array) $responses as $response) {
|
||||
if (!($response instanceof ResponseInterface)) {
|
||||
throw new \Exception('Invalid response given.');
|
||||
}
|
||||
$headers = array_map(function ($h) {
|
||||
return implode(' ,', $h);
|
||||
}, $response->getHeaders());
|
||||
|
||||
$data[] = [
|
||||
'status' => (string) $response->getStatusCode(),
|
||||
'reason' => $response->getReasonPhrase(),
|
||||
'headers' => $headers,
|
||||
'body' => base64_encode((string) $response->getBody())
|
||||
];
|
||||
}
|
||||
|
||||
self::getClient()->request('PUT', 'guzzle-server/responses', [
|
||||
'json' => $data
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all of the received requests
|
||||
*
|
||||
* @return ResponseInterface[]
|
||||
* @throws \RuntimeException
|
||||
*/
|
||||
public static function received()
|
||||
{
|
||||
if (!self::$started) {
|
||||
return [];
|
||||
}
|
||||
|
||||
$response = self::getClient()->request('GET', 'guzzle-server/requests');
|
||||
$data = json_decode($response->getBody(), true);
|
||||
|
||||
return array_map(
|
||||
function ($message) {
|
||||
$uri = $message['uri'];
|
||||
if (isset($message['query_string'])) {
|
||||
$uri .= '?' . $message['query_string'];
|
||||
}
|
||||
$response = new Psr7\Request(
|
||||
$message['http_method'],
|
||||
$uri,
|
||||
$message['headers'],
|
||||
$message['body'],
|
||||
$message['version']
|
||||
);
|
||||
return $response->withUri(
|
||||
$response->getUri()
|
||||
->withScheme('http')
|
||||
->withHost($response->getHeaderLine('host'))
|
||||
);
|
||||
},
|
||||
$data
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Stop running the node.js server
|
||||
*/
|
||||
public static function stop()
|
||||
{
|
||||
if (self::$started) {
|
||||
self::getClient()->request('DELETE', 'guzzle-server');
|
||||
}
|
||||
|
||||
self::$started = false;
|
||||
}
|
||||
|
||||
public static function wait($maxTries = 5)
|
||||
{
|
||||
$tries = 0;
|
||||
while (!self::isListening() && ++$tries < $maxTries) {
|
||||
usleep(100000);
|
||||
}
|
||||
|
||||
if (!self::isListening()) {
|
||||
throw new \RuntimeException('Unable to contact node.js server');
|
||||
}
|
||||
}
|
||||
|
||||
public static function start()
|
||||
{
|
||||
if (self::$started) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!self::isListening()) {
|
||||
exec('node ' . __DIR__ . '/server.js '
|
||||
. self::$port . ' >> /tmp/server.log 2>&1 &');
|
||||
self::wait();
|
||||
}
|
||||
|
||||
self::$started = true;
|
||||
}
|
||||
|
||||
private static function isListening()
|
||||
{
|
||||
try {
|
||||
self::getClient()->request('GET', 'guzzle-server/perf', [
|
||||
'connect_timeout' => 5,
|
||||
'timeout' => 5
|
||||
]);
|
||||
return true;
|
||||
} catch (\Exception $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private static function getClient()
|
||||
{
|
||||
if (!self::$client) {
|
||||
self::$client = new Client([
|
||||
'base_uri' => self::$url,
|
||||
'sync' => true,
|
||||
]);
|
||||
}
|
||||
|
||||
return self::$client;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user