/vendor/guzzlehttp/guzzle/src/Subscriber/Cookie.php |
@@ -0,0 +1,59 @@ |
<?php |
|
namespace GuzzleHttp\Subscriber; |
|
use GuzzleHttp\Cookie\CookieJar; |
use GuzzleHttp\Cookie\CookieJarInterface; |
use GuzzleHttp\Event\BeforeEvent; |
use GuzzleHttp\Event\CompleteEvent; |
use GuzzleHttp\Event\RequestEvents; |
use GuzzleHttp\Event\SubscriberInterface; |
|
/** |
* Adds, extracts, and persists cookies between HTTP requests |
*/ |
class Cookie implements SubscriberInterface |
{ |
/** @var CookieJarInterface */ |
private $cookieJar; |
|
/** |
* @param CookieJarInterface $cookieJar Cookie jar used to hold cookies |
*/ |
public function __construct(CookieJarInterface $cookieJar = null) |
{ |
$this->cookieJar = $cookieJar ?: new CookieJar(); |
} |
|
public function getEvents() |
{ |
// Fire the cookie plugin complete event before redirecting |
return [ |
'before' => ['onBefore'], |
'complete' => ['onComplete', RequestEvents::REDIRECT_RESPONSE + 10] |
]; |
} |
|
/** |
* Get the cookie cookieJar |
* |
* @return CookieJarInterface |
*/ |
public function getCookieJar() |
{ |
return $this->cookieJar; |
} |
|
public function onBefore(BeforeEvent $event) |
{ |
$this->cookieJar->addCookieHeader($event->getRequest()); |
} |
|
public function onComplete(CompleteEvent $event) |
{ |
$this->cookieJar->extractCookies( |
$event->getRequest(), |
$event->getResponse() |
); |
} |
} |
/vendor/guzzlehttp/guzzle/src/Subscriber/History.php |
@@ -0,0 +1,142 @@ |
<?php |
|
namespace GuzzleHttp\Subscriber; |
|
use GuzzleHttp\Event\CompleteEvent; |
use GuzzleHttp\Event\ErrorEvent; |
use GuzzleHttp\Event\RequestEvents; |
use GuzzleHttp\Event\SubscriberInterface; |
use GuzzleHttp\Message\RequestInterface; |
use GuzzleHttp\Message\ResponseInterface; |
|
/** |
* Maintains a list of requests and responses sent using a request or client |
*/ |
class History implements SubscriberInterface, \IteratorAggregate, \Countable |
{ |
/** @var int The maximum number of requests to maintain in the history */ |
private $limit; |
|
/** @var array Requests and responses that have passed through the plugin */ |
private $transactions = []; |
|
public function __construct($limit = 10) |
{ |
$this->limit = $limit; |
} |
|
public function getEvents() |
{ |
return [ |
'complete' => ['onComplete', RequestEvents::EARLY], |
'error' => ['onError', RequestEvents::EARLY], |
]; |
} |
|
/** |
* Convert to a string that contains all request and response headers |
* |
* @return string |
*/ |
public function __toString() |
{ |
$lines = array(); |
foreach ($this->transactions as $entry) { |
$response = isset($entry['response']) ? $entry['response'] : ''; |
$lines[] = '> ' . trim($entry['request']) . "\n\n< " . trim($response) . "\n"; |
} |
|
return implode("\n", $lines); |
} |
|
public function onComplete(CompleteEvent $event) |
{ |
$this->add($event->getRequest(), $event->getResponse()); |
} |
|
public function onError(ErrorEvent $event) |
{ |
// Only track when no response is present, meaning this didn't ever |
// emit a complete event |
if (!$event->getResponse()) { |
$this->add($event->getRequest()); |
} |
} |
|
/** |
* Returns an Iterator that yields associative array values where each |
* associative array contains a 'request' and 'response' key. |
* |
* @return \Iterator |
*/ |
public function getIterator() |
{ |
return new \ArrayIterator($this->transactions); |
} |
|
/** |
* Get all of the requests sent through the plugin |
* |
* @return RequestInterface[] |
*/ |
public function getRequests() |
{ |
return array_map(function ($t) { |
return $t['request']; |
}, $this->transactions); |
} |
|
/** |
* Get the number of requests in the history |
* |
* @return int |
*/ |
public function count() |
{ |
return count($this->transactions); |
} |
|
/** |
* Get the last request sent |
* |
* @return RequestInterface |
*/ |
public function getLastRequest() |
{ |
return end($this->transactions)['request']; |
} |
|
/** |
* Get the last response in the history |
* |
* @return ResponseInterface|null |
*/ |
public function getLastResponse() |
{ |
return end($this->transactions)['response']; |
} |
|
/** |
* Clears the history |
*/ |
public function clear() |
{ |
$this->transactions = array(); |
} |
|
/** |
* Add a request to the history |
* |
* @param RequestInterface $request Request to add |
* @param ResponseInterface $response Response of the request |
*/ |
private function add( |
RequestInterface $request, |
ResponseInterface $response = null |
) { |
$this->transactions[] = ['request' => $request, 'response' => $response]; |
if (count($this->transactions) > $this->limit) { |
array_shift($this->transactions); |
} |
} |
} |
/vendor/guzzlehttp/guzzle/src/Subscriber/Mock.php |
@@ -0,0 +1,143 @@ |
<?php |
|
namespace GuzzleHttp\Subscriber; |
|
use GuzzleHttp\Adapter\Transaction; |
use GuzzleHttp\Event\BeforeEvent; |
use GuzzleHttp\Event\HeadersEvent; |
use GuzzleHttp\Event\RequestEvents; |
use GuzzleHttp\Event\SubscriberInterface; |
use GuzzleHttp\Exception\RequestException; |
use GuzzleHttp\Message\MessageFactory; |
use GuzzleHttp\Message\ResponseInterface; |
|
/** |
* Queues mock responses or exceptions and delivers mock responses or |
* exceptions in a fifo order. |
*/ |
class Mock implements SubscriberInterface, \Countable |
{ |
/** @var array Array of mock responses / exceptions */ |
private $queue = []; |
|
/** @var bool Whether or not to consume an entity body when mocking */ |
private $readBodies; |
|
/** @var MessageFactory */ |
private $factory; |
|
/** |
* @param array $items Array of responses or exceptions to queue |
* @param bool $readBodies Set to false to not consume the entity body of |
* a request when a mock is served. |
*/ |
public function __construct(array $items = [], $readBodies = true) |
{ |
$this->factory = new MessageFactory(); |
$this->readBodies = $readBodies; |
$this->addMultiple($items); |
} |
|
public function getEvents() |
{ |
// Fire the event last, after signing |
return ['before' => ['onBefore', RequestEvents::SIGN_REQUEST - 10]]; |
} |
|
/** |
* @throws \OutOfBoundsException|\Exception |
*/ |
public function onBefore(BeforeEvent $event) |
{ |
if (!$item = array_shift($this->queue)) { |
throw new \OutOfBoundsException('Mock queue is empty'); |
} elseif ($item instanceof RequestException) { |
throw $item; |
} |
|
// Emulate the receiving of the response headers |
$request = $event->getRequest(); |
$transaction = new Transaction($event->getClient(), $request); |
$transaction->setResponse($item); |
$request->getEmitter()->emit( |
'headers', |
new HeadersEvent($transaction) |
); |
|
// Emulate reading a response body |
if ($this->readBodies && $request->getBody()) { |
while (!$request->getBody()->eof()) { |
$request->getBody()->read(8096); |
} |
} |
|
$event->intercept($item); |
} |
|
public function count() |
{ |
return count($this->queue); |
} |
|
/** |
* Add a response to the end of the queue |
* |
* @param string|ResponseInterface $response Response or path to response file |
* |
* @return self |
* @throws \InvalidArgumentException if a string or Response is not passed |
*/ |
public function addResponse($response) |
{ |
if (is_string($response)) { |
$response = file_exists($response) |
? $this->factory->fromMessage(file_get_contents($response)) |
: $this->factory->fromMessage($response); |
} elseif (!($response instanceof ResponseInterface)) { |
throw new \InvalidArgumentException('Response must a message ' |
. 'string, response object, or path to a file'); |
} |
|
$this->queue[] = $response; |
|
return $this; |
} |
|
/** |
* Add an exception to the end of the queue |
* |
* @param RequestException $e Exception to throw when the request is executed |
* |
* @return self |
*/ |
public function addException(RequestException $e) |
{ |
$this->queue[] = $e; |
|
return $this; |
} |
|
/** |
* Add multiple items to the queue |
* |
* @param array $items Items to add |
*/ |
public function addMultiple(array $items) |
{ |
foreach ($items as $item) { |
if ($item instanceof RequestException) { |
$this->addException($item); |
} else { |
$this->addResponse($item); |
} |
} |
} |
|
/** |
* Clear the queue |
*/ |
public function clearQueue() |
{ |
$this->queue = []; |
} |
} |
/vendor/guzzlehttp/guzzle/src/Subscriber/Prepare.php |
@@ -0,0 +1,136 @@ |
<?php |
|
namespace GuzzleHttp\Subscriber; |
|
use GuzzleHttp\Event\BeforeEvent; |
use GuzzleHttp\Event\RequestEvents; |
use GuzzleHttp\Event\SubscriberInterface; |
use GuzzleHttp\Message\RequestInterface; |
use GuzzleHttp\Mimetypes; |
use GuzzleHttp\Post\PostBodyInterface; |
use GuzzleHttp\Stream\MetadataStreamInterface; |
use GuzzleHttp\Stream\StreamInterface; |
|
/** |
* Prepares requests with a body before sending |
* |
* **Request Options** |
* |
* - expect: Set to true to enable the "Expect: 100-Continue" header for a |
* request that send a body. Set to false to disable "Expect: 100-Continue". |
* 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. |
*/ |
class Prepare implements SubscriberInterface |
{ |
public function getEvents() |
{ |
return ['before' => ['onBefore', RequestEvents::PREPARE_REQUEST]]; |
} |
|
public function onBefore(BeforeEvent $event) |
{ |
$request = $event->getRequest(); |
|
// Set the appropriate Content-Type for a request if one is not set and |
// there are form fields |
if (!($body = $request->getBody())) { |
return; |
} |
|
$this->addContentLength($request, $body); |
|
if ($body instanceof PostBodyInterface) { |
// Synchronize the POST body with the request's headers |
$body->applyRequestHeaders($request); |
} elseif (!$request->hasHeader('Content-Type')) { |
$this->addContentType($request, $body); |
} |
|
$this->addExpectHeader($request, $body); |
} |
|
private function addContentType( |
RequestInterface $request, |
StreamInterface $body |
) { |
if (!($body instanceof MetadataStreamInterface)) { |
return; |
} |
|
if (!($uri = $body->getMetadata('uri'))) { |
return; |
} |
|
// Guess the content-type based on the stream's "uri" metadata value. |
// The file extension is used to determine the appropriate mime-type. |
if ($contentType = Mimetypes::getInstance()->fromFilename($uri)) { |
$request->setHeader('Content-Type', $contentType); |
} |
} |
|
private function addContentLength( |
RequestInterface $request, |
StreamInterface $body |
) { |
// Set the Content-Length header if it can be determined, and never |
// send a Transfer-Encoding: chunked and Content-Length header in |
// the same request. |
if ($request->hasHeader('Content-Length')) { |
// Remove transfer-encoding if content-length is set. |
$request->removeHeader('Transfer-Encoding'); |
return; |
} |
|
if ($request->hasHeader('Transfer-Encoding')) { |
return; |
} |
|
if (null !== ($size = $body->getSize())) { |
$request->setHeader('Content-Length', $size) |
->removeHeader('Transfer-Encoding'); |
} elseif ('1.1' == $request->getProtocolVersion()) { |
// Use chunked Transfer-Encoding if there is no determinable |
// content-length header and we're using HTTP/1.1. |
$request->setHeader('Transfer-Encoding', 'chunked') |
->removeHeader('Content-Length'); |
} |
} |
|
private function addExpectHeader( |
RequestInterface $request, |
StreamInterface $body |
) { |
// Determine if the Expect header should be used |
if ($request->hasHeader('Expect')) { |
return; |
} |
|
$expect = $request->getConfig()['expect']; |
|
// Return if disabled or if you're not using HTTP/1.1 |
if ($expect === false || $request->getProtocolVersion() !== '1.1') { |
return; |
} |
|
// The expect header is unconditionally enabled |
if ($expect === true) { |
$request->setHeader('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 |
$size = $body->getSize(); |
if ($size === null || $size >= (int) $expect || !$body->isSeekable()) { |
$request->setHeader('Expect', '100-Continue'); |
} |
} |
} |
/vendor/guzzlehttp/guzzle/src/Subscriber/Redirect.php |
@@ -0,0 +1,172 @@ |
<?php |
|
namespace GuzzleHttp\Subscriber; |
|
use GuzzleHttp\Event\CompleteEvent; |
use GuzzleHttp\Event\RequestEvents; |
use GuzzleHttp\Event\SubscriberInterface; |
use GuzzleHttp\Exception\CouldNotRewindStreamException; |
use GuzzleHttp\Exception\TooManyRedirectsException; |
use GuzzleHttp\Message\RequestInterface; |
use GuzzleHttp\Message\ResponseInterface; |
use GuzzleHttp\Url; |
|
/** |
* Subscriber used to implement HTTP redirects. |
* |
* **Request options** |
* |
* - redirect: Associative array containing the 'max', 'strict', and 'referer' |
* keys. |
* |
* - max: Maximum number of redirects allowed per-request |
* - strict: You can use strict redirects by setting this value to ``true``. |
* Strict redirects adhere to strict RFC compliant redirection (e.g., |
* redirect POST with POST) vs doing what most clients do (e.g., redirect |
* POST request with a GET request). |
* - referer: Set to true to automatically add the "Referer" header when a |
* redirect request is sent. |
*/ |
class Redirect implements SubscriberInterface |
{ |
public function getEvents() |
{ |
return ['complete' => ['onComplete', RequestEvents::REDIRECT_RESPONSE]]; |
} |
|
/** |
* Rewind the entity body of the request if needed |
* |
* @param RequestInterface $redirectRequest |
* @throws CouldNotRewindStreamException |
*/ |
public static function rewindEntityBody(RequestInterface $redirectRequest) |
{ |
// Rewind the entity body of the request if needed |
if ($redirectRequest->getBody()) { |
$body = $redirectRequest->getBody(); |
// Only rewind the body if some of it has been read already, and |
// throw an exception if the rewind fails |
if ($body->tell() && !$body->seek(0)) { |
throw new CouldNotRewindStreamException( |
'Unable to rewind the non-seekable request body after redirecting', |
$redirectRequest |
); |
} |
} |
} |
|
/** |
* Called when a request receives a redirect response |
* |
* @param CompleteEvent $event Event emitted |
* @throws TooManyRedirectsException |
*/ |
public function onComplete(CompleteEvent $event) |
{ |
$response = $event->getResponse(); |
|
if (substr($response->getStatusCode(), 0, 1) != '3' || |
!$response->hasHeader('Location') |
) { |
return; |
} |
|
$redirectCount = 0; |
$redirectRequest = $event->getRequest(); |
$redirectResponse = $response; |
$max = $redirectRequest->getConfig()->getPath('redirect/max') ?: 5; |
|
do { |
if (++$redirectCount > $max) { |
throw new TooManyRedirectsException( |
"Will not follow more than {$redirectCount} redirects", |
$redirectRequest |
); |
} |
$redirectRequest = $this->createRedirectRequest($redirectRequest, $redirectResponse); |
$redirectResponse = $event->getClient()->send($redirectRequest); |
} while (substr($redirectResponse->getStatusCode(), 0, 1) == '3' && |
$redirectResponse->hasHeader('Location') |
); |
|
if ($redirectResponse !== $response) { |
$event->intercept($redirectResponse); |
} |
} |
|
/** |
* Create a redirect request for a specific request object |
* |
* Takes into account strict RFC compliant redirection (e.g. redirect POST |
* with POST) vs doing what most clients do (e.g. redirect POST with GET). |
* |
* @param RequestInterface $request |
* @param ResponseInterface $response |
* |
* @return RequestInterface Returns a new redirect request |
* @throws CouldNotRewindStreamException If the body cannot be rewound. |
*/ |
private function createRedirectRequest( |
RequestInterface $request, |
ResponseInterface $response |
) { |
$config = $request->getConfig(); |
|
// 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. Be sure to disable redirects on the clone. |
$redirectRequest = clone $request; |
$redirectRequest->getEmitter()->detach($this); |
$statusCode = $response->getStatusCode(); |
|
if ($statusCode == 303 || |
($statusCode <= 302 && $request->getBody() && |
!$config->getPath('redirect/strict')) |
) { |
$redirectRequest->setMethod('GET'); |
$redirectRequest->setBody(null); |
} |
|
$this->setRedirectUrl($redirectRequest, $response); |
$this->rewindEntityBody($redirectRequest); |
|
// 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 ($config->getPath('redirect/referer') && ( |
$redirectRequest->getScheme() == 'https' || |
$redirectRequest->getScheme() == $request->getScheme() |
)) { |
$url = Url::fromString($request->getUrl()); |
$url->setUsername(null)->setPassword(null); |
$redirectRequest->setHeader('Referer', (string) $url); |
} |
|
return $redirectRequest; |
} |
|
/** |
* Set the appropriate URL on the request based on the location header |
* |
* @param RequestInterface $redirectRequest |
* @param ResponseInterface $response |
*/ |
private function setRedirectUrl( |
RequestInterface $redirectRequest, |
ResponseInterface $response |
) { |
$location = $response->getHeader('Location'); |
$location = Url::fromString($location); |
|
// Combine location with the original URL if it is not absolute. |
if (!$location->isAbsolute()) { |
$originalUrl = Url::fromString($redirectRequest->getUrl()); |
// Remove query string parameters and just take what is present on |
// the redirect Location header |
$originalUrl->getQuery()->clear(); |
$location = $originalUrl->combine($location); |
} |
|
$redirectRequest->setUrl($location); |
} |
} |