diff --git a/composer.json b/composer.json index 4526a905060..d94ede28bbb 100644 --- a/composer.json +++ b/composer.json @@ -18,7 +18,7 @@ "twig/twig": "1.15.*", "doctrine/common": "dev-master#a45d110f71c323e29f41eb0696fa230e3fa1b1b5", "doctrine/annotations": "dev-master#463d926a8dcc49271cb7db5a08364a70ed6e3cd3", - "guzzle/http": "3.7.*", + "guzzlehttp/guzzle": "4.0.*", "kriswallsmith/assetic": "1.1.*@alpha", "symfony-cmf/routing": "1.1.*@alpha", "easyrdf/easyrdf": "0.8.*", diff --git a/composer.lock b/composer.lock index aa19f0fa3ad..f8712885d86 100644 --- a/composer.lock +++ b/composer.lock @@ -3,7 +3,7 @@ "This file locks the dependencies of your project to a known state", "Read more about it at http://getcomposer.org/doc/01-basic-usage.md#composer-lock-the-lock-file" ], - "hash": "5a96c248a0be5c8d138fcbf2a5bf9160", + "hash": "764a98eeaf89d9f52b9c32d343036de0", "packages": [ { "name": "doctrine/annotations", @@ -457,83 +457,41 @@ "time": "2013-12-30 22:31:37" }, { - "name": "guzzle/common", - "version": "v3.7.1", - "target-dir": "Guzzle/Common", + "name": "guzzlehttp/guzzle", + "version": "4.0.0", "source": { "type": "git", - "url": "https://github.com/guzzle/common.git", - "reference": "v3.7.1" + "url": "https://github.com/guzzle/guzzle.git", + "reference": "4063f08ca434efac12bf7a3db0d370b1c451345b" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/common/zipball/v3.7.1", - "reference": "v3.7.1", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/4063f08ca434efac12bf7a3db0d370b1c451345b", + "reference": "4063f08ca434efac12bf7a3db0d370b1c451345b", "shasum": "" }, "require": { - "php": ">=5.3.2", - "symfony/event-dispatcher": ">=2.1" + "guzzlehttp/streams": "1.*", + "php": ">=5.4.0" + }, + "require-dev": { + "ext-curl": "*", + "phpunit/phpunit": "4.*", + "psr/log": "~1" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.7-dev" + "dev-master": "4.0.x-dev" } }, "autoload": { - "psr-0": { - "Guzzle\\Common": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Common libraries used by Guzzle", - "homepage": "http://guzzlephp.org/", - "keywords": [ - "collection", - "common", - "event", - "exception" - ], - "time": "2013-07-05 20:17:54" - }, - { - "name": "guzzle/http", - "version": "v3.7.1", - "target-dir": "Guzzle/Http", - "source": { - "type": "git", - "url": "https://github.com/guzzle/http.git", - "reference": "v3.7.1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/guzzle/http/zipball/v3.7.1", - "reference": "v3.7.1", - "shasum": "" - }, - "require": { - "guzzle/common": "self.version", - "guzzle/parser": "self.version", - "guzzle/stream": "self.version", - "php": ">=5.3.2" - }, - "suggest": { - "ext-curl": "*" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.7-dev" - } - }, - "autoload": { - "psr-0": { - "Guzzle\\Http": "" - } + "psr-4": { + "GuzzleHttp\\": "src/" + }, + "files": [ + "src/functions.php" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -546,93 +504,52 @@ "homepage": "https://github.com/mtdowling" } ], - "description": "HTTP libraries used by Guzzle", + "description": "Guzzle is a PHP HTTP client library and framework for building RESTful web service clients", "homepage": "http://guzzlephp.org/", "keywords": [ - "Guzzle", "client", "curl", + "framework", "http", - "http client" + "http client", + "rest", + "web service" ], - "time": "2013-07-02 19:53:26" + "time": "2014-03-29 23:11:36" }, { - "name": "guzzle/parser", - "version": "v3.7.1", - "target-dir": "Guzzle/Parser", + "name": "guzzlehttp/streams", + "version": "1.0.0", "source": { "type": "git", - "url": "https://github.com/guzzle/parser.git", - "reference": "v3.7.1" + "url": "https://github.com/guzzle/streams.git", + "reference": "d249beffe5fa5e0da3855974bcc2dd9082069ccf" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/guzzle/parser/zipball/v3.7.1", - "reference": "v3.7.1", + "url": "https://api.github.com/repos/guzzle/streams/zipball/d249beffe5fa5e0da3855974bcc2dd9082069ccf", + "reference": "d249beffe5fa5e0da3855974bcc2dd9082069ccf", "shasum": "" }, "require": { - "php": ">=5.3.2" + "php": ">=5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "4.*" }, "type": "library", "extra": { "branch-alias": { - "dev-master": "3.7-dev" + "dev-master": "1.0.x-dev" } }, "autoload": { - "psr-0": { - "Guzzle\\Parser": "" - } - }, - "notification-url": "https://packagist.org/downloads/", - "license": [ - "MIT" - ], - "description": "Interchangeable parsers used by Guzzle", - "homepage": "http://guzzlephp.org/", - "keywords": [ - "URI Template", - "cookie", - "http", - "message", - "url" - ], - "time": "2013-06-11 00:24:07" - }, - { - "name": "guzzle/stream", - "version": "v3.7.1", - "target-dir": "Guzzle/Stream", - "source": { - "type": "git", - "url": "https://github.com/guzzle/stream.git", - "reference": "v3.7.1" - }, - "dist": { - "type": "zip", - "url": "https://api.github.com/repos/guzzle/stream/zipball/v3.7.1", - "reference": "v3.7.1", - "shasum": "" - }, - "require": { - "guzzle/common": "self.version", - "php": ">=5.3.2" - }, - "suggest": { - "guzzle/http": "To convert Guzzle request objects to PHP streams" - }, - "type": "library", - "extra": { - "branch-alias": { - "dev-master": "3.7-dev" - } - }, - "autoload": { - "psr-0": { - "Guzzle\\Stream": "" - } + "psr-4": { + "GuzzleHttp\\Stream\\": "src/" + }, + "files": [ + "src/functions.php" + ] }, "notification-url": "https://packagist.org/downloads/", "license": [ @@ -645,14 +562,13 @@ "homepage": "https://github.com/mtdowling" } ], - "description": "Guzzle stream wrapper component", + "description": "Provides a simple abstraction over streams of data (Guzzle 4+)", "homepage": "http://guzzlephp.org/", "keywords": [ "Guzzle", - "component", "stream" ], - "time": "2013-06-27 00:50:43" + "time": "2014-03-25 18:31:28" }, { "name": "kriswallsmith/assetic", @@ -2143,9 +2059,9 @@ "kriswallsmith/assetic": 15, "symfony-cmf/routing": 15 }, - "platform": [ - - ], + "platform": { + "php": ">=5.4.2" + }, "platform-dev": [ ] diff --git a/core/core.services.yml b/core/core.services.yml index 53487c5b76f..f3c6cd91d1c 100644 --- a/core/core.services.yml +++ b/core/core.services.yml @@ -157,19 +157,8 @@ services: path.alias_manager: class: Drupal\Core\Path\AliasManager arguments: ['@path.alias_storage', '@path.alias_whitelist', '@language_manager'] - http_client_simpletest_subscriber: - class: Drupal\Core\Http\Plugin\SimpletestHttpRequestSubscriber http_default_client: - class: Guzzle\Http\Client - # Security consideration: we must not use the certificate authority file - # shipped with Guzzle because it can easily get outdated if a certificate - # authority is hacked. Instead, we rely on the certificate authority file - # provided by the operating system which is more likely going to be updated - # in a timely fashion. - arguments: [null, { curl.CURLOPT_TIMEOUT: 30, curl.CURLOPT_MAXREDIRS: 3, ssl.certificate_authority: system }] - calls: - - [addSubscriber, ['@http_client_simpletest_subscriber']] - - [setUserAgent, ['Drupal (+http://drupal.org/)']] + class: Drupal\Core\Http\Client theme.negotiator: class: Drupal\Core\Theme\ThemeNegotiator arguments: ['@access_check.theme', '@request_stack'] diff --git a/core/includes/install.core.inc b/core/includes/install.core.inc index a0a60388015..f1cad478f80 100644 --- a/core/includes/install.core.inc +++ b/core/includes/install.core.inc @@ -21,7 +21,7 @@ use Symfony\Component\DependencyInjection\Reference; use Symfony\Component\HttpFoundation\Request; use Symfony\Component\HttpFoundation\Response; -use Guzzle\Http\Exception\RequestException; +use GuzzleHttp\Exception\RequestException; /** * @file @@ -1580,8 +1580,8 @@ function install_retrieve_file($uri, $destination) { } try { - $request = \Drupal::httpClient()->get($uri, array('Accept' => 'text/plain')); - $data = $request->send()->getBody(TRUE); + $request = \Drupal::httpClient()->get($uri, array('headers' => array('Accept' => 'text/plain'))); + $data = $request->getBody(TRUE); if (empty($data)) { return FALSE; } @@ -1603,8 +1603,7 @@ function install_retrieve_file($uri, $destination) { */ function install_check_localization_server($uri) { try { - $request = \Drupal::httpClient()->head($uri); - $request->send(); + \Drupal::httpClient()->head($uri); return TRUE; } catch (RequestException $e) { diff --git a/core/lib/Drupal.php b/core/lib/Drupal.php index faeb0818c5d..c22b92251d1 100644 --- a/core/lib/Drupal.php +++ b/core/lib/Drupal.php @@ -345,7 +345,7 @@ class Drupal { /** * Returns the default http client. * - * @return \Guzzle\Http\ClientInterface + * @return \GuzzleHttp\ClientInterface * A guzzle http client instance. */ public static function httpClient() { diff --git a/core/lib/Drupal/Core/Http/Client.php b/core/lib/Drupal/Core/Http/Client.php new file mode 100644 index 00000000000..f0b26a116d6 --- /dev/null +++ b/core/lib/Drupal/Core/Http/Client.php @@ -0,0 +1,51 @@ + array( + 'config' => array( + 'curl' => array( + CURLOPT_TIMEOUT => 30, + CURLOPT_MAXREDIRS => 3, + ), + ), + // Security consideration: we must not use the certificate authority + // file shipped with Guzzle because it can easily get outdated if a + // certificate authority is hacked. Instead, we rely on the certificate + // authority file provided by the operating system which is more likely + // going to be updated in a timely fashion. This overrides the default + // path to the pem file bundled with Guzzle. + 'verify' => TRUE, + 'headers' => array( + 'User-Agent' => 'Drupal (+http://drupal.org/)', + ), + ), + ); + $config = NestedArray::mergeDeep($default_config, $config); + + parent::__construct($config); + + $this->getEmitter()->attach(new SimpletestHttpRequestSubscriber()); + } + + +} diff --git a/core/lib/Drupal/Core/Http/Plugin/SimpletestHttpRequestSubscriber.php b/core/lib/Drupal/Core/Http/Plugin/SimpletestHttpRequestSubscriber.php index a8de4a89d20..825588ca657 100644 --- a/core/lib/Drupal/Core/Http/Plugin/SimpletestHttpRequestSubscriber.php +++ b/core/lib/Drupal/Core/Http/Plugin/SimpletestHttpRequestSubscriber.php @@ -1,4 +1,5 @@ 'onBeforeSendRequest'); + public function getEvents() { + return array( + 'before' => array('onBeforeSendRequest'), + ); } - /** - * Event callback for request.before_send + * Event callback for the 'before' event */ - public function onBeforeSendRequest(Event $event) { + public function onBeforeSendRequest(BeforeEvent $event) { // If the database prefix is being used by SimpleTest to run the tests in a copied // database then set the user-agent header to the database prefix so that any // calls to other Drupal pages will run the SimpleTest prefixed database. The @@ -35,7 +36,7 @@ class SimpletestHttpRequestSubscriber implements EventSubscriberInterface { // same time won't interfere with each other as they would if the database // prefix were stored statically in a file or database variable. if ($test_prefix = drupal_valid_test_ua()) { - $event['request']->setHeader('User-Agent', drupal_generate_test_ua($test_prefix)); + $event->getRequest()->setHeader('User-Agent', drupal_generate_test_ua($test_prefix)); } } } diff --git a/core/modules/aggregator/lib/Drupal/aggregator/Form/OpmlFeedAdd.php b/core/modules/aggregator/lib/Drupal/aggregator/Form/OpmlFeedAdd.php index 4284ee10278..b43cf314a86 100644 --- a/core/modules/aggregator/lib/Drupal/aggregator/Form/OpmlFeedAdd.php +++ b/core/modules/aggregator/lib/Drupal/aggregator/Form/OpmlFeedAdd.php @@ -11,9 +11,8 @@ use Drupal\aggregator\FeedStorageInterface; use Drupal\Component\Utility\UrlHelper; use Drupal\Core\Form\FormBase; use Symfony\Component\DependencyInjection\ContainerInterface; -use Guzzle\Http\Exception\RequestException; -use Guzzle\Http\Exception\BadResponseException; -use Guzzle\Http\ClientInterface; +use GuzzleHttp\Exception\RequestException; +use GuzzleHttp\ClientInterface; /** * Imports feeds from OPML. @@ -30,7 +29,7 @@ class OpmlFeedAdd extends FormBase { /** * The HTTP client to fetch the feed data with. * - * @var \Guzzle\Http\ClientInterface + * @var \GuzzleHttp\ClientInterface */ protected $httpClient; @@ -39,7 +38,7 @@ class OpmlFeedAdd extends FormBase { * * @param \Drupal\aggregator\FeedStorageInterface $feed_storage * The feed storage. - * @param \Guzzle\Http\ClientInterface $http_client + * @param \GuzzleHttp\ClientInterface $http_client * The Guzzle HTTP client. */ public function __construct(FeedStorageInterface $feed_storage, ClientInterface $http_client) { @@ -121,15 +120,9 @@ class OpmlFeedAdd extends FormBase { else { // @todo Move this to a fetcher implementation. try { - $response = $this->httpClient->get($form_state['values']['remote'])->send(); + $response = $this->httpClient->get($form_state['values']['remote']); $data = $response->getBody(TRUE); } - catch (BadResponseException $e) { - $response = $e->getResponse(); - watchdog('aggregator', 'Failed to download OPML file due to "%error".', array('%error' => $response->getStatusCode() . ' ' . $response->getReasonPhrase()), WATCHDOG_WARNING); - drupal_set_message($this->t('Failed to download OPML file due to "%error".', array('%error' => $response->getStatusCode() . ' ' . $response->getReasonPhrase()))); - return; - } catch (RequestException $e) { watchdog('aggregator', 'Failed to download OPML file due to "%error".', array('%error' => $e->getMessage()), WATCHDOG_WARNING); drupal_set_message($this->t('Failed to download OPML file due to "%error".', array('%error' => $e->getMessage()))); diff --git a/core/modules/aggregator/lib/Drupal/aggregator/Plugin/aggregator/fetcher/DefaultFetcher.php b/core/modules/aggregator/lib/Drupal/aggregator/Plugin/aggregator/fetcher/DefaultFetcher.php index f730033a56f..bc2ba0a75a7 100644 --- a/core/modules/aggregator/lib/Drupal/aggregator/Plugin/aggregator/fetcher/DefaultFetcher.php +++ b/core/modules/aggregator/lib/Drupal/aggregator/Plugin/aggregator/fetcher/DefaultFetcher.php @@ -10,9 +10,8 @@ namespace Drupal\aggregator\Plugin\aggregator\fetcher; use Drupal\aggregator\Plugin\FetcherInterface; use Drupal\aggregator\FeedInterface; use Drupal\Core\Plugin\ContainerFactoryPluginInterface; -use Guzzle\Http\ClientInterface; -use Guzzle\Http\Exception\BadResponseException; -use Guzzle\Http\Exception\RequestException; +use GuzzleHttp\ClientInterface; +use GuzzleHttp\Exception\RequestException; use Symfony\Component\DependencyInjection\ContainerInterface; /** @@ -31,14 +30,14 @@ class DefaultFetcher implements FetcherInterface, ContainerFactoryPluginInterfac /** * The HTTP client to fetch the feed data with. * - * @var \Guzzle\Http\ClientInterface + * @var \GuzzleHttp\ClientInterface */ protected $httpClient; /** * Constructs a DefaultFetcher object. * - * @param \Guzzle\Http\ClientInterface $http_client + * @param \GuzzleHttp\ClientInterface $http_client * A Guzzle client object. */ public function __construct(ClientInterface $http_client) { @@ -58,7 +57,7 @@ class DefaultFetcher implements FetcherInterface, ContainerFactoryPluginInterfac * {@inheritdoc} */ public function fetch(FeedInterface $feed) { - $request = $this->httpClient->get($feed->getUrl()); + $request = $this->httpClient->createRequest('GET', $feed->getUrl()); $feed->source_string = FALSE; // Generate conditional GET headers. @@ -70,7 +69,7 @@ class DefaultFetcher implements FetcherInterface, ContainerFactoryPluginInterfac } try { - $response = $request->send(); + $response = $this->httpClient->send($request); // In case of a 304 Not Modified, there is no new content, so return // FALSE. @@ -79,8 +78,8 @@ class DefaultFetcher implements FetcherInterface, ContainerFactoryPluginInterfac } $feed->source_string = $response->getBody(TRUE); - $feed->setEtag($response->getEtag()); - $feed->setLastModified(strtotime($response->getLastModified())); + $feed->setEtag($response->getHeader('ETag')); + $feed->setLastModified(strtotime($response->getHeader('Last-Modified'))); $feed->http_headers = $response->getHeaders(); // Update the feed URL in case of a 301 redirect. @@ -90,12 +89,6 @@ class DefaultFetcher implements FetcherInterface, ContainerFactoryPluginInterfac } return TRUE; } - catch (BadResponseException $e) { - $response = $e->getResponse(); - watchdog('aggregator', 'The feed from %site seems to be broken because of error "%error".', array('%site' => $feed->label(), '%error' => $response->getStatusCode() . ' ' . $response->getReasonPhrase()), WATCHDOG_WARNING); - drupal_set_message(t('The feed from %site seems to be broken because of error "%error".', array('%site' => $feed->label(), '%error' => $response->getStatusCode() . ' ' . $response->getReasonPhrase()))); - return FALSE; - } catch (RequestException $e) { watchdog('aggregator', 'The feed from %site seems to be broken because of error "%error".', array('%site' => $feed->label(), '%error' => $e->getMessage()), WATCHDOG_WARNING); drupal_set_message(t('The feed from %site seems to be broken because of error "%error".', array('%site' => $feed->label(), '%error' => $e->getMessage()))); diff --git a/core/modules/aggregator/tests/modules/aggregator_test/lib/Drupal/aggregator_test/Plugin/aggregator/fetcher/TestFetcher.php b/core/modules/aggregator/tests/modules/aggregator_test/lib/Drupal/aggregator_test/Plugin/aggregator/fetcher/TestFetcher.php index 8aaf8e0170e..8c06a96d0d4 100644 --- a/core/modules/aggregator/tests/modules/aggregator_test/lib/Drupal/aggregator_test/Plugin/aggregator/fetcher/TestFetcher.php +++ b/core/modules/aggregator/tests/modules/aggregator_test/lib/Drupal/aggregator_test/Plugin/aggregator/fetcher/TestFetcher.php @@ -10,7 +10,6 @@ namespace Drupal\aggregator_test\Plugin\aggregator\fetcher; use Drupal\aggregator\Plugin\FetcherInterface; use Drupal\aggregator\Plugin\aggregator\fetcher\DefaultFetcher; use Drupal\aggregator\FeedInterface; -use Guzzle\Http\Exception\BadResponseException; /** * Defines a test fetcher implementation. diff --git a/core/modules/hal/lib/Drupal/hal/Normalizer/FileEntityNormalizer.php b/core/modules/hal/lib/Drupal/hal/Normalizer/FileEntityNormalizer.php index 03c0292d24d..18ddf99d099 100644 --- a/core/modules/hal/lib/Drupal/hal/Normalizer/FileEntityNormalizer.php +++ b/core/modules/hal/lib/Drupal/hal/Normalizer/FileEntityNormalizer.php @@ -10,7 +10,7 @@ namespace Drupal\hal\Normalizer; use Drupal\Core\Entity\EntityManagerInterface; use Drupal\Core\Extension\ModuleHandlerInterface; use Drupal\rest\LinkManager\LinkManagerInterface; -use Guzzle\Http\ClientInterface; +use GuzzleHttp\ClientInterface; /** * Converts the Drupal entity object structure to a HAL array structure. @@ -27,7 +27,7 @@ class FileEntityNormalizer extends ContentEntityNormalizer { /** * The HTTP client. * - * @var \Guzzle\Http\ClientInterface + * @var \GuzzleHttp\ClientInterface */ protected $httpClient; @@ -36,7 +36,7 @@ class FileEntityNormalizer extends ContentEntityNormalizer { * * @param \Drupal\Core\Entity\EntityManagerInterface $entity_manager * The entity manager. - * @param \Guzzle\Http\ClientInterface $http_client + * @param \GuzzleHttp\ClientInterface $http_client * The HTTP Client. * @param \Drupal\rest\LinkManager\LinkManagerInterface $link_manager * The hypermedia link manager. @@ -64,9 +64,7 @@ class FileEntityNormalizer extends ContentEntityNormalizer { * {@inheritdoc} */ public function denormalize($data, $class, $format = NULL, array $context = array()) { - $file_data = $this->httpClient->get($data['uri'][0]['value']) - ->send() - ->getBody(TRUE); + $file_data = $this->httpClient->get($data['uri'][0]['value'])->getBody(TRUE); $path = 'temporary://' . drupal_basename($data['uri'][0]['value']); $data['uri'] = file_unmanaged_save_data($file_data, $path); diff --git a/core/modules/locale/locale.batch.inc b/core/modules/locale/locale.batch.inc index 5085a2bf5d6..6dfcae6364b 100644 --- a/core/modules/locale/locale.batch.inc +++ b/core/modules/locale/locale.batch.inc @@ -5,8 +5,7 @@ * Batch process to check the availability of remote or local po files. */ -use Guzzle\Http\Exception\BadResponseException; -use Guzzle\Http\Exception\RequestException; +use GuzzleHttp\Exception\RequestException; /** * Load the common translation API. @@ -231,9 +230,7 @@ function locale_translation_batch_fetch_finished($success, $results) { function locale_translation_http_check($uri) { try { - $response = \Drupal::httpClient() - ->head($uri) - ->send(); + $response = \Drupal::httpClient()->head($uri); $result = array(); // Return the effective URL if it differs from the requested. @@ -241,10 +238,10 @@ function locale_translation_http_check($uri) { $result['location'] = $response->getEffectiveUrl(); } - $result['last_modified'] = $response->getLastModified() ? strtotime($response->getLastModified()) : 0; + $result['last_modified'] = $response->hasHeader('Last-Modified') ? strtotime($response->getHeader('Last-Modified')) : 0; return $result; } - catch (BadResponseException $e) { + catch (RequestException $e) { // Handle 4xx and 5xx http responses. $response = $e->getResponse(); if ($response->getStatusCode() == 404) { @@ -258,11 +255,7 @@ function locale_translation_http_check($uri) { } watchdog('locale', 'HTTP request to @url failed with error: @error.', array('@url' => $uri, '@error' => $response->getStatusCode() . ' ' . $response->getReasonPhrase())); } - catch (RequestException $e) { - // Handle connection problems and cURL specific errors (CurlException) and - // other http related errors. - watchdog('locale', 'HTTP request to @url failed with error: @error.', array('@url' => $uri, '@error' => $e->getMessage())); - } + return FALSE; } diff --git a/core/modules/statistics/lib/Drupal/statistics/Tests/StatisticsAdminTest.php b/core/modules/statistics/lib/Drupal/statistics/Tests/StatisticsAdminTest.php index e8abd34066a..ad68b72f3f7 100644 --- a/core/modules/statistics/lib/Drupal/statistics/Tests/StatisticsAdminTest.php +++ b/core/modules/statistics/lib/Drupal/statistics/Tests/StatisticsAdminTest.php @@ -40,7 +40,7 @@ class StatisticsAdminTest extends WebTestBase { /** * The Guzzle HTTP client. * - * @var \Guzzle\Http\ClientInterface; + * @var \GuzzleHttp\ClientInterface; */ protected $client; @@ -63,7 +63,7 @@ class StatisticsAdminTest extends WebTestBase { $this->drupalLogin($this->privileged_user); $this->test_node = $this->drupalCreateNode(array('type' => 'page', 'uid' => $this->privileged_user->id())); $this->client = \Drupal::httpClient(); - $this->client->setConfig(array('curl.options' => array(CURLOPT_TIMEOUT => 10))); + $this->client->setDefaultOption('config/curl', array(CURLOPT_TIMEOUT => 10)); } /** @@ -86,16 +86,16 @@ class StatisticsAdminTest extends WebTestBase { $post = array('nid' => $nid); global $base_url; $stats_path = $base_url . '/' . drupal_get_path('module', 'statistics'). '/statistics.php'; - $this->client->post($stats_path, array(), $post)->send(); + $this->client->post($stats_path, array('body' => $post)); // Hit the node again (the counter is incremented after the hit, so // "1 view" will actually be shown when the node is hit the second time). $this->drupalGet('node/' . $this->test_node->id()); - $this->client->post($stats_path, array(), $post)->send(); + $this->client->post($stats_path, array('body' => $post)); $this->assertText('1 view', 'Node is viewed once.'); $this->drupalGet('node/' . $this->test_node->id()); - $this->client->post($stats_path, array(), $post)->send(); + $this->client->post($stats_path, array('body' => $post)); $this->assertText('2 views', 'Node is viewed 2 times.'); } @@ -111,7 +111,7 @@ class StatisticsAdminTest extends WebTestBase { $post = array('nid' => $nid); global $base_url; $stats_path = $base_url . '/' . drupal_get_path('module', 'statistics'). '/statistics.php'; - $this->client->post($stats_path, array(), $post)->send(); + $this->client->post($stats_path, array('body' => $post)); $result = db_select('node_counter', 'n') ->fields('n', array('nid')) @@ -145,9 +145,9 @@ class StatisticsAdminTest extends WebTestBase { $post = array('nid' => $nid); global $base_url; $stats_path = $base_url . '/' . drupal_get_path('module', 'statistics'). '/statistics.php'; - $this->client->post($stats_path, array(), $post)->send(); + $this->client->post($stats_path, array('body' => $post)); $this->drupalGet('node/' . $this->test_node->id()); - $this->client->post($stats_path, array(), $post)->send(); + $this->client->post($stats_path, array('body' => $post)); $this->assertText('1 view', 'Node is viewed once.'); // statistics_cron() will subtract diff --git a/core/modules/statistics/lib/Drupal/statistics/Tests/StatisticsLoggingTest.php b/core/modules/statistics/lib/Drupal/statistics/Tests/StatisticsLoggingTest.php index 6177b863cb1..3effaf59360 100644 --- a/core/modules/statistics/lib/Drupal/statistics/Tests/StatisticsLoggingTest.php +++ b/core/modules/statistics/lib/Drupal/statistics/Tests/StatisticsLoggingTest.php @@ -27,7 +27,7 @@ class StatisticsLoggingTest extends WebTestBase { /** * The Guzzle HTTP client. * - * @var \Guzzle\Http\ClientInterface; + * @var \GuzzleHttp\ClientInterface; */ protected $client; @@ -61,7 +61,7 @@ class StatisticsLoggingTest extends WebTestBase { db_truncate('node_counter'); $this->client = \Drupal::httpClient(); - $this->client->setConfig(array('curl.options' => array(CURLOPT_TIMEOUT => 10))); + $this->client->setDefaultOption('config/curl', array(CURLOPT_TIMEOUT => 10)); } /** @@ -93,7 +93,7 @@ class StatisticsLoggingTest extends WebTestBase { // Manually call statistics.php to simulate ajax data collection behavior. $nid = $this->node->id(); $post = array('nid' => $nid); - $this->client->post($stats_path, array(), $post)->send(); + $this->client->post($stats_path, array('body' => $post)); $node_counter = statistics_get($this->node->id()); $this->assertIdentical($node_counter['totalcount'], '1'); } diff --git a/core/modules/statistics/lib/Drupal/statistics/Tests/StatisticsReportsTest.php b/core/modules/statistics/lib/Drupal/statistics/Tests/StatisticsReportsTest.php index e1dc9f6ada3..3d8309aca97 100644 --- a/core/modules/statistics/lib/Drupal/statistics/Tests/StatisticsReportsTest.php +++ b/core/modules/statistics/lib/Drupal/statistics/Tests/StatisticsReportsTest.php @@ -37,8 +37,8 @@ class StatisticsReportsTest extends StatisticsTestBase { global $base_url; $stats_path = $base_url . '/' . drupal_get_path('module', 'statistics'). '/statistics.php'; $client = \Drupal::httpClient(); - $client->setConfig(array('curl.options' => array(CURLOPT_TIMEOUT => 10))); - $client->post($stats_path, $headers, $post)->send(); + $client->setDefaultOption('config/curl', array(CURLOPT_TIMEOUT => 10)); + $client->post($stats_path, array('headers' => $headers, 'body' => $post)); // Configure and save the block. $this->drupalPlaceBlock('statistics_popular_block', array( diff --git a/core/modules/statistics/lib/Drupal/statistics/Tests/StatisticsTokenReplaceTest.php b/core/modules/statistics/lib/Drupal/statistics/Tests/StatisticsTokenReplaceTest.php index 712c5ab21a4..16c1fda1246 100644 --- a/core/modules/statistics/lib/Drupal/statistics/Tests/StatisticsTokenReplaceTest.php +++ b/core/modules/statistics/lib/Drupal/statistics/Tests/StatisticsTokenReplaceTest.php @@ -41,8 +41,8 @@ class StatisticsTokenReplaceTest extends StatisticsTestBase { global $base_url; $stats_path = $base_url . '/' . drupal_get_path('module', 'statistics'). '/statistics.php'; $client = \Drupal::httpClient(); - $client->setConfig(array('curl.options' => array(CURLOPT_TIMEOUT => 10))); - $client->post($stats_path, $headers, $post)->send(); + $client->setDefaultOption('config/curl', array(CURLOPT_TIMEOUT => 10)); + $client->post($stats_path, array('headers' => $headers, 'body' => $post)); $statistics = statistics_get($node->id()); // Generate and test tokens. diff --git a/core/modules/statistics/lib/Drupal/statistics/Tests/Views/IntegrationTest.php b/core/modules/statistics/lib/Drupal/statistics/Tests/Views/IntegrationTest.php index 7d3e567f381..f7fec462034 100644 --- a/core/modules/statistics/lib/Drupal/statistics/Tests/Views/IntegrationTest.php +++ b/core/modules/statistics/lib/Drupal/statistics/Tests/Views/IntegrationTest.php @@ -83,8 +83,8 @@ class IntegrationTest extends ViewTestBase { global $base_url; $stats_path = $base_url . '/' . drupal_get_path('module', 'statistics'). '/statistics.php'; $client = \Drupal::httpClient(); - $client->setConfig(array('curl.options' => array(CURLOPT_TIMEOUT => 10))); - $client->post($stats_path, array(), array('nid' => $this->node->id()))->send(); + $client->setDefaultOption('config/curl', array(CURLOPT_TIMEOUT => 10)); + $client->post($stats_path, array('body' => array('nid' => $this->node->id()))); $this->drupalGet('test_statistics_integration'); $expected = statistics_get($this->node->id()); diff --git a/core/modules/system/system.module b/core/modules/system/system.module index ad8c0844bb4..541168da5b5 100644 --- a/core/modules/system/system.module +++ b/core/modules/system/system.module @@ -12,8 +12,7 @@ use Drupal\Core\Extension\ExtensionDiscovery; use Drupal\block\BlockPluginInterface; use Drupal\user\UserInterface; use Symfony\Component\HttpFoundation\RedirectResponse; -use Guzzle\Http\Exception\BadResponseException; -use Guzzle\Http\Exception\RequestException; +use GuzzleHttp\Exception\RequestException; /** * Maximum age of temporary files in seconds. @@ -1677,15 +1676,9 @@ function system_retrieve_file($url, $destination = NULL, $managed = FALSE, $repl try { $data = \Drupal::httpClient() ->get($url) - ->send() ->getBody(TRUE); $local = $managed ? file_save_data($data, $path, $replace) : file_unmanaged_save_data($data, $path, $replace); } - catch (BadResponseException $exception) { - $response = $exception->getResponse(); - drupal_set_message(t('Failed to fetch file due to HTTP error "%error"', array('%error' => $response->getStatusCode() . ' ' . $response->getReasonPhrase())), 'error'); - return FALSE; - } catch (RequestException $exception) { drupal_set_message(t('Failed to fetch file due to error "%error"', array('%error' => $exception->getMessage())), 'error'); return FALSE; diff --git a/core/modules/update/lib/Drupal/update/UpdateFetcher.php b/core/modules/update/lib/Drupal/update/UpdateFetcher.php index 394810ed174..14bdb29336e 100644 --- a/core/modules/update/lib/Drupal/update/UpdateFetcher.php +++ b/core/modules/update/lib/Drupal/update/UpdateFetcher.php @@ -8,8 +8,8 @@ namespace Drupal\update; use Drupal\Core\Config\ConfigFactoryInterface; -use Guzzle\Http\ClientInterface; -use Guzzle\Http\Exception\RequestException; +use GuzzleHttp\ClientInterface; +use GuzzleHttp\Exception\RequestException; /** * Fetches project information from remote locations. @@ -38,7 +38,7 @@ class UpdateFetcher implements UpdateFetcherInterface { /** * The HTTP client to fetch the feed data with. * - * @var \Guzzle\Http\ClientInterface + * @var \GuzzleHttp\ClientInterface */ protected $httpClient; @@ -47,7 +47,7 @@ class UpdateFetcher implements UpdateFetcherInterface { * * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory * The config factory. - * @param \Guzzle\Http\ClientInterface $http_client + * @param \GuzzleHttp\ClientInterface $http_client * A Guzzle client object. */ public function __construct(ConfigFactoryInterface $config_factory, ClientInterface $http_client) { @@ -64,8 +64,7 @@ class UpdateFetcher implements UpdateFetcherInterface { $data = ''; try { $data = $this->httpClient - ->get($url, array('Accept' => 'text/xml')) - ->send() + ->get($url, array('headers' => array('Accept' => 'text/xml'))) ->getBody(TRUE); } catch (RequestException $exception) { diff --git a/core/modules/update/tests/Drupal/update/Tests/UpdateFetcherTest.php b/core/modules/update/tests/Drupal/update/Tests/UpdateFetcherTest.php index e43a3ae4738..4a3191614d9 100644 --- a/core/modules/update/tests/Drupal/update/Tests/UpdateFetcherTest.php +++ b/core/modules/update/tests/Drupal/update/Tests/UpdateFetcherTest.php @@ -39,7 +39,10 @@ class UpdateFetcherTest extends UnitTestCase { */ protected function setUp() { $config_factory = $this->getConfigFactoryStub(array('update.settings' => array('fetch_url' => 'http://www.example.com'))); - $this->updateFetcher = new UpdateFetcher($config_factory, $this->getMock('Guzzle\Http\Client')); + $http_client_mock = $this->getMockBuilder('Drupal\Core\Http\Client') + ->disableOriginalConstructor() + ->getMock(); + $this->updateFetcher = new UpdateFetcher($config_factory, $http_client_mock); } /** diff --git a/core/modules/xmlrpc/xmlrpc.inc b/core/modules/xmlrpc/xmlrpc.inc index 445993a1f0d..cb2180e114e 100644 --- a/core/modules/xmlrpc/xmlrpc.inc +++ b/core/modules/xmlrpc/xmlrpc.inc @@ -11,8 +11,7 @@ * This version is made available under the GNU GPL License */ -use Guzzle\Http\Exception\BadResponseException; -use Guzzle\Http\Exception\RequestException; +use GuzzleHttp\Exception\RequestException; /** * Turns a data structure into objects with 'data' and 'type' attributes. @@ -561,15 +560,11 @@ function _xmlrpc($url, array $args, array $headers = array()) { $args = $args[$method]; } $xmlrpc_request = xmlrpc_request($method, $args); - $request = \Drupal::httpClient()->post($url, $headers, $xmlrpc_request->xml); - $request->setHeader('Content-Type', 'text/xml'); + + $headers['Content-Type'] = 'text/xml'; + try { - $response = $request->send(); - } - catch (BadResponseException $exception) { - $response = $exception->getResponse(); - xmlrpc_error($response->getStatusCode(), $response->getReasonPhrase()); - return FALSE; + $response = \Drupal::httpClient()->post($url, array('headers' => $headers, 'body' => $xmlrpc_request->xml)); } catch (RequestException $exception) { xmlrpc_error(NULL, $exception->getMethod()); diff --git a/core/tests/Drupal/Tests/Core/Cache/CacheContextsTest.php b/core/tests/Drupal/Tests/Core/Cache/CacheContextsTest.php index 6e5864de35b..e4309659bcf 100644 --- a/core/tests/Drupal/Tests/Core/Cache/CacheContextsTest.php +++ b/core/tests/Drupal/Tests/Core/Cache/CacheContextsTest.php @@ -9,6 +9,7 @@ namespace Drupal\Tests\Core\Cache; use Drupal\Core\Cache\CacheContexts; use Drupal\Core\Cache\CacheContextInterface; +use Drupal\Tests\UnitTestCase; /** * Fake cache context class. @@ -38,7 +39,7 @@ class FooCacheContext implements CacheContextInterface { * * @see \Drupal\Core\Cache\CacheContexts */ -class CacheContextsTest extends \PHPUnit_Framework_TestCase { +class CacheContextsTest extends UnitTestCase { public static function getInfo() { return array( diff --git a/core/vendor/composer/ClassLoader.php b/core/vendor/composer/ClassLoader.php index 47ae2ee9252..a7105553143 100644 --- a/core/vendor/composer/ClassLoader.php +++ b/core/vendor/composer/ClassLoader.php @@ -291,8 +291,25 @@ class ClassLoader return $this->classMap[$class]; } + $file = $this->findFileWithExtension($class, '.php'); + + // Search for Hack files if we are running on HHVM + if ($file === null && defined('HHVM_VERSION')) { + $file = $this->findFileWithExtension($class, '.hh'); + } + + if ($file === null) { + // Remember that this class does not exist. + return $this->classMap[$class] = false; + } + + return $file; + } + + private function findFileWithExtension($class, $ext) + { // PSR-4 lookup - $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . '.php'; + $logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext; $first = $class[0]; if (isset($this->prefixLengthsPsr4[$first])) { @@ -321,7 +338,7 @@ class ClassLoader . strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR); } else { // PEAR-like class name - $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . '.php'; + $logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext; } if (isset($this->prefixesPsr0[$first])) { @@ -347,9 +364,6 @@ class ClassLoader if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) { return $file; } - - // Remember that this class does not exist. - return $this->classMap[$class] = false; } } diff --git a/core/vendor/composer/autoload_files.php b/core/vendor/composer/autoload_files.php index 2ebcd822ecf..2ca5d44933d 100644 --- a/core/vendor/composer/autoload_files.php +++ b/core/vendor/composer/autoload_files.php @@ -6,6 +6,8 @@ $vendorDir = dirname(dirname(__FILE__)); $baseDir = dirname(dirname($vendorDir)); return array( + $vendorDir . '/guzzlehttp/streams/src/functions.php', $vendorDir . '/kriswallsmith/assetic/src/functions.php', + $vendorDir . '/guzzlehttp/guzzle/src/functions.php', $baseDir . '/core/lib/Drupal.php', ); diff --git a/core/vendor/composer/autoload_namespaces.php b/core/vendor/composer/autoload_namespaces.php index 83fb6eda09c..80f7f7a604e 100644 --- a/core/vendor/composer/autoload_namespaces.php +++ b/core/vendor/composer/autoload_namespaces.php @@ -25,10 +25,6 @@ return array( 'Symfony\\Component\\ClassLoader\\' => array($vendorDir . '/symfony/class-loader'), 'Symfony\\Cmf\\Component\\Routing' => array($vendorDir . '/symfony-cmf/routing'), 'Psr\\Log\\' => array($vendorDir . '/psr/log'), - 'Guzzle\\Stream' => array($vendorDir . '/guzzle/stream'), - 'Guzzle\\Parser' => array($vendorDir . '/guzzle/parser'), - 'Guzzle\\Http' => array($vendorDir . '/guzzle/http'), - 'Guzzle\\Common' => array($vendorDir . '/guzzle/common'), 'Gliph' => array($vendorDir . '/sdboyer/gliph/src'), 'EasyRdf_' => array($vendorDir . '/easyrdf/easyrdf/lib'), 'Drupal\\Driver' => array($baseDir . '/drivers/lib'), diff --git a/core/vendor/composer/autoload_psr4.php b/core/vendor/composer/autoload_psr4.php index 80607ee9774..e53db415a08 100644 --- a/core/vendor/composer/autoload_psr4.php +++ b/core/vendor/composer/autoload_psr4.php @@ -6,4 +6,6 @@ $vendorDir = dirname(dirname(__FILE__)); $baseDir = dirname(dirname($vendorDir)); return array( + 'GuzzleHttp\\Stream\\' => array($vendorDir . '/guzzlehttp/streams/src'), + 'GuzzleHttp\\' => array($vendorDir . '/guzzlehttp/guzzle/src'), ); diff --git a/core/vendor/composer/installed.json b/core/vendor/composer/installed.json index a0016750da8..ed8df0cbbb6 100644 --- a/core/vendor/composer/installed.json +++ b/core/vendor/composer/installed.json @@ -2199,5 +2199,123 @@ ], "description": "Symfony Yaml Component", "homepage": "http://symfony.com" + }, + { + "name": "guzzlehttp/streams", + "version": "1.0.0", + "version_normalized": "1.0.0.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/streams.git", + "reference": "d249beffe5fa5e0da3855974bcc2dd9082069ccf" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/streams/zipball/d249beffe5fa5e0da3855974bcc2dd9082069ccf", + "reference": "d249beffe5fa5e0da3855974bcc2dd9082069ccf", + "shasum": "" + }, + "require": { + "php": ">=5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "4.*" + }, + "time": "2014-03-25 18:31:28", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "GuzzleHttp\\Stream\\": "src/" + }, + "files": [ + "src/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Provides a simple abstraction over streams of data (Guzzle 4+)", + "homepage": "http://guzzlephp.org/", + "keywords": [ + "Guzzle", + "stream" + ] + }, + { + "name": "guzzlehttp/guzzle", + "version": "4.0.0", + "version_normalized": "4.0.0.0", + "source": { + "type": "git", + "url": "https://github.com/guzzle/guzzle.git", + "reference": "4063f08ca434efac12bf7a3db0d370b1c451345b" + }, + "dist": { + "type": "zip", + "url": "https://api.github.com/repos/guzzle/guzzle/zipball/4063f08ca434efac12bf7a3db0d370b1c451345b", + "reference": "4063f08ca434efac12bf7a3db0d370b1c451345b", + "shasum": "" + }, + "require": { + "guzzlehttp/streams": "1.*", + "php": ">=5.4.0" + }, + "require-dev": { + "ext-curl": "*", + "phpunit/phpunit": "4.*", + "psr/log": "~1" + }, + "time": "2014-03-29 23:11:36", + "type": "library", + "extra": { + "branch-alias": { + "dev-master": "4.0.x-dev" + } + }, + "installation-source": "dist", + "autoload": { + "psr-4": { + "GuzzleHttp\\": "src/" + }, + "files": [ + "src/functions.php" + ] + }, + "notification-url": "https://packagist.org/downloads/", + "license": [ + "MIT" + ], + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "description": "Guzzle is a PHP HTTP client library and framework for building RESTful web service clients", + "homepage": "http://guzzlephp.org/", + "keywords": [ + "client", + "curl", + "framework", + "http", + "http client", + "rest", + "web service" + ] } ] diff --git a/core/vendor/guzzle/common/Guzzle/Common/AbstractHasDispatcher.php b/core/vendor/guzzle/common/Guzzle/Common/AbstractHasDispatcher.php deleted file mode 100644 index 9c6874fb4e4..00000000000 --- a/core/vendor/guzzle/common/Guzzle/Common/AbstractHasDispatcher.php +++ /dev/null @@ -1,49 +0,0 @@ -eventDispatcher = $eventDispatcher; - - return $this; - } - - public function getEventDispatcher() - { - if (!$this->eventDispatcher) { - $this->eventDispatcher = new EventDispatcher(); - } - - return $this->eventDispatcher; - } - - public function dispatch($eventName, array $context = array()) - { - $this->getEventDispatcher()->dispatch($eventName, new Event($context)); - } - - public function addSubscriber(EventSubscriberInterface $subscriber) - { - $this->getEventDispatcher()->addSubscriber($subscriber); - - return $this; - } -} diff --git a/core/vendor/guzzle/common/Guzzle/Common/Collection.php b/core/vendor/guzzle/common/Guzzle/Common/Collection.php deleted file mode 100644 index 5cb1535d07a..00000000000 --- a/core/vendor/guzzle/common/Guzzle/Common/Collection.php +++ /dev/null @@ -1,403 +0,0 @@ -data = $data; - } - - /** - * Create a new collection from an array, validate the keys, and add default values where missing - * - * @param array $config Configuration values to apply. - * @param array $defaults Default parameters - * @param array $required Required parameter names - * - * @return self - * @throws InvalidArgumentException if a parameter is missing - */ - public static function fromConfig(array $config = array(), array $defaults = array(), array $required = array()) - { - $data = $config + $defaults; - - if ($missing = array_diff($required, array_keys($data))) { - throw new InvalidArgumentException('Config is missing the following keys: ' . implode(', ', $missing)); - } - - return new self($data); - } - - public function count() - { - return count($this->data); - } - - public function getIterator() - { - return new \ArrayIterator($this->data); - } - - public function toArray() - { - return $this->data; - } - - /** - * Removes all key value pairs - * - * @return Collection - */ - public function clear() - { - $this->data = array(); - - return $this; - } - - /** - * Get all or a subset of matching key value pairs - * - * @param array $keys Pass an array of keys to retrieve only a subset of key value pairs - * - * @return array Returns an array of all matching key value pairs - */ - public function getAll(array $keys = null) - { - return $keys ? array_intersect_key($this->data, array_flip($keys)) : $this->data; - } - - /** - * Get a specific key value. - * - * @param string $key Key to retrieve. - * - * @return mixed|null Value of the key or NULL - */ - public function get($key) - { - return isset($this->data[$key]) ? $this->data[$key] : null; - } - - /** - * Set a key value pair - * - * @param string $key Key to set - * @param mixed $value Value to set - * - * @return Collection Returns a reference to the object - */ - public function set($key, $value) - { - $this->data[$key] = $value; - - return $this; - } - - /** - * Add a value to a key. If a key of the same name has already been added, the key value will be converted into an - * array and the new value will be pushed to the end of the array. - * - * @param string $key Key to add - * @param mixed $value Value to add to the key - * - * @return Collection Returns a reference to the object. - */ - public function add($key, $value) - { - if (!array_key_exists($key, $this->data)) { - $this->data[$key] = $value; - } elseif (is_array($this->data[$key])) { - $this->data[$key][] = $value; - } else { - $this->data[$key] = array($this->data[$key], $value); - } - - return $this; - } - - /** - * Remove a specific key value pair - * - * @param string $key A key to remove - * - * @return Collection - */ - public function remove($key) - { - unset($this->data[$key]); - - return $this; - } - - /** - * Get all keys in the collection - * - * @return array - */ - public function getKeys() - { - return array_keys($this->data); - } - - /** - * Returns whether or not the specified key is present. - * - * @param string $key The key for which to check the existence. - * - * @return bool - */ - public function hasKey($key) - { - return array_key_exists($key, $this->data); - } - - /** - * Case insensitive search the keys in the collection - * - * @param string $key Key to search for - * - * @return bool|string Returns false if not found, otherwise returns the key - */ - public function keySearch($key) - { - foreach (array_keys($this->data) as $k) { - if (!strcasecmp($k, $key)) { - return $k; - } - } - - return false; - } - - /** - * Checks if any keys contains a certain value - * - * @param string $value Value to search for - * - * @return mixed Returns the key if the value was found FALSE if the value was not found. - */ - public function hasValue($value) - { - return array_search($value, $this->data); - } - - /** - * Replace the data of the object with the value of an array - * - * @param array $data Associative array of data - * - * @return Collection Returns a reference to the object - */ - public function replace(array $data) - { - $this->data = $data; - - return $this; - } - - /** - * Add and merge in a Collection or array of key value pair data. - * - * @param Collection|array $data Associative array of key value pair data - * - * @return Collection Returns a reference to the object. - */ - public function merge($data) - { - foreach ($data as $key => $value) { - $this->add($key, $value); - } - - return $this; - } - - /** - * Over write key value pairs in this collection with all of the data from an array or collection. - * - * @param array|\Traversable $data Values to override over this config - * - * @return self - */ - public function overwriteWith($data) - { - if (is_array($data)) { - $this->data = $data + $this->data; - } elseif ($data instanceof Collection) { - $this->data = $data->toArray() + $this->data; - } else { - foreach ($data as $key => $value) { - $this->data[$key] = $value; - } - } - - return $this; - } - - /** - * Returns a Collection containing all the elements of the collection after applying the callback function to each - * one. The Closure should accept three parameters: (string) $key, (string) $value, (array) $context and return a - * modified value - * - * @param \Closure $closure Closure to apply - * @param array $context Context to pass to the closure - * @param bool $static Set to TRUE to use the same class as the return rather than returning a Collection - * - * @return Collection - */ - public function map(\Closure $closure, array $context = array(), $static = true) - { - $collection = $static ? new static() : new self(); - foreach ($this as $key => $value) { - $collection->add($key, $closure($key, $value, $context)); - } - - return $collection; - } - - /** - * Iterates over each key value pair in the collection passing them to the Closure. If the Closure function returns - * true, the current value from input is returned into the result Collection. The Closure must accept three - * parameters: (string) $key, (string) $value and return Boolean TRUE or FALSE for each value. - * - * @param \Closure $closure Closure evaluation function - * @param bool $static Set to TRUE to use the same class as the return rather than returning a Collection - * - * @return Collection - */ - public function filter(\Closure $closure, $static = true) - { - $collection = ($static) ? new static() : new self(); - foreach ($this->data as $key => $value) { - if ($closure($key, $value)) { - $collection->add($key, $value); - } - } - - return $collection; - } - - public function offsetExists($offset) - { - return isset($this->data[$offset]); - } - - public function offsetGet($offset) - { - return isset($this->data[$offset]) ? $this->data[$offset] : null; - } - - public function offsetSet($offset, $value) - { - $this->data[$offset] = $value; - } - - public function offsetUnset($offset) - { - unset($this->data[$offset]); - } - - /** - * Set a value into a nested array key. Keys will be created as needed to set the value. - * - * @param string $path Path to set - * @param mixed $value Value to set at the key - * - * @return self - * @throws RuntimeException when trying to setPath using a nested path that travels through a scalar value - */ - public function setPath($path, $value) - { - $current =& $this->data; - $queue = explode('/', $path); - while (null !== ($key = array_shift($queue))) { - if (!is_array($current)) { - throw new RuntimeException("Trying to setPath {$path}, but {$key} is set and is not an array"); - } elseif (!$queue) { - $current[$key] = $value; - } elseif (isset($current[$key])) { - $current =& $current[$key]; - } else { - $current[$key] = array(); - $current =& $current[$key]; - } - } - - return $this; - } - - /** - * Gets a value from the collection using an array path (e.g. foo/baz/bar would retrieve bar from two nested arrays) - * Allows for wildcard searches which recursively combine matches up to the level at which the wildcard occurs. This - * can be useful for accepting any key of a sub-array and combining matching keys from each diverging path. - * - * @param string $path Path to traverse and retrieve a value from - * @param string $separator Character used to add depth to the search - * @param mixed $data Optional data to descend into (used when wildcards are encountered) - * - * @return mixed|null - */ - public function getPath($path, $separator = '/', $data = null) - { - if ($data === null) { - $data =& $this->data; - } - - $path = is_array($path) ? $path : explode($separator, $path); - while (null !== ($part = array_shift($path))) { - if (!is_array($data)) { - return null; - } elseif (isset($data[$part])) { - $data =& $data[$part]; - } elseif ($part != '*') { - return null; - } else { - // Perform a wildcard search by diverging and merging paths - $result = array(); - foreach ($data as $value) { - if (!$path) { - $result = array_merge_recursive($result, (array) $value); - } elseif (null !== ($test = $this->getPath($path, $separator, $value))) { - $result = array_merge_recursive($result, (array) $test); - } - } - return $result; - } - } - - return $data; - } - - /** - * Inject configuration settings into an input string - * - * @param string $input Input to inject - * - * @return string - * @deprecated - */ - public function inject($input) - { - Version::warn(__METHOD__ . ' is deprecated'); - $replace = array(); - foreach ($this->data as $key => $val) { - $replace['{' . $key . '}'] = $val; - } - - return strtr($input, $replace); - } -} diff --git a/core/vendor/guzzle/common/Guzzle/Common/Event.php b/core/vendor/guzzle/common/Guzzle/Common/Event.php deleted file mode 100644 index fad76a9b817..00000000000 --- a/core/vendor/guzzle/common/Guzzle/Common/Event.php +++ /dev/null @@ -1,52 +0,0 @@ -context = $context; - } - - public function getIterator() - { - return new \ArrayIterator($this->context); - } - - public function offsetGet($offset) - { - return isset($this->context[$offset]) ? $this->context[$offset] : null; - } - - public function offsetSet($offset, $value) - { - $this->context[$offset] = $value; - } - - public function offsetExists($offset) - { - return isset($this->context[$offset]); - } - - public function offsetUnset($offset) - { - unset($this->context[$offset]); - } - - public function toArray() - { - return $this->context; - } -} diff --git a/core/vendor/guzzle/common/Guzzle/Common/Exception/BadMethodCallException.php b/core/vendor/guzzle/common/Guzzle/Common/Exception/BadMethodCallException.php deleted file mode 100644 index 08d1c7256d7..00000000000 --- a/core/vendor/guzzle/common/Guzzle/Common/Exception/BadMethodCallException.php +++ /dev/null @@ -1,5 +0,0 @@ -exceptions = array(); - foreach ($exceptions as $exception) { - $this->add($exception); - } - - return $this; - } - - /** - * Add exceptions to the collection - * - * @param ExceptionCollection|\Exception $e Exception to add - * - * @return ExceptionCollection; - */ - public function add($e) - { - if ($this->message) { - $this->message .= "\n"; - } - - if ($e instanceof self) { - $this->message .= '(' . get_class($e) . ")"; - foreach (explode("\n", $e->getMessage()) as $message) { - $this->message .= "\n {$message}"; - } - } elseif ($e instanceof \Exception) { - $this->exceptions[] = $e; - $this->message .= '(' . get_class($e) . ') ' . $e->getMessage(); - } - - return $this; - } - - /** - * Get the total number of request exceptions - * - * @return int - */ - public function count() - { - return count($this->exceptions); - } - - /** - * Allows array-like iteration over the request exceptions - * - * @return \ArrayIterator - */ - public function getIterator() - { - return new \ArrayIterator($this->exceptions); - } - - /** - * Get the first exception in the collection - * - * @return \Exception - */ - public function getFirst() - { - return $this->exceptions ? $this->exceptions[0] : null; - } -} diff --git a/core/vendor/guzzle/common/Guzzle/Common/Exception/GuzzleException.php b/core/vendor/guzzle/common/Guzzle/Common/Exception/GuzzleException.php deleted file mode 100644 index 458e6f2ea16..00000000000 --- a/core/vendor/guzzle/common/Guzzle/Common/Exception/GuzzleException.php +++ /dev/null @@ -1,8 +0,0 @@ -=5.3.2", - "symfony/event-dispatcher": ">=2.1" - }, - "autoload": { - "psr-0": { "Guzzle\\Common": "" } - }, - "target-dir": "Guzzle/Common", - "extra": { - "branch-alias": { - "dev-master": "3.7-dev" - } - } -} diff --git a/core/vendor/guzzle/http/Guzzle/Http/AbstractEntityBodyDecorator.php b/core/vendor/guzzle/http/Guzzle/Http/AbstractEntityBodyDecorator.php deleted file mode 100644 index 5005a887cf5..00000000000 --- a/core/vendor/guzzle/http/Guzzle/Http/AbstractEntityBodyDecorator.php +++ /dev/null @@ -1,221 +0,0 @@ -body = $body; - } - - public function __toString() - { - return (string) $this->body; - } - - /** - * Allow decorators to implement custom methods - * - * @param string $method Missing method name - * @param array $args Method arguments - * - * @return mixed - */ - public function __call($method, array $args) - { - return call_user_func_array(array($this->body, $method), $args); - } - - public function close() - { - return $this->body->close(); - } - - public function setRewindFunction($callable) - { - $this->body->setRewindFunction($callable); - - return $this; - } - - public function rewind() - { - return $this->body->rewind(); - } - - public function compress($filter = 'zlib.deflate') - { - return $this->body->compress($filter); - } - - public function uncompress($filter = 'zlib.inflate') - { - return $this->body->uncompress($filter); - } - - public function getContentLength() - { - return $this->getSize(); - } - - public function getContentType() - { - return $this->body->getContentType(); - } - - public function getContentMd5($rawOutput = false, $base64Encode = false) - { - $hash = Stream::getHash($this, 'md5', $rawOutput); - - return $hash && $base64Encode ? base64_encode($hash) : $hash; - } - - public function getContentEncoding() - { - return $this->body->getContentEncoding(); - } - - public function getMetaData($key = null) - { - return $this->body->getMetaData($key); - } - - public function getStream() - { - return $this->body->getStream(); - } - - public function setStream($stream, $size = 0) - { - $this->body->setStream($stream, $size); - - return $this; - } - - public function detachStream() - { - $this->body->detachStream(); - - return $this; - } - - public function getWrapper() - { - return $this->body->getWrapper(); - } - - public function getWrapperData() - { - return $this->body->getWrapperData(); - } - - public function getStreamType() - { - return $this->body->getStreamType(); - } - - public function getUri() - { - return $this->body->getUri(); - } - - public function getSize() - { - return $this->body->getSize(); - } - - public function isReadable() - { - return $this->body->isReadable(); - } - - public function isRepeatable() - { - return $this->isSeekable() && $this->isReadable(); - } - - public function isWritable() - { - return $this->body->isWritable(); - } - - public function isConsumed() - { - return $this->body->isConsumed(); - } - - /** - * Alias of isConsumed() - * {@inheritdoc} - */ - public function feof() - { - return $this->isConsumed(); - } - - public function isLocal() - { - return $this->body->isLocal(); - } - - public function isSeekable() - { - return $this->body->isSeekable(); - } - - public function setSize($size) - { - $this->body->setSize($size); - - return $this; - } - - public function seek($offset, $whence = SEEK_SET) - { - return $this->body->seek($offset, $whence); - } - - public function read($length) - { - return $this->body->read($length); - } - - public function write($string) - { - return $this->body->write($string); - } - - public function readLine($maxLength = null) - { - return $this->body->readLine($maxLength); - } - - public function ftell() - { - return $this->body->ftell(); - } - - public function getCustomData($key) - { - return $this->body->getCustomData($key); - } - - public function setCustomData($key, $value) - { - $this->body->setCustomData($key, $value); - - return $this; - } -} diff --git a/core/vendor/guzzle/http/Guzzle/Http/CachingEntityBody.php b/core/vendor/guzzle/http/Guzzle/Http/CachingEntityBody.php deleted file mode 100644 index c65c1365042..00000000000 --- a/core/vendor/guzzle/http/Guzzle/Http/CachingEntityBody.php +++ /dev/null @@ -1,229 +0,0 @@ -remoteStream = $body; - $this->body = new EntityBody(fopen('php://temp', 'r+')); - } - - /** - * Will give the contents of the buffer followed by the exhausted remote stream. - * - * Warning: Loads the entire stream into memory - * - * @return string - */ - public function __toString() - { - $pos = $this->ftell(); - $this->rewind(); - - $str = ''; - while (!$this->isConsumed()) { - $str .= $this->read(16384); - } - - $this->seek($pos); - - return $str; - } - - public function getSize() - { - return max($this->body->getSize(), $this->remoteStream->getSize()); - } - - /** - * {@inheritdoc} - * @throws RuntimeException When seeking with SEEK_END or when seeking past the total size of the buffer stream - */ - public function seek($offset, $whence = SEEK_SET) - { - if ($whence == SEEK_SET) { - $byte = $offset; - } elseif ($whence == SEEK_CUR) { - $byte = $offset + $this->ftell(); - } else { - throw new RuntimeException(__CLASS__ . ' supports only SEEK_SET and SEEK_CUR seek operations'); - } - - // You cannot skip ahead past where you've read from the remote stream - if ($byte > $this->body->getSize()) { - throw new RuntimeException( - "Cannot seek to byte {$byte} when the buffered stream only contains {$this->body->getSize()} bytes" - ); - } - - return $this->body->seek($byte); - } - - public function rewind() - { - return $this->seek(0); - } - - /** - * Does not support custom rewind functions - * - * @throws RuntimeException - */ - public function setRewindFunction($callable) - { - throw new RuntimeException(__CLASS__ . ' does not support custom stream rewind functions'); - } - - public function read($length) - { - // Perform a regular read on any previously read data from the buffer - $data = $this->body->read($length); - $remaining = $length - strlen($data); - - // More data was requested so read from the remote stream - if ($remaining) { - // If data was written to the buffer in a position that would have been filled from the remote stream, - // then we must skip bytes on the remote stream to emulate overwriting bytes from that position. This - // mimics the behavior of other PHP stream wrappers. - $remoteData = $this->remoteStream->read($remaining + $this->skipReadBytes); - - if ($this->skipReadBytes) { - $len = strlen($remoteData); - $remoteData = substr($remoteData, $this->skipReadBytes); - $this->skipReadBytes = max(0, $this->skipReadBytes - $len); - } - - $data .= $remoteData; - $this->body->write($remoteData); - } - - return $data; - } - - public function write($string) - { - // When appending to the end of the currently read stream, you'll want to skip bytes from being read from - // the remote stream to emulate other stream wrappers. Basically replacing bytes of data of a fixed length. - $overflow = (strlen($string) + $this->ftell()) - $this->remoteStream->ftell(); - if ($overflow > 0) { - $this->skipReadBytes += $overflow; - } - - return $this->body->write($string); - } - - /** - * {@inheritdoc} - * @link http://php.net/manual/en/function.fgets.php - */ - public function readLine($maxLength = null) - { - $buffer = ''; - $size = 0; - while (!$this->isConsumed()) { - $byte = $this->read(1); - $buffer .= $byte; - // Break when a new line is found or the max length - 1 is reached - if ($byte == PHP_EOL || ++$size == $maxLength - 1) { - break; - } - } - - return $buffer; - } - - public function isConsumed() - { - return $this->body->isConsumed() && $this->remoteStream->isConsumed(); - } - - /** - * Close both the remote stream and buffer stream - */ - public function close() - { - return $this->remoteStream->close() && $this->body->close(); - } - - public function setStream($stream, $size = 0) - { - $this->remoteStream->setStream($stream, $size); - } - - public function getContentType() - { - return $this->remoteStream->getContentType(); - } - - public function getContentEncoding() - { - return $this->remoteStream->getContentEncoding(); - } - - public function getMetaData($key = null) - { - return $this->remoteStream->getMetaData($key); - } - - public function getStream() - { - return $this->remoteStream->getStream(); - } - - public function getWrapper() - { - return $this->remoteStream->getWrapper(); - } - - public function getWrapperData() - { - return $this->remoteStream->getWrapperData(); - } - - public function getStreamType() - { - return $this->remoteStream->getStreamType(); - } - - public function getUri() - { - return $this->remoteStream->getUri(); - } - - /** - * Always retrieve custom data from the remote stream - * {@inheritdoc} - */ - public function getCustomData($key) - { - return $this->remoteStream->getCustomData($key); - } - - /** - * Always set custom data on the remote stream - * {@inheritdoc} - */ - public function setCustomData($key, $value) - { - $this->remoteStream->setCustomData($key, $value); - - return $this; - } -} diff --git a/core/vendor/guzzle/http/Guzzle/Http/Client.php b/core/vendor/guzzle/http/Guzzle/Http/Client.php deleted file mode 100644 index 465962149d1..00000000000 --- a/core/vendor/guzzle/http/Guzzle/Http/Client.php +++ /dev/null @@ -1,506 +0,0 @@ -setConfig($config ?: new Collection()); - $this->initSsl(); - $this->setBaseUrl($baseUrl); - $this->defaultHeaders = new Collection(); - $this->setRequestFactory(RequestFactory::getInstance()); - $this->userAgent = $this->getDefaultUserAgent(); - if (!$this->config[self::DISABLE_REDIRECTS]) { - $this->addSubscriber(new RedirectPlugin()); - } - } - - final public function setConfig($config) - { - if ($config instanceof Collection) { - $this->config = $config; - } elseif (is_array($config)) { - $this->config = new Collection($config); - } else { - throw new InvalidArgumentException('Config must be an array or Collection'); - } - - return $this; - } - - final public function getConfig($key = false) - { - return $key ? $this->config[$key] : $this->config; - } - - /** - * Set a default request option on the client that will be used as a default for each request - * - * @param string $keyOrPath request.options key (e.g. allow_redirects) or path to a nested key (e.g. headers/foo) - * @param mixed $value Value to set - * - * @return $this - */ - public function setDefaultOption($keyOrPath, $value) - { - $keyOrPath = self::REQUEST_OPTIONS . '/' . $keyOrPath; - $this->config->setPath($keyOrPath, $value); - - return $this; - } - - /** - * Retrieve a default request option from the client - * - * @param string $keyOrPath request.options key (e.g. allow_redirects) or path to a nested key (e.g. headers/foo) - * - * @return mixed|null - */ - public function getDefaultOption($keyOrPath) - { - $keyOrPath = self::REQUEST_OPTIONS . '/' . $keyOrPath; - - return $this->config->getPath($keyOrPath); - } - - final public function setSslVerification($certificateAuthority = true, $verifyPeer = true, $verifyHost = 2) - { - $opts = $this->config[self::CURL_OPTIONS] ?: array(); - - if ($certificateAuthority === true) { - // use bundled CA bundle, set secure defaults - $opts[CURLOPT_CAINFO] = __DIR__ . '/Resources/cacert.pem'; - $opts[CURLOPT_SSL_VERIFYPEER] = true; - $opts[CURLOPT_SSL_VERIFYHOST] = 2; - } elseif ($certificateAuthority === false) { - unset($opts[CURLOPT_CAINFO]); - $opts[CURLOPT_SSL_VERIFYPEER] = false; - $opts[CURLOPT_SSL_VERIFYHOST] = 2; - } elseif ($verifyPeer !== true && $verifyPeer !== false && $verifyPeer !== 1 && $verifyPeer !== 0) { - throw new InvalidArgumentException('verifyPeer must be 1, 0 or boolean'); - } elseif ($verifyHost !== 0 && $verifyHost !== 1 && $verifyHost !== 2) { - throw new InvalidArgumentException('verifyHost must be 0, 1 or 2'); - } else { - $opts[CURLOPT_SSL_VERIFYPEER] = $verifyPeer; - $opts[CURLOPT_SSL_VERIFYHOST] = $verifyHost; - if (is_file($certificateAuthority)) { - unset($opts[CURLOPT_CAPATH]); - $opts[CURLOPT_CAINFO] = $certificateAuthority; - } elseif (is_dir($certificateAuthority)) { - unset($opts[CURLOPT_CAINFO]); - $opts[CURLOPT_CAPATH] = $certificateAuthority; - } else { - throw new RuntimeException( - 'Invalid option passed to ' . self::SSL_CERT_AUTHORITY . ': ' . $certificateAuthority - ); - } - } - - $this->config->set(self::CURL_OPTIONS, $opts); - - return $this; - } - - public function createRequest($method = 'GET', $uri = null, $headers = null, $body = null, array $options = array()) - { - if (!$uri) { - $url = $this->getBaseUrl(); - } else { - if (!is_array($uri)) { - $templateVars = null; - } else { - list($uri, $templateVars) = $uri; - } - if (substr($uri, 0, 4) === 'http') { - // Use absolute URLs as-is - $url = $this->expandTemplate($uri, $templateVars); - } else { - $url = Url::factory($this->getBaseUrl())->combine($this->expandTemplate($uri, $templateVars)); - } - } - - // If default headers are provided, then merge them under any explicitly provided headers for the request - if (count($this->defaultHeaders)) { - if (!$headers) { - $headers = $this->defaultHeaders->toArray(); - } elseif (is_array($headers)) { - $headers += $this->defaultHeaders->toArray(); - } elseif ($headers instanceof Collection) { - $headers = $headers->toArray() + $this->defaultHeaders->toArray(); - } - } - - return $this->prepareRequest($this->requestFactory->create($method, (string) $url, $headers, $body), $options); - } - - public function getBaseUrl($expand = true) - { - return $expand ? $this->expandTemplate($this->baseUrl) : $this->baseUrl; - } - - public function setBaseUrl($url) - { - $this->baseUrl = $url; - - return $this; - } - - public function setUserAgent($userAgent, $includeDefault = false) - { - if ($includeDefault) { - $userAgent .= ' ' . $this->getDefaultUserAgent(); - } - $this->userAgent = $userAgent; - - return $this; - } - - /** - * Get the default User-Agent string to use with Guzzle - * - * @return string - */ - public function getDefaultUserAgent() - { - return 'Guzzle/' . Version::VERSION - . ' curl/' . CurlVersion::getInstance()->get('version') - . ' PHP/' . PHP_VERSION; - } - - public function get($uri = null, $headers = null, $options = array()) - { - // BC compat: $options can be a string, resource, etc to specify where the response body is downloaded - return is_array($options) - ? $this->createRequest('GET', $uri, $headers, null, $options) - : $this->createRequest('GET', $uri, $headers, $options); - } - - public function head($uri = null, $headers = null, array $options = array()) - { - return $this->createRequest('HEAD', $uri, $headers, null, $options); - } - - public function delete($uri = null, $headers = null, $body = null, array $options = array()) - { - return $this->createRequest('DELETE', $uri, $headers, $body, $options); - } - - public function put($uri = null, $headers = null, $body = null, array $options = array()) - { - return $this->createRequest('PUT', $uri, $headers, $body, $options); - } - - public function patch($uri = null, $headers = null, $body = null, array $options = array()) - { - return $this->createRequest('PATCH', $uri, $headers, $body, $options); - } - - public function post($uri = null, $headers = null, $postBody = null, array $options = array()) - { - return $this->createRequest('POST', $uri, $headers, $postBody, $options); - } - - public function options($uri = null, array $options = array()) - { - return $this->createRequest('OPTIONS', $uri, $options); - } - - public function send($requests) - { - if (!($requests instanceof RequestInterface)) { - return $this->sendMultiple($requests); - } - - try { - /** @var $requests RequestInterface */ - $this->getCurlMulti()->add($requests)->send(); - return $requests->getResponse(); - } catch (ExceptionCollection $e) { - throw $e->getFirst(); - } - } - - /** - * Set a curl multi object to be used internally by the client for transferring requests. - * - * @param CurlMultiInterface $curlMulti Multi object - * - * @return self - */ - public function setCurlMulti(CurlMultiInterface $curlMulti) - { - $this->curlMulti = $curlMulti; - - return $this; - } - - /** - * @return CurlMultiInterface|CurlMultiProxy - */ - public function getCurlMulti() - { - if (!$this->curlMulti) { - $this->curlMulti = new CurlMultiProxy(); - } - - return $this->curlMulti; - } - - public function setRequestFactory(RequestFactoryInterface $factory) - { - $this->requestFactory = $factory; - - return $this; - } - - /** - * Set the URI template expander to use with the client - * - * @param UriTemplateInterface $uriTemplate URI template expander - * - * @return self - */ - public function setUriTemplate(UriTemplateInterface $uriTemplate) - { - $this->uriTemplate = $uriTemplate; - - return $this; - } - - /** - * Copy the cacert.pem file from the phar if it is not in the temp folder and validate the MD5 checksum - * - * @param bool $md5Check Set to false to not perform the MD5 validation - * - * @return string Returns the path to the extracted cacert - * @throws RuntimeException if the file cannot be copied or there is a MD5 mismatch - */ - public function preparePharCacert($md5Check = true) - { - $from = __DIR__ . '/Resources/cacert.pem'; - $certFile = sys_get_temp_dir() . '/guzzle-cacert.pem'; - if (!file_exists($certFile) && !copy($from, $certFile)) { - throw new RuntimeException("Could not copy {$from} to {$certFile}: " . var_export(error_get_last(), true)); - } elseif ($md5Check) { - $actualMd5 = md5_file($certFile); - $expectedMd5 = trim(file_get_contents("{$from}.md5")); - if ($actualMd5 != $expectedMd5) { - throw new RuntimeException("{$certFile} MD5 mismatch: expected {$expectedMd5} but got {$actualMd5}"); - } - } - - return $certFile; - } - - /** - * Expand a URI template while merging client config settings into the template variables - * - * @param string $template Template to expand - * @param array $variables Variables to inject - * - * @return string - */ - protected function expandTemplate($template, array $variables = null) - { - $expansionVars = $this->getConfig()->toArray(); - if ($variables) { - $expansionVars = $variables + $expansionVars; - } - - return $this->getUriTemplate()->expand($template, $expansionVars); - } - - /** - * Get the URI template expander used by the client - * - * @return UriTemplateInterface - */ - protected function getUriTemplate() - { - if (!$this->uriTemplate) { - $this->uriTemplate = ParserRegistry::getInstance()->getParser('uri_template'); - } - - return $this->uriTemplate; - } - - /** - * Send multiple requests in parallel - * - * @param array $requests Array of RequestInterface objects - * - * @return array Returns an array of Response objects - */ - protected function sendMultiple(array $requests) - { - $curlMulti = $this->getCurlMulti(); - foreach ($requests as $request) { - $curlMulti->add($request); - } - $curlMulti->send(); - - /** @var $request RequestInterface */ - $result = array(); - foreach ($requests as $request) { - $result[] = $request->getResponse(); - } - - return $result; - } - - /** - * Prepare a request to be sent from the Client by adding client specific behaviors and properties to the request. - * - * @param RequestInterface $request Request to prepare for the client - * @param array $options Options to apply to the request - * - * @return RequestInterface - */ - protected function prepareRequest(RequestInterface $request, array $options = array()) - { - $request->setClient($this)->setEventDispatcher(clone $this->getEventDispatcher()); - - if ($curl = $this->config[self::CURL_OPTIONS]) { - $request->getCurlOptions()->overwriteWith(CurlHandle::parseCurlConfig($curl)); - } - - if ($params = $this->config[self::REQUEST_PARAMS]) { - Version::warn('request.params is deprecated. Use request.options to add default request options.'); - $request->getParams()->overwriteWith($params); - } - - if ($this->userAgent && !$request->hasHeader('User-Agent')) { - $request->setHeader('User-Agent', $this->userAgent); - } - - if ($defaults = $this->config[self::REQUEST_OPTIONS]) { - $this->requestFactory->applyOptions($request, $defaults, RequestFactoryInterface::OPTIONS_AS_DEFAULTS); - } - - if ($options) { - $this->requestFactory->applyOptions($request, $options); - } - - $this->dispatch('client.create_request', array('client' => $this, 'request' => $request)); - - return $request; - } - - /** - * Initializes SSL settings - */ - protected function initSsl() - { - if ('system' == ($authority = $this->config[self::SSL_CERT_AUTHORITY])) { - return; - } - - if ($authority === null) { - $authority = true; - } - - if ($authority === true && substr(__FILE__, 0, 7) == 'phar://') { - $authority = $this->preparePharCacert(); - $that = $this; - $this->getEventDispatcher()->addListener('request.before_send', function ($event) use ($authority, $that) { - if ($authority == $event['request']->getCurlOptions()->get(CURLOPT_CAINFO)) { - $that->preparePharCacert(false); - } - }); - } - - $this->setSslVerification($authority); - } - - /** - * @deprecated - */ - public function getDefaultHeaders() - { - Version::warn(__METHOD__ . ' is deprecated. Use the request.options array to retrieve default request options'); - return $this->defaultHeaders; - } - - /** - * @deprecated - */ - public function setDefaultHeaders($headers) - { - Version::warn(__METHOD__ . ' is deprecated. Use the request.options array to specify default request options'); - if ($headers instanceof Collection) { - $this->defaultHeaders = $headers; - } elseif (is_array($headers)) { - $this->defaultHeaders = new Collection($headers); - } else { - throw new InvalidArgumentException('Headers must be an array or Collection'); - } - - return $this; - } -} diff --git a/core/vendor/guzzle/http/Guzzle/Http/ClientInterface.php b/core/vendor/guzzle/http/Guzzle/Http/ClientInterface.php deleted file mode 100644 index 10e4de2ab09..00000000000 --- a/core/vendor/guzzle/http/Guzzle/Http/ClientInterface.php +++ /dev/null @@ -1,223 +0,0 @@ -getCurlOptions(); - $mediator = new RequestMediator($request, $requestCurlOptions->get('emit_io')); - $tempContentLength = null; - $method = $request->getMethod(); - $bodyAsString = $requestCurlOptions->get(self::BODY_AS_STRING); - - // Array of default cURL options. - $curlOptions = array( - CURLOPT_URL => $request->getUrl(), - CURLOPT_CONNECTTIMEOUT => 150, - CURLOPT_RETURNTRANSFER => false, - CURLOPT_HEADER => false, - CURLOPT_PORT => $request->getPort(), - CURLOPT_HTTPHEADER => array(), - CURLOPT_WRITEFUNCTION => array($mediator, 'writeResponseBody'), - CURLOPT_HEADERFUNCTION => array($mediator, 'receiveResponseHeader'), - CURLOPT_HTTP_VERSION => $request->getProtocolVersion() === '1.0' - ? CURL_HTTP_VERSION_1_0 : CURL_HTTP_VERSION_1_1, - // Verifies the authenticity of the peer's certificate - CURLOPT_SSL_VERIFYPEER => 1, - // Certificate must indicate that the server is the server to which you meant to connect - CURLOPT_SSL_VERIFYHOST => 2 - ); - - if (defined('CURLOPT_PROTOCOLS')) { - // Allow only HTTP and HTTPS protocols - $curlOptions[CURLOPT_PROTOCOLS] = CURLPROTO_HTTP | CURLPROTO_HTTPS; - } - - // Add CURLOPT_ENCODING if Accept-Encoding header is provided - if ($acceptEncodingHeader = $request->getHeader('Accept-Encoding')) { - $curlOptions[CURLOPT_ENCODING] = (string) $acceptEncodingHeader; - // Let cURL set the Accept-Encoding header, prevents duplicate values - $request->removeHeader('Accept-Encoding'); - } - - // Enable curl debug information if the 'debug' param was set - if ($requestCurlOptions->get('debug')) { - $curlOptions[CURLOPT_STDERR] = fopen('php://temp', 'r+'); - // @codeCoverageIgnoreStart - if (false === $curlOptions[CURLOPT_STDERR]) { - throw new RuntimeException('Unable to create a stream for CURLOPT_STDERR'); - } - // @codeCoverageIgnoreEnd - $curlOptions[CURLOPT_VERBOSE] = true; - } - - // Specify settings according to the HTTP method - if ($method == 'GET') { - $curlOptions[CURLOPT_HTTPGET] = true; - } elseif ($method == 'HEAD') { - $curlOptions[CURLOPT_NOBODY] = true; - // HEAD requests do not use a write function - unset($curlOptions[CURLOPT_WRITEFUNCTION]); - } elseif (!($request instanceof EntityEnclosingRequest)) { - $curlOptions[CURLOPT_CUSTOMREQUEST] = $method; - } else { - - $curlOptions[CURLOPT_CUSTOMREQUEST] = $method; - - // Handle sending raw bodies in a request - if ($request->getBody()) { - // You can send the body as a string using curl's CURLOPT_POSTFIELDS - if ($bodyAsString) { - $curlOptions[CURLOPT_POSTFIELDS] = (string) $request->getBody(); - // Allow curl to add the Content-Length for us to account for the times when - // POST redirects are followed by GET requests - if ($tempContentLength = $request->getHeader('Content-Length')) { - $tempContentLength = (int) (string) $tempContentLength; - } - // Remove the curl generated Content-Type header if none was set manually - if (!$request->hasHeader('Content-Type')) { - $curlOptions[CURLOPT_HTTPHEADER][] = 'Content-Type:'; - } - } else { - $curlOptions[CURLOPT_UPLOAD] = true; - // Let cURL handle setting the Content-Length header - if ($tempContentLength = $request->getHeader('Content-Length')) { - $tempContentLength = (int) (string) $tempContentLength; - $curlOptions[CURLOPT_INFILESIZE] = $tempContentLength; - } - // Add a callback for curl to read data to send with the request only if a body was specified - $curlOptions[CURLOPT_READFUNCTION] = array($mediator, 'readRequestBody'); - // Attempt to seek to the start of the stream - $request->getBody()->seek(0); - } - - } else { - - // Special handling for POST specific fields and files - $postFields = false; - if (count($request->getPostFiles())) { - $postFields = $request->getPostFields()->useUrlEncoding(false)->urlEncode(); - foreach ($request->getPostFiles() as $key => $data) { - $prefixKeys = count($data) > 1; - foreach ($data as $index => $file) { - // Allow multiple files in the same key - $fieldKey = $prefixKeys ? "{$key}[{$index}]" : $key; - $postFields[$fieldKey] = $file->getCurlValue(); - } - } - } elseif (count($request->getPostFields())) { - $postFields = (string) $request->getPostFields()->useUrlEncoding(true); - } - - if ($postFields !== false) { - if ($method == 'POST') { - unset($curlOptions[CURLOPT_CUSTOMREQUEST]); - $curlOptions[CURLOPT_POST] = true; - } - $curlOptions[CURLOPT_POSTFIELDS] = $postFields; - $request->removeHeader('Content-Length'); - } - } - - // If the Expect header is not present, prevent curl from adding it - if (!$request->hasHeader('Expect')) { - $curlOptions[CURLOPT_HTTPHEADER][] = 'Expect:'; - } - } - - // If a Content-Length header was specified but we want to allow curl to set one for us - if (null !== $tempContentLength) { - $request->removeHeader('Content-Length'); - } - - // Set custom cURL options - foreach ($requestCurlOptions->toArray() as $key => $value) { - if (is_numeric($key)) { - $curlOptions[$key] = $value; - } - } - - // Do not set an Accept header by default - if (!isset($curlOptions[CURLOPT_ENCODING])) { - $curlOptions[CURLOPT_HTTPHEADER][] = 'Accept:'; - } - - // Add any custom headers to the request. Empty headers will cause curl to not send the header at all. - foreach ($request->getHeaderLines() as $line) { - $curlOptions[CURLOPT_HTTPHEADER][] = $line; - } - - // Add the content-length header back if it was temporarily removed - if ($tempContentLength) { - $request->setHeader('Content-Length', $tempContentLength); - } - - // Apply the options to a new cURL handle. - $handle = curl_init(); - - // Enable the progress function if the 'progress' param was set - if ($requestCurlOptions->get('progress')) { - // Wrap the function in a function that provides the curl handle to the mediator's progress function - // Using this rather than injecting the handle into the mediator prevents a circular reference - $curlOptions[CURLOPT_PROGRESSFUNCTION] = function () use ($mediator, $handle) { - $args = func_get_args(); - $args[] = $handle; - call_user_func_array(array($mediator, 'progress'), $args); - }; - $curlOptions[CURLOPT_NOPROGRESS] = false; - } - - curl_setopt_array($handle, $curlOptions); - - return new static($handle, $curlOptions); - } - - /** - * Construct a new CurlHandle object that wraps a cURL handle - * - * @param resource $handle Configured cURL handle resource - * @param Collection|array $options Curl options to use with the handle - * - * @throws InvalidArgumentException - */ - public function __construct($handle, $options) - { - if (!is_resource($handle)) { - throw new InvalidArgumentException('Invalid handle provided'); - } - if (is_array($options)) { - $this->options = new Collection($options); - } elseif ($options instanceof Collection) { - $this->options = $options; - } else { - throw new InvalidArgumentException('Expected array or Collection'); - } - $this->handle = $handle; - } - - /** - * Destructor - */ - public function __destruct() - { - $this->close(); - } - - /** - * Close the curl handle - */ - public function close() - { - if (is_resource($this->handle)) { - curl_close($this->handle); - } - $this->handle = null; - } - - /** - * Check if the handle is available and still OK - * - * @return bool - */ - public function isAvailable() - { - return is_resource($this->handle); - } - - /** - * Get the last error that occurred on the cURL handle - * - * @return string - */ - public function getError() - { - return $this->isAvailable() ? curl_error($this->handle) : ''; - } - - /** - * Get the last error number that occurred on the cURL handle - * - * @return int - */ - public function getErrorNo() - { - if ($this->errorNo) { - return $this->errorNo; - } - - return $this->isAvailable() ? curl_errno($this->handle) : CURLE_OK; - } - - /** - * Set the curl error number - * - * @param int $error Error number to set - * - * @return CurlHandle - */ - public function setErrorNo($error) - { - $this->errorNo = $error; - - return $this; - } - - /** - * Get cURL curl_getinfo data - * - * @param int $option Option to retrieve. Pass null to retrieve all data as an array. - * - * @return array|mixed - */ - public function getInfo($option = null) - { - if (!is_resource($this->handle)) { - return null; - } - - if (null !== $option) { - return curl_getinfo($this->handle, $option) ?: null; - } - - return curl_getinfo($this->handle) ?: array(); - } - - /** - * Get the stderr output - * - * @param bool $asResource Set to TRUE to get an fopen resource - * - * @return string|resource|null - */ - public function getStderr($asResource = false) - { - $stderr = $this->getOptions()->get(CURLOPT_STDERR); - if (!$stderr) { - return null; - } - - if ($asResource) { - return $stderr; - } - - fseek($stderr, 0); - $e = stream_get_contents($stderr); - fseek($stderr, 0, SEEK_END); - - return $e; - } - - /** - * Get the URL that this handle is connecting to - * - * @return Url - */ - public function getUrl() - { - return Url::factory($this->options->get(CURLOPT_URL)); - } - - /** - * Get the wrapped curl handle - * - * @return resource|null Returns the cURL handle or null if it was closed - */ - public function getHandle() - { - return $this->isAvailable() ? $this->handle : null; - } - - /** - * Get the cURL setopt options of the handle. Changing values in the return object will have no effect on the curl - * handle after it is created. - * - * @return Collection - */ - public function getOptions() - { - return $this->options; - } - - /** - * Update a request based on the log messages of the CurlHandle - * - * @param RequestInterface $request Request to update - */ - public function updateRequestFromTransfer(RequestInterface $request) - { - if (!$request->getResponse()) { - return; - } - - // Update the transfer stats of the response - $request->getResponse()->setInfo($this->getInfo()); - - if (!$log = $this->getStderr(true)) { - return; - } - - // Parse the cURL stderr output for outgoing requests - $headers = ''; - fseek($log, 0); - while (($line = fgets($log)) !== false) { - if ($line && $line[0] == '>') { - $headers = substr(trim($line), 2) . "\r\n"; - while (($line = fgets($log)) !== false) { - if ($line[0] == '*' || $line[0] == '<') { - break; - } else { - $headers .= trim($line) . "\r\n"; - } - } - } - } - - // Add request headers to the request exactly as they were sent - if ($headers) { - $parsed = ParserRegistry::getInstance()->getParser('message')->parseRequest($headers); - if (!empty($parsed['headers'])) { - $request->setHeaders(array()); - foreach ($parsed['headers'] as $name => $value) { - $request->setHeader($name, $value); - } - } - if (!empty($parsed['version'])) { - $request->setProtocolVersion($parsed['version']); - } - } - } - - /** - * Parse the config and replace curl.* configurators into the constant based values so it can be used elsewhere - * - * @param array|Collection $config The configuration we want to parse - * - * @return array - */ - public static function parseCurlConfig($config) - { - $curlOptions = array(); - foreach ($config as $key => $value) { - if (is_string($key) && defined($key)) { - // Convert constants represented as string to constant int values - $key = constant($key); - } - if (is_string($value) && defined($value)) { - $value = constant($value); - } - $curlOptions[$key] = $value; - } - - return $curlOptions; - } -} diff --git a/core/vendor/guzzle/http/Guzzle/Http/Curl/CurlMulti.php b/core/vendor/guzzle/http/Guzzle/Http/Curl/CurlMulti.php deleted file mode 100644 index a8c569984d2..00000000000 --- a/core/vendor/guzzle/http/Guzzle/Http/Curl/CurlMulti.php +++ /dev/null @@ -1,390 +0,0 @@ - array('CURLM_BAD_HANDLE', 'The passed-in handle is not a valid CURLM handle.'), - CURLM_BAD_EASY_HANDLE => array('CURLM_BAD_EASY_HANDLE', "An easy handle was not good/valid. It could mean that it isn't an easy handle at all, or possibly that the handle already is in used by this or another multi handle."), - CURLM_OUT_OF_MEMORY => array('CURLM_OUT_OF_MEMORY', 'You are doomed.'), - CURLM_INTERNAL_ERROR => array('CURLM_INTERNAL_ERROR', 'This can only be returned if libcurl bugs. Please report it to us!') - ); - - public function __construct() - { - $this->multiHandle = curl_multi_init(); - // @codeCoverageIgnoreStart - if ($this->multiHandle === false) { - throw new CurlException('Unable to create multi handle'); - } - // @codeCoverageIgnoreEnd - $this->reset(); - } - - public function __destruct() - { - if (is_resource($this->multiHandle)) { - curl_multi_close($this->multiHandle); - } - } - - public function add(RequestInterface $request) - { - $this->requests[] = $request; - // If requests are currently transferring and this is async, then the - // request must be prepared now as the send() method is not called. - $this->beforeSend($request); - $this->dispatch(self::ADD_REQUEST, array('request' => $request)); - - return $this; - } - - public function all() - { - return $this->requests; - } - - public function remove(RequestInterface $request) - { - $this->removeHandle($request); - foreach ($this->requests as $i => $r) { - if ($request === $r) { - unset($this->requests[$i]); - $this->requests = array_values($this->requests); - $this->dispatch(self::REMOVE_REQUEST, array('request' => $request)); - return true; - } - } - - return false; - } - - public function reset($hard = false) - { - // Remove each request - if ($this->requests) { - foreach ($this->requests as $request) { - $this->remove($request); - } - } - - $this->handles = new \SplObjectStorage(); - $this->requests = $this->resourceHash = $this->exceptions = $this->successful = array(); - } - - public function send() - { - $this->perform(); - $exceptions = $this->exceptions; - $successful = $this->successful; - $this->reset(); - - if ($exceptions) { - $this->throwMultiException($exceptions, $successful); - } - } - - public function count() - { - return count($this->requests); - } - - /** - * Build and throw a MultiTransferException - * - * @param array $exceptions Exceptions encountered - * @param array $successful Successful requests - * @throws MultiTransferException - */ - protected function throwMultiException(array $exceptions, array $successful) - { - $multiException = new MultiTransferException('Errors during multi transfer'); - - while ($e = array_shift($exceptions)) { - $multiException->add($e['exception']); - $multiException->addFailedRequest($e['request']); - } - - // Add successful requests - foreach ($successful as $request) { - if (!$multiException->containsRequest($request)) { - $multiException->addSuccessfulRequest($request); - } - } - - throw $multiException; - } - - /** - * Prepare for sending - * - * @param RequestInterface $request Request to prepare - * @throws \Exception on error preparing the request - */ - protected function beforeSend(RequestInterface $request) - { - try { - $state = $request->setState(RequestInterface::STATE_TRANSFER); - if ($state == RequestInterface::STATE_TRANSFER) { - // Add the request curl handle to the multi handle - $this->checkCurlResult(curl_multi_add_handle($this->multiHandle, $this->createCurlHandle($request)->getHandle())); - } else { - // Requests might decide they don't need to be sent just before transfer (e.g. CachePlugin) - $this->remove($request); - if ($state == RequestInterface::STATE_COMPLETE) { - $this->successful[] = $request; - } - } - } catch (\Exception $e) { - // Queue the exception to be thrown when sent - $this->removeErroredRequest($request, $e); - } - } - - /** - * Create a curl handle for a request - * - * @param RequestInterface $request Request - * - * @return CurlHandle - */ - protected function createCurlHandle(RequestInterface $request) - { - $wrapper = CurlHandle::factory($request); - $this->handles[$request] = $wrapper; - $this->resourceHash[(int) $wrapper->getHandle()] = $request; - - return $wrapper; - } - - /** - * Get the data from the multi handle - */ - protected function perform() - { - if (!$this->requests) { - return; - } - - // Initialize the handles with a very quick select timeout - $active = $mrc = null; - $this->executeHandles($active, $mrc, 0.001); - $event = new Event(array('curl_multi' => $this)); - $this->processMessages(); - - while ($this->requests) { - - // Notify each request as polling - $blocking = $total = 0; - foreach ($this->requests as $request) { - ++$total; - $event['request'] = $request; - $request->getEventDispatcher()->dispatch(self::POLLING_REQUEST, $event); - // The blocking variable just has to be non-falsey to block the loop - if ($request->getParams()->hasKey(self::BLOCKING)) { - ++$blocking; - } - } - - if ($blocking == $total) { - // Sleep to prevent eating CPU because no requests are actually pending a select call - usleep(500); - } else { - do { - $this->executeHandles($active, $mrc, 1); - } while ($active); - } - $this->processMessages(); - } - } - - /** - * Process any received curl multi messages - */ - private function processMessages() - { - // Get messages from curl handles - while ($done = curl_multi_info_read($this->multiHandle)) { - try { - $request = $this->resourceHash[(int) $done['handle']]; - $this->processResponse($request, $this->handles[$request], $done); - $this->successful[] = $request; - } catch (MultiTransferException $e) { - $this->removeErroredRequest($request, $e, false); - throw $e; - } catch (\Exception $e) { - $this->removeErroredRequest($request, $e); - } - } - } - - /** - * Execute and select curl handles until there is activity - * - * @param int $active Active value to update - * @param int $mrc Multi result value to update - * @param int $timeout Select timeout in seconds - */ - private function executeHandles(&$active, &$mrc, $timeout = 1) - { - do { - $mrc = curl_multi_exec($this->multiHandle, $active); - } while ($mrc == CURLM_CALL_MULTI_PERFORM && $active); - $this->checkCurlResult($mrc); - - // @codeCoverageIgnoreStart - // Select the curl handles until there is any activity on any of the open file descriptors - // See https://github.com/php/php-src/blob/master/ext/curl/multi.c#L170 - if ($active && $mrc == CURLM_OK && curl_multi_select($this->multiHandle, $timeout) == -1) { - // Perform a usleep if a previously executed select returned -1 - // @see https://bugs.php.net/bug.php?id=61141 - usleep(100); - } - // @codeCoverageIgnoreEnd - } - - /** - * Remove a request that encountered an exception - * - * @param RequestInterface $request Request to remove - * @param \Exception $e Exception encountered - * @param bool $buffer Set to false to not buffer the exception - */ - protected function removeErroredRequest(RequestInterface $request, \Exception $e = null, $buffer = true) - { - if ($buffer) { - $this->exceptions[] = array('request' => $request, 'exception' => $e); - } - - $this->remove($request); - $this->dispatch(self::MULTI_EXCEPTION, array('exception' => $e, 'all_exceptions' => $this->exceptions)); - } - - /** - * Check for errors and fix headers of a request based on a curl response - * - * @param RequestInterface $request Request to process - * @param CurlHandle $handle Curl handle object - * @param array $curl Array returned from curl_multi_info_read - * - * @throws CurlException on Curl error - */ - protected function processResponse(RequestInterface $request, CurlHandle $handle, array $curl) - { - // Set the transfer stats on the response - $handle->updateRequestFromTransfer($request); - // Check if a cURL exception occurred, and if so, notify things - $curlException = $this->isCurlException($request, $handle, $curl); - - // Always remove completed curl handles. They can be added back again - // via events if needed (e.g. ExponentialBackoffPlugin) - $this->removeHandle($request); - - if (!$curlException) { - $state = $request->setState(RequestInterface::STATE_COMPLETE, array('handle' => $handle)); - // Only remove the request if it wasn't resent as a result of the state change - if ($state != RequestInterface::STATE_TRANSFER) { - $this->remove($request); - } - } else { - // Set the state of the request to an error - $state = $request->setState(RequestInterface::STATE_ERROR, array('exception' => $curlException)); - // Allow things to ignore the error if possible - if ($state != RequestInterface::STATE_TRANSFER) { - $this->remove($request); - } - // The error was not handled, so fail - if ($state == RequestInterface::STATE_ERROR) { - /** @var CurlException $curlException */ - throw $curlException; - } - } - } - - /** - * Remove a curl handle from the curl multi object - * - * @param RequestInterface $request Request that owns the handle - */ - protected function removeHandle(RequestInterface $request) - { - if (isset($this->handles[$request])) { - $handle = $this->handles[$request]; - unset($this->handles[$request]); - unset($this->resourceHash[(int) $handle->getHandle()]); - curl_multi_remove_handle($this->multiHandle, $handle->getHandle()); - $handle->close(); - } - } - - /** - * Check if a cURL transfer resulted in what should be an exception - * - * @param RequestInterface $request Request to check - * @param CurlHandle $handle Curl handle object - * @param array $curl Array returned from curl_multi_info_read - * - * @return CurlException|bool - */ - private function isCurlException(RequestInterface $request, CurlHandle $handle, array $curl) - { - if (CURLM_OK == $curl['result'] || CURLM_CALL_MULTI_PERFORM == $curl['result']) { - return false; - } - - $handle->setErrorNo($curl['result']); - $e = new CurlException(sprintf('[curl] %s: %s [url] %s', - $handle->getErrorNo(), $handle->getError(), $handle->getUrl())); - $e->setCurlHandle($handle) - ->setRequest($request) - ->setCurlInfo($handle->getInfo()) - ->setError($handle->getError(), $handle->getErrorNo()); - - return $e; - } - - /** - * Throw an exception for a cURL multi response if needed - * - * @param int $code Curl response code - * @throws CurlException - */ - private function checkCurlResult($code) - { - if ($code != CURLM_OK && $code != CURLM_CALL_MULTI_PERFORM) { - throw new CurlException(isset($this->multiErrors[$code]) - ? "cURL error: {$code} ({$this->multiErrors[$code][0]}): cURL message: {$this->multiErrors[$code][1]}" - : 'Unexpected cURL error: ' . $code - ); - } - } -} diff --git a/core/vendor/guzzle/http/Guzzle/Http/Curl/CurlMultiInterface.php b/core/vendor/guzzle/http/Guzzle/Http/Curl/CurlMultiInterface.php deleted file mode 100644 index 0ead7573502..00000000000 --- a/core/vendor/guzzle/http/Guzzle/Http/Curl/CurlMultiInterface.php +++ /dev/null @@ -1,58 +0,0 @@ -maxHandles = $maxHandles; - // You can get some weird "Too many open files" errors when sending a large amount of requests in parallel. - // These two statements autoload classes before a system runs out of file descriptors so that you can get back - // valuable error messages if you run out. - class_exists('Guzzle\Http\Message\Response'); - class_exists('Guzzle\Http\Exception\CurlException'); - } - - public function add(RequestInterface $request) - { - $this->queued[] = $request; - - return $this; - } - - public function all() - { - $requests = $this->queued; - foreach ($this->handles as $handle) { - $requests = array_merge($requests, $handle->all()); - } - - return $requests; - } - - public function remove(RequestInterface $request) - { - foreach ($this->queued as $i => $r) { - if ($request === $r) { - unset($this->queued[$i]); - return true; - } - } - - foreach ($this->handles as $handle) { - if ($handle->remove($request)) { - return true; - } - } - - return false; - } - - public function reset($hard = false) - { - $this->queued = array(); - $this->groups = array(); - foreach ($this->handles as $handle) { - $handle->reset(); - } - if ($hard) { - $this->handles = array(); - } - - return $this; - } - - public function send() - { - if ($this->queued) { - $group = $this->getAvailableHandle(); - // Add this handle to a list of handles than is claimed - $this->groups[] = $group; - while ($request = array_shift($this->queued)) { - $group->add($request); - } - try { - $group->send(); - array_pop($this->groups); - $this->cleanupHandles(); - } catch (\Exception $e) { - // Remove the group and cleanup if an exception was encountered and no more requests in group - if (!$group->count()) { - array_pop($this->groups); - $this->cleanupHandles(); - } - throw $e; - } - } - } - - public function count() - { - return count($this->all()); - } - - /** - * Get an existing available CurlMulti handle or create a new one - * - * @return CurlMulti - */ - protected function getAvailableHandle() - { - // Grab a handle that is not claimed - foreach ($this->handles as $h) { - if (!in_array($h, $this->groups, true)) { - return $h; - } - } - - // All are claimed, so create one - $handle = new CurlMulti(); - $handle->setEventDispatcher($this->getEventDispatcher()); - $this->handles[] = $handle; - - return $handle; - } - - /** - * Trims down unused CurlMulti handles to limit the number of open connections - */ - protected function cleanupHandles() - { - if ($diff = max(0, count($this->handles) - $this->maxHandles)) { - for ($i = count($this->handles) - 1; $i > 0 && $diff > 0; $i--) { - if (!count($this->handles[$i])) { - unset($this->handles[$i]); - $diff--; - } - } - $this->handles = array_values($this->handles); - } - } -} diff --git a/core/vendor/guzzle/http/Guzzle/Http/Curl/CurlVersion.php b/core/vendor/guzzle/http/Guzzle/Http/Curl/CurlVersion.php deleted file mode 100644 index c3f99dd25dd..00000000000 --- a/core/vendor/guzzle/http/Guzzle/Http/Curl/CurlVersion.php +++ /dev/null @@ -1,66 +0,0 @@ -version) { - $this->version = curl_version(); - } - - return $this->version; - } - - /** - * Get a specific type of curl information - * - * @param string $type Version information to retrieve. This value is one of: - * - version_number: cURL 24 bit version number - * - version: cURL version number, as a string - * - ssl_version_number: OpenSSL 24 bit version number - * - ssl_version: OpenSSL version number, as a string - * - libz_version: zlib version number, as a string - * - host: Information about the host where cURL was built - * - features: A bitmask of the CURL_VERSION_XXX constants - * - protocols: An array of protocols names supported by cURL - * - * @return string|float|bool if the $type is found, and false if not found - */ - public function get($type) - { - $version = $this->getAll(); - - return isset($version[$type]) ? $version[$type] : false; - } -} diff --git a/core/vendor/guzzle/http/Guzzle/Http/Curl/RequestMediator.php b/core/vendor/guzzle/http/Guzzle/Http/Curl/RequestMediator.php deleted file mode 100644 index 54b1b0d57d3..00000000000 --- a/core/vendor/guzzle/http/Guzzle/Http/Curl/RequestMediator.php +++ /dev/null @@ -1,142 +0,0 @@ -request = $request; - $this->emitIo = $emitIo; - } - - /** - * Receive a response header from curl - * - * @param resource $curl Curl handle - * @param string $header Received header - * - * @return int - */ - public function receiveResponseHeader($curl, $header) - { - static $normalize = array("\r", "\n"); - $length = strlen($header); - $header = str_replace($normalize, '', $header); - - if (strpos($header, 'HTTP/') === 0) { - - $startLine = explode(' ', $header, 3); - $code = $startLine[1]; - $status = isset($startLine[2]) ? $startLine[2] : ''; - - // Only download the body of the response to the specified response - // body when a successful response is received. - if ($code >= 200 && $code < 300) { - $body = $this->request->getResponseBody(); - } else { - $body = EntityBody::factory(); - } - - $response = new Response($code, null, $body); - $response->setStatus($code, $status); - $this->request->startResponse($response); - - $this->request->dispatch('request.receive.status_line', array( - 'request' => $this, - 'line' => $header, - 'status_code' => $code, - 'reason_phrase' => $status - )); - - } elseif ($pos = strpos($header, ':')) { - $this->request->getResponse()->addHeader( - trim(substr($header, 0, $pos)), - trim(substr($header, $pos + 1)) - ); - } - - return $length; - } - - /** - * Received a progress notification - * - * @param int $downloadSize Total download size - * @param int $downloaded Amount of bytes downloaded - * @param int $uploadSize Total upload size - * @param int $uploaded Amount of bytes uploaded - * @param resource $handle CurlHandle object - */ - public function progress($downloadSize, $downloaded, $uploadSize, $uploaded, $handle = null) - { - $this->request->dispatch('curl.callback.progress', array( - 'request' => $this->request, - 'handle' => $handle, - 'download_size' => $downloadSize, - 'downloaded' => $downloaded, - 'upload_size' => $uploadSize, - 'uploaded' => $uploaded - )); - } - - /** - * Write data to the response body of a request - * - * @param resource $curl Curl handle - * @param string $write Data that was received - * - * @return int - */ - public function writeResponseBody($curl, $write) - { - if ($this->emitIo) { - $this->request->dispatch('curl.callback.write', array( - 'request' => $this->request, - 'write' => $write - )); - } - - return $this->request->getResponse()->getBody()->write($write); - } - - /** - * Read data from the request body and send it to curl - * - * @param resource $ch Curl handle - * @param resource $fd File descriptor - * @param int $length Amount of data to read - * - * @return string - */ - public function readRequestBody($ch, $fd, $length) - { - if (!($body = $this->request->getBody())) { - return ''; - } - - $read = (string) $body->read($length); - if ($this->emitIo) { - $this->request->dispatch('curl.callback.read', array('request' => $this->request, 'read' => $read)); - } - - return $read; - } -} diff --git a/core/vendor/guzzle/http/Guzzle/Http/EntityBody.php b/core/vendor/guzzle/http/Guzzle/Http/EntityBody.php deleted file mode 100644 index b60d170f02a..00000000000 --- a/core/vendor/guzzle/http/Guzzle/Http/EntityBody.php +++ /dev/null @@ -1,201 +0,0 @@ -rewindFunction = $callable; - - return $this; - } - - public function rewind() - { - return $this->rewindFunction ? call_user_func($this->rewindFunction, $this) : parent::rewind(); - } - - /** - * Create a new EntityBody from a string - * - * @param string $string String of data - * - * @return EntityBody - */ - public static function fromString($string) - { - $stream = fopen('php://temp', 'r+'); - if ($string !== '') { - fwrite($stream, $string); - rewind($stream); - } - - return new static($stream); - } - - public function compress($filter = 'zlib.deflate') - { - $result = $this->handleCompression($filter); - $this->contentEncoding = $result ? $filter : false; - - return $result; - } - - public function uncompress($filter = 'zlib.inflate') - { - $offsetStart = 0; - - // When inflating gzipped data, the first 10 bytes must be stripped - // if a gzip header is present - if ($filter == 'zlib.inflate') { - // @codeCoverageIgnoreStart - if (!$this->isReadable() || ($this->isConsumed() && !$this->isSeekable())) { - return false; - } - // @codeCoverageIgnoreEnd - if (stream_get_contents($this->stream, 3, 0) === "\x1f\x8b\x08") { - $offsetStart = 10; - } - } - - $this->contentEncoding = false; - - return $this->handleCompression($filter, $offsetStart); - } - - public function getContentLength() - { - return $this->getSize(); - } - - public function getContentType() - { - return $this->getUri() ? Mimetypes::getInstance()->fromFilename($this->getUri()) : null; - } - - public function getContentMd5($rawOutput = false, $base64Encode = false) - { - if ($hash = self::getHash($this, 'md5', $rawOutput)) { - return $hash && $base64Encode ? base64_encode($hash) : $hash; - } else { - return false; - } - } - - /** - * Calculate the MD5 hash of an entity body - * - * @param EntityBodyInterface $body Entity body to calculate the hash for - * @param bool $rawOutput Whether or not to use raw output - * @param bool $base64Encode Whether or not to base64 encode raw output (only if raw output is true) - * - * @return bool|string Returns an MD5 string on success or FALSE on failure - * @deprecated This will be deprecated soon - * @codeCoverageIgnore - */ - public static function calculateMd5(EntityBodyInterface $body, $rawOutput = false, $base64Encode = false) - { - Version::warn(__CLASS__ . ' is deprecated. Use getContentMd5()'); - return $body->getContentMd5($rawOutput, $base64Encode); - } - - public function setStreamFilterContentEncoding($streamFilterContentEncoding) - { - $this->contentEncoding = $streamFilterContentEncoding; - - return $this; - } - - public function getContentEncoding() - { - return strtr($this->contentEncoding, array( - 'zlib.deflate' => 'gzip', - 'bzip2.compress' => 'compress' - )) ?: false; - } - - protected function handleCompression($filter, $offsetStart = 0) - { - // @codeCoverageIgnoreStart - if (!$this->isReadable() || ($this->isConsumed() && !$this->isSeekable())) { - return false; - } - // @codeCoverageIgnoreEnd - - $handle = fopen('php://temp', 'r+'); - $filter = @stream_filter_append($handle, $filter, STREAM_FILTER_WRITE); - if (!$filter) { - return false; - } - - // Seek to the offset start if possible - $this->seek($offsetStart); - while ($data = fread($this->stream, 8096)) { - fwrite($handle, $data); - } - - fclose($this->stream); - $this->stream = $handle; - stream_filter_remove($filter); - $stat = fstat($this->stream); - $this->size = $stat['size']; - $this->rebuildCache(); - $this->seek(0); - - // Remove any existing rewind function as the underlying stream has been replaced - $this->rewindFunction = null; - - return true; - } -} diff --git a/core/vendor/guzzle/http/Guzzle/Http/EntityBodyInterface.php b/core/vendor/guzzle/http/Guzzle/Http/EntityBodyInterface.php deleted file mode 100644 index e640f578501..00000000000 --- a/core/vendor/guzzle/http/Guzzle/Http/EntityBodyInterface.php +++ /dev/null @@ -1,73 +0,0 @@ -isClientError()) { - $label = 'Client error response'; - $class = __NAMESPACE__ . '\\ClientErrorResponseException'; - } elseif ($response->isServerError()) { - $label = 'Server error response'; - $class = __NAMESPACE__ . '\\ServerErrorResponseException'; - } else { - $label = 'Unsuccessful response'; - $class = __CLASS__; - $e = new self(); - } - - $message = $label . PHP_EOL . implode(PHP_EOL, array( - '[status code] ' . $response->getStatusCode(), - '[reason phrase] ' . $response->getReasonPhrase(), - '[url] ' . $request->getUrl(), - )); - - $e = new $class($message); - $e->setResponse($response); - $e->setRequest($request); - - return $e; - } - - /** - * Set the response that caused the exception - * - * @param Response $response Response to set - */ - public function setResponse(Response $response) - { - $this->response = $response; - } - - /** - * Get the response that caused the exception - * - * @return Response - */ - public function getResponse() - { - return $this->response; - } -} diff --git a/core/vendor/guzzle/http/Guzzle/Http/Exception/ClientErrorResponseException.php b/core/vendor/guzzle/http/Guzzle/Http/Exception/ClientErrorResponseException.php deleted file mode 100644 index 04d7ddc05ef..00000000000 --- a/core/vendor/guzzle/http/Guzzle/Http/Exception/ClientErrorResponseException.php +++ /dev/null @@ -1,8 +0,0 @@ -curlError = $error; - $this->curlErrorNo = $number; - - return $this; - } - - /** - * Set the associated curl handle - * - * @param CurlHandle $handle Curl handle - * - * @return self - */ - public function setCurlHandle(CurlHandle $handle) - { - $this->handle = $handle; - - return $this; - } - - /** - * Get the associated cURL handle - * - * @return CurlHandle|null - */ - public function getCurlHandle() - { - return $this->handle; - } - - /** - * Get the associated cURL error message - * - * @return string|null - */ - public function getError() - { - return $this->curlError; - } - - /** - * Get the associated cURL error number - * - * @return int|null - */ - public function getErrorNo() - { - return $this->curlErrorNo; - } - - /** - * Returns curl information about the transfer - * - * @return array - */ - public function getCurlInfo() - { - return $this->curlInfo; - } - - /** - * Set curl transfer information - * - * @param array $info Array of curl transfer information - * - * @return self - * @link http://php.net/manual/en/function.curl-getinfo.php - */ - public function setCurlInfo(array $info) - { - $this->curlInfo = $info; - - return $this; - } -} diff --git a/core/vendor/guzzle/http/Guzzle/Http/Exception/HttpException.php b/core/vendor/guzzle/http/Guzzle/Http/Exception/HttpException.php deleted file mode 100644 index ee87295d36e..00000000000 --- a/core/vendor/guzzle/http/Guzzle/Http/Exception/HttpException.php +++ /dev/null @@ -1,10 +0,0 @@ -successfulRequests, $this->failedRequests); - } - - /** - * Add to the array of successful requests - * - * @param RequestInterface $request Successful request - * - * @return self - */ - public function addSuccessfulRequest(RequestInterface $request) - { - $this->successfulRequests[] = $request; - - return $this; - } - - /** - * Add to the array of failed requests - * - * @param RequestInterface $request Failed request - * - * @return self - */ - public function addFailedRequest(RequestInterface $request) - { - $this->failedRequests[] = $request; - - return $this; - } - - /** - * Set all of the successful requests - * - * @param array Array of requests - * - * @return self - */ - public function setSuccessfulRequests(array $requests) - { - $this->successfulRequests = $requests; - - return $this; - } - - /** - * Set all of the failed requests - * - * @param array Array of requests - * - * @return self - */ - public function setFailedRequests(array $requests) - { - $this->failedRequests = $requests; - - return $this; - } - - /** - * Get an array of successful requests sent in the multi transfer - * - * @return array - */ - public function getSuccessfulRequests() - { - return $this->successfulRequests; - } - - /** - * Get an array of failed requests sent in the multi transfer - * - * @return array - */ - public function getFailedRequests() - { - return $this->failedRequests; - } - - /** - * Check if the exception object contains a request - * - * @param RequestInterface $request Request to check - * - * @return bool - */ - public function containsRequest(RequestInterface $request) - { - return in_array($request, $this->failedRequests, true) || in_array($request, $this->successfulRequests, true); - } -} diff --git a/core/vendor/guzzle/http/Guzzle/Http/Exception/RequestException.php b/core/vendor/guzzle/http/Guzzle/Http/Exception/RequestException.php deleted file mode 100644 index 274df2cb167..00000000000 --- a/core/vendor/guzzle/http/Guzzle/Http/Exception/RequestException.php +++ /dev/null @@ -1,39 +0,0 @@ -request = $request; - - return $this; - } - - /** - * Get the request that caused the exception - * - * @return RequestInterface - */ - public function getRequest() - { - return $this->request; - } -} diff --git a/core/vendor/guzzle/http/Guzzle/Http/Exception/ServerErrorResponseException.php b/core/vendor/guzzle/http/Guzzle/Http/Exception/ServerErrorResponseException.php deleted file mode 100644 index f0f7cfe4810..00000000000 --- a/core/vendor/guzzle/http/Guzzle/Http/Exception/ServerErrorResponseException.php +++ /dev/null @@ -1,8 +0,0 @@ -eventDispatcher = $eventDispatcher; - - return $this; - } - - public function getEventDispatcher() - { - if (!$this->eventDispatcher) { - $this->eventDispatcher = new EventDispatcher(); - } - - return $this->eventDispatcher; - } - - public function dispatch($eventName, array $context = array()) - { - $this->getEventDispatcher()->dispatch($eventName, new Event($context)); - } - - /** - * {@inheritdoc} - * @codeCoverageIgnore - */ - public function addSubscriber(EventSubscriberInterface $subscriber) - { - $this->getEventDispatcher()->addSubscriber($subscriber); - - return $this; - } - - public function read($length) - { - $event = array( - 'body' => $this, - 'length' => $length, - 'read' => $this->body->read($length) - ); - $this->dispatch('body.read', $event); - - return $event['read']; - } - - public function write($string) - { - $event = array( - 'body' => $this, - 'write' => $string, - 'result' => $this->body->write($string) - ); - $this->dispatch('body.write', $event); - - return $event['result']; - } -} diff --git a/core/vendor/guzzle/http/Guzzle/Http/Message/AbstractMessage.php b/core/vendor/guzzle/http/Guzzle/Http/Message/AbstractMessage.php deleted file mode 100644 index 0d066ffceb0..00000000000 --- a/core/vendor/guzzle/http/Guzzle/Http/Message/AbstractMessage.php +++ /dev/null @@ -1,220 +0,0 @@ -params = new Collection(); - $this->headerFactory = new HeaderFactory(); - $this->headers = new HeaderCollection(); - } - - /** - * Set the header factory to use to create headers - * - * @param HeaderFactoryInterface $factory - * - * @return self - */ - public function setHeaderFactory(HeaderFactoryInterface $factory) - { - $this->headerFactory = $factory; - - return $this; - } - - public function getParams() - { - return $this->params; - } - - public function addHeader($header, $value) - { - if (isset($this->headers[$header])) { - $this->headers[$header]->add($value); - } elseif ($value instanceof HeaderInterface) { - $this->headers[$header] = $value; - } else { - $this->headers[$header] = $this->headerFactory->createHeader($header, $value); - } - - return $this; - } - - public function addHeaders(array $headers) - { - foreach ($headers as $key => $value) { - $this->addHeader($key, $value); - } - - return $this; - } - - public function getHeader($header) - { - return $this->headers[$header]; - } - - public function getHeaders() - { - return $this->headers; - } - - public function getHeaderLines() - { - $headers = array(); - foreach ($this->headers as $value) { - $headers[] = $value->getName() . ': ' . $value; - } - - return $headers; - } - - public function setHeader($header, $value) - { - unset($this->headers[$header]); - $this->addHeader($header, $value); - - return $this; - } - - public function setHeaders(array $headers) - { - $this->headers->clear(); - foreach ($headers as $key => $value) { - $this->addHeader($key, $value); - } - - return $this; - } - - public function hasHeader($header) - { - return isset($this->headers[$header]); - } - - public function removeHeader($header) - { - unset($this->headers[$header]); - - return $this; - } - - /** - * @deprecated Use $message->getHeader()->parseParams() - * @codeCoverageIgnore - */ - public function getTokenizedHeader($header, $token = ';') - { - Version::warn(__METHOD__ . ' is deprecated. Use $message->getHeader()->parseParams()'); - if ($this->hasHeader($header)) { - $data = new Collection(); - foreach ($this->getHeader($header)->parseParams() as $values) { - foreach ($values as $key => $value) { - if ($value === '') { - $data->set($data->count(), $key); - } else { - $data->add($key, $value); - } - } - } - return $data; - } - } - - /** - * @deprecated - * @codeCoverageIgnore - */ - public function setTokenizedHeader($header, $data, $token = ';') - { - Version::warn(__METHOD__ . ' is deprecated.'); - return $this; - } - - /** - * @deprecated - * @codeCoverageIgnore - */ - public function getCacheControlDirective($directive) - { - Version::warn(__METHOD__ . ' is deprecated. Use $message->getHeader(\'Cache-Control\')->getDirective()'); - if (!($header = $this->getHeader('Cache-Control'))) { - return null; - } - - return $header->getDirective($directive); - } - - /** - * @deprecated - * @codeCoverageIgnore - */ - public function hasCacheControlDirective($directive) - { - Version::warn(__METHOD__ . ' is deprecated. Use $message->getHeader(\'Cache-Control\')->hasDirective()'); - if ($header = $this->getHeader('Cache-Control')) { - return $header->hasDirective($directive); - } else { - return false; - } - } - - /** - * @deprecated - * @codeCoverageIgnore - */ - public function addCacheControlDirective($directive, $value = true) - { - Version::warn(__METHOD__ . ' is deprecated. Use $message->getHeader(\'Cache-Control\')->addDirective()'); - if (!($header = $this->getHeader('Cache-Control'))) { - $this->addHeader('Cache-Control', ''); - $header = $this->getHeader('Cache-Control'); - } - - $header->addDirective($directive, $value); - - return $this; - } - - /** - * @deprecated - * @codeCoverageIgnore - */ - public function removeCacheControlDirective($directive) - { - Version::warn(__METHOD__ . ' is deprecated. Use $message->getHeader(\'Cache-Control\')->removeDirective()'); - if ($header = $this->getHeader('Cache-Control')) { - $header->removeDirective($directive); - } - - return $this; - } -} diff --git a/core/vendor/guzzle/http/Guzzle/Http/Message/EntityEnclosingRequest.php b/core/vendor/guzzle/http/Guzzle/Http/Message/EntityEnclosingRequest.php deleted file mode 100644 index d9c83d815be..00000000000 --- a/core/vendor/guzzle/http/Guzzle/Http/Message/EntityEnclosingRequest.php +++ /dev/null @@ -1,248 +0,0 @@ -postFields = new QueryString(); - parent::__construct($method, $url, $headers); - } - - /** - * @return string - */ - public function __toString() - { - // Only attempt to include the POST data if it's only fields - if (count($this->postFields) && empty($this->postFiles)) { - return parent::__toString() . (string) $this->postFields; - } - - return parent::__toString() . $this->body; - } - - public function setState($state, array $context = array()) - { - parent::setState($state, $context); - if ($state == self::STATE_TRANSFER && !$this->body && !count($this->postFields) && !count($this->postFiles)) { - $this->setHeader('Content-Length', 0)->removeHeader('Transfer-Encoding'); - } - - return $this->state; - } - - public function setBody($body, $contentType = null) - { - $this->body = EntityBody::factory($body); - - // Auto detect the Content-Type from the path of the request if possible - if ($contentType === null && !$this->hasHeader('Content-Type')) { - $contentType = $this->body->getContentType() ?: Mimetypes::getInstance()->fromFilename($this->getPath()); - } - - if ($contentType) { - $this->setHeader('Content-Type', $contentType); - } - - // Always add the Expect 100-Continue header if the body cannot be rewound. This helps with redirects. - if (!$this->body->isSeekable() && $this->expectCutoff !== false) { - $this->setHeader('Expect', '100-Continue'); - } - - // Set the Content-Length header if it can be determined - $size = $this->body->getContentLength(); - if ($size !== null && $size !== false) { - $this->setHeader('Content-Length', $size); - if ($size > $this->expectCutoff) { - $this->setHeader('Expect', '100-Continue'); - } - } elseif (!$this->hasHeader('Content-Length')) { - if ('1.1' == $this->protocolVersion) { - $this->setHeader('Transfer-Encoding', 'chunked'); - } else { - throw new RequestException( - 'Cannot determine Content-Length and cannot use chunked Transfer-Encoding when using HTTP/1.0' - ); - } - } - - return $this; - } - - public function getBody() - { - return $this->body; - } - - /** - * Set the size that the entity body of the request must exceed before adding the Expect: 100-Continue header. - * - * @param int|bool $size Cutoff in bytes. Set to false to never send the expect header (even with non-seekable data) - * - * @return self - */ - public function setExpectHeaderCutoff($size) - { - $this->expectCutoff = $size; - if ($size === false || !$this->body) { - $this->removeHeader('Expect'); - } elseif ($this->body && $this->body->getSize() && $this->body->getSize() > $size) { - $this->setHeader('Expect', '100-Continue'); - } - - return $this; - } - - public function configureRedirects($strict = false, $maxRedirects = 5) - { - $this->getParams()->set(RedirectPlugin::STRICT_REDIRECTS, $strict); - if ($maxRedirects == 0) { - $this->getParams()->set(RedirectPlugin::DISABLE, true); - } else { - $this->getParams()->set(RedirectPlugin::MAX_REDIRECTS, $maxRedirects); - } - - return $this; - } - - public function getPostField($field) - { - return $this->postFields->get($field); - } - - public function getPostFields() - { - return $this->postFields; - } - - public function setPostField($key, $value) - { - $this->postFields->set($key, $value); - $this->processPostFields(); - - return $this; - } - - public function addPostFields($fields) - { - $this->postFields->merge($fields); - $this->processPostFields(); - - return $this; - } - - public function removePostField($field) - { - $this->postFields->remove($field); - $this->processPostFields(); - - return $this; - } - - public function getPostFiles() - { - return $this->postFiles; - } - - public function getPostFile($fieldName) - { - return isset($this->postFiles[$fieldName]) ? $this->postFiles[$fieldName] : null; - } - - public function removePostFile($fieldName) - { - unset($this->postFiles[$fieldName]); - $this->processPostFields(); - - return $this; - } - - public function addPostFile($field, $filename = null, $contentType = null) - { - $data = null; - - if ($field instanceof PostFileInterface) { - $data = $field; - } elseif (is_array($filename)) { - // Allow multiple values to be set in a single key - foreach ($filename as $file) { - $this->addPostFile($field, $file, $contentType); - } - return $this; - } elseif (!is_string($filename)) { - throw new RequestException('The path to a file must be a string'); - } elseif (!empty($filename)) { - // Adding an empty file will cause cURL to error out - $data = new PostFile($field, $filename, $contentType); - } - - if ($data) { - if (!isset($this->postFiles[$data->getFieldName()])) { - $this->postFiles[$data->getFieldName()] = array($data); - } else { - $this->postFiles[$data->getFieldName()][] = $data; - } - $this->processPostFields(); - } - - return $this; - } - - public function addPostFiles(array $files) - { - foreach ($files as $key => $file) { - if ($file instanceof PostFileInterface) { - $this->addPostFile($file, null, null, false); - } elseif (is_string($file)) { - // Convert non-associative array keys into 'file' - if (is_numeric($key)) { - $key = 'file'; - } - $this->addPostFile($key, $file, null, false); - } else { - throw new RequestException('File must be a string or instance of PostFileInterface'); - } - } - - return $this; - } - - /** - * Determine what type of request should be sent based on post fields - */ - protected function processPostFields() - { - if (!$this->postFiles) { - $this->removeHeader('Expect')->setHeader('Content-Type', self::URL_ENCODED); - } else { - $this->setHeader('Content-Type', self::MULTIPART); - if ($this->expectCutoff !== false) { - $this->setHeader('Expect', '100-Continue'); - } - } - } -} diff --git a/core/vendor/guzzle/http/Guzzle/Http/Message/EntityEnclosingRequestInterface.php b/core/vendor/guzzle/http/Guzzle/Http/Message/EntityEnclosingRequestInterface.php deleted file mode 100644 index d9c037de683..00000000000 --- a/core/vendor/guzzle/http/Guzzle/Http/Message/EntityEnclosingRequestInterface.php +++ /dev/null @@ -1,136 +0,0 @@ - filenames where filename can be a string or PostFileInterface - * - * @return self - */ - public function addPostFiles(array $files); - - /** - * Configure how redirects are handled for the request - * - * @param bool $strict Set to true to follow strict RFC compliance when redirecting POST requests. Most - * browsers with follow a 301-302 redirect for a POST request with a GET request. This is - * the default behavior of Guzzle. Enable strict redirects to redirect these responses - * with a POST rather than a GET request. - * @param int $maxRedirects Specify the maximum number of allowed redirects. Set to 0 to disable redirects. - * - * @return self - */ - public function configureRedirects($strict = false, $maxRedirects = 5); -} diff --git a/core/vendor/guzzle/http/Guzzle/Http/Message/Header.php b/core/vendor/guzzle/http/Guzzle/Http/Message/Header.php deleted file mode 100644 index b919166a71f..00000000000 --- a/core/vendor/guzzle/http/Guzzle/Http/Message/Header.php +++ /dev/null @@ -1,177 +0,0 @@ -header = trim($header); - $this->glue = $glue; - - foreach ((array) $values as $value) { - foreach ((array) $value as $v) { - $this->values[] = $v; - } - } - } - - public function __toString() - { - return implode($this->glue . ' ', $this->toArray()); - } - - public function add($value) - { - $this->values[] = $value; - - return $this; - } - - public function getName() - { - return $this->header; - } - - public function setName($name) - { - $this->header = $name; - - return $this; - } - - public function setGlue($glue) - { - $this->glue = $glue; - - return $this; - } - - public function getGlue() - { - return $this->glue; - } - - /** - * Normalize the header to be a single header with an array of values. - * - * If any values of the header contains the glue string value (e.g. ","), then the value will be exploded into - * multiple entries in the header. - * - * @return self - */ - public function normalize() - { - $values = $this->toArray(); - - for ($i = 0, $total = count($values); $i < $total; $i++) { - if (strpos($values[$i], $this->glue) !== false) { - foreach (explode($this->glue, $values[$i]) as $v) { - $values[] = trim($v); - } - unset($values[$i]); - } - } - - $this->values = array_values($values); - - return $this; - } - - public function hasValue($searchValue) - { - return in_array($searchValue, $this->toArray()); - } - - public function removeValue($searchValue) - { - $this->values = array_values(array_filter($this->values, function ($value) use ($searchValue) { - return $value != $searchValue; - })); - - return $this; - } - - public function toArray() - { - return $this->values; - } - - public function count() - { - return count($this->toArray()); - } - - public function getIterator() - { - return new \ArrayIterator($this->toArray()); - } - - public function parseParams() - { - $params = $matches = array(); - $callback = array($this, 'trimHeader'); - - // Normalize the header into a single array and iterate over all values - foreach ($this->normalize()->toArray() as $val) { - $part = array(); - foreach (preg_split('/;(?=([^"]*"[^"]*")*[^"]*$)/', $val) as $kvp) { - preg_match_all('/<[^>]+>|[^=]+/', $kvp, $matches); - $pieces = array_map($callback, $matches[0]); - $part[$pieces[0]] = isset($pieces[1]) ? $pieces[1] : ''; - } - $params[] = $part; - } - - return $params; - } - - /** - * @deprecated - * @codeCoverageIgnore - */ - public function hasExactHeader($header) - { - Version::warn(__METHOD__ . ' is deprecated'); - return $this->header == $header; - } - - /** - * @deprecated - * @codeCoverageIgnore - */ - public function raw() - { - Version::warn(__METHOD__ . ' is deprecated. Use toArray()'); - return $this->toArray(); - } - - /** - * Trim a header by removing excess spaces and wrapping quotes - * - * @param $str - * - * @return string - */ - protected function trimHeader($str) - { - static $trimmed = "\"' \n\t"; - - return trim($str, $trimmed); - } -} diff --git a/core/vendor/guzzle/http/Guzzle/Http/Message/Header/CacheControl.php b/core/vendor/guzzle/http/Guzzle/Http/Message/Header/CacheControl.php deleted file mode 100644 index 77789e51fd4..00000000000 --- a/core/vendor/guzzle/http/Guzzle/Http/Message/Header/CacheControl.php +++ /dev/null @@ -1,121 +0,0 @@ -directives = null; - } - - public function removeValue($searchValue) - { - parent::removeValue($searchValue); - $this->directives = null; - } - - /** - * Check if a specific cache control directive exists - * - * @param string $param Directive to retrieve - * - * @return bool - */ - public function hasDirective($param) - { - $directives = $this->getDirectives(); - - return isset($directives[$param]); - } - - /** - * Get a specific cache control directive - * - * @param string $param Directive to retrieve - * - * @return string|bool|null - */ - public function getDirective($param) - { - $directives = $this->getDirectives(); - - return isset($directives[$param]) ? $directives[$param] : null; - } - - /** - * Add a cache control directive - * - * @param string $param Directive to add - * @param string $value Value to set - * - * @return self - */ - public function addDirective($param, $value) - { - $directives = $this->getDirectives(); - $directives[$param] = $value; - $this->updateFromDirectives($directives); - - return $this; - } - - /** - * Remove a cache control directive by name - * - * @param string $param Directive to remove - * - * @return self - */ - public function removeDirective($param) - { - $directives = $this->getDirectives(); - unset($directives[$param]); - $this->updateFromDirectives($directives); - - return $this; - } - - /** - * Get an associative array of cache control directives - * - * @return array - */ - public function getDirectives() - { - if ($this->directives === null) { - $this->directives = array(); - foreach ($this->parseParams() as $collection) { - foreach ($collection as $key => $value) { - $this->directives[$key] = $value === '' ? true : $value; - } - } - } - - return $this->directives; - } - - /** - * Updates the header value based on the parsed directives - * - * @param array $directives Array of cache control directives - */ - protected function updateFromDirectives(array $directives) - { - $this->directives = $directives; - $this->values = array(); - - foreach ($directives as $key => $value) { - $this->values[] = $value === true ? $key : "{$key}={$value}"; - } - } -} diff --git a/core/vendor/guzzle/http/Guzzle/Http/Message/Header/HeaderCollection.php b/core/vendor/guzzle/http/Guzzle/Http/Message/Header/HeaderCollection.php deleted file mode 100644 index ec282d9a911..00000000000 --- a/core/vendor/guzzle/http/Guzzle/Http/Message/Header/HeaderCollection.php +++ /dev/null @@ -1,109 +0,0 @@ -headers = $headers; - } - - public function __clone() - { - foreach ($this->headers as &$header) { - $header = clone $header; - } - } - - /** - * Clears the header collection - */ - public function clear() - { - $this->headers = array(); - } - - /** - * Set a header on the collection - * - * @param HeaderInterface $header Header to add - * - * @return self - */ - public function add(HeaderInterface $header) - { - $this->headers[strtolower($header->getName())] = $header; - - return $this; - } - - /** - * Get an array of header objects - * - * @return array - */ - public function getAll() - { - return $this->headers; - } - - /** - * Alias of offsetGet - */ - public function get($key) - { - return $this->offsetGet($key); - } - - public function count() - { - return count($this->headers); - } - - public function offsetExists($offset) - { - return isset($this->headers[strtolower($offset)]); - } - - public function offsetGet($offset) - { - $l = strtolower($offset); - - return isset($this->headers[$l]) ? $this->headers[$l] : null; - } - - public function offsetSet($offset, $value) - { - $this->add($value); - } - - public function offsetUnset($offset) - { - unset($this->headers[strtolower($offset)]); - } - - public function getIterator() - { - return new \ArrayIterator($this->headers); - } - - public function toArray() - { - $result = array(); - foreach ($this->headers as $header) { - $result[$header->getName()] = $header->toArray(); - } - - return $result; - } -} diff --git a/core/vendor/guzzle/http/Guzzle/Http/Message/Header/HeaderFactory.php b/core/vendor/guzzle/http/Guzzle/Http/Message/Header/HeaderFactory.php deleted file mode 100644 index 0273be52f81..00000000000 --- a/core/vendor/guzzle/http/Guzzle/Http/Message/Header/HeaderFactory.php +++ /dev/null @@ -1,26 +0,0 @@ - 'Guzzle\Http\Message\Header\CacheControl', - 'link' => 'Guzzle\Http\Message\Header\Link', - ); - - public function createHeader($header, $value = null) - { - $lowercase = strtolower($header); - - return isset($this->mapping[$lowercase]) - ? new $this->mapping[$lowercase]($header, $value) - : new Header($header, $value); - } -} diff --git a/core/vendor/guzzle/http/Guzzle/Http/Message/Header/HeaderFactoryInterface.php b/core/vendor/guzzle/http/Guzzle/Http/Message/Header/HeaderFactoryInterface.php deleted file mode 100644 index 9457cf64a1c..00000000000 --- a/core/vendor/guzzle/http/Guzzle/Http/Message/Header/HeaderFactoryInterface.php +++ /dev/null @@ -1,19 +0,0 @@ -", "rel=\"{$rel}\""); - - foreach ($params as $k => $v) { - $values[] = "{$k}=\"{$v}\""; - } - - return $this->add(implode('; ', $values)); - } - - /** - * Check if a specific link exists for a given rel attribute - * - * @param string $rel rel value - * - * @return bool - */ - public function hasLink($rel) - { - return $this->getLink($rel) !== null; - } - - /** - * Get a specific link for a given rel attribute - * - * @param string $rel Rel value - * - * @return array|null - */ - public function getLink($rel) - { - foreach ($this->getLinks() as $link) { - if (isset($link['rel']) && $link['rel'] == $rel) { - return $link; - } - } - - return null; - } - - /** - * Get an associative array of links - * - * For example: - * Link: ; rel=front; type="image/jpeg", ; rel=back; type="image/jpeg" - * - * - * var_export($response->getLinks()); - * array( - * array( - * 'url' => 'http:/.../front.jpeg', - * 'rel' => 'back', - * 'type' => 'image/jpeg', - * ) - * ) - * - * - * @return array - */ - public function getLinks() - { - $links = $this->parseParams(); - - foreach ($links as &$link) { - $key = key($link); - unset($link[$key]); - $link['url'] = trim($key, '<> '); - } - - return $links; - } -} diff --git a/core/vendor/guzzle/http/Guzzle/Http/Message/MessageInterface.php b/core/vendor/guzzle/http/Guzzle/Http/Message/MessageInterface.php deleted file mode 100644 index 62bcd439133..00000000000 --- a/core/vendor/guzzle/http/Guzzle/Http/Message/MessageInterface.php +++ /dev/null @@ -1,102 +0,0 @@ -fieldName = $fieldName; - $this->setFilename($filename); - $this->contentType = $contentType ?: $this->guessContentType(); - } - - public function setFieldName($name) - { - $this->fieldName = $name; - - return $this; - } - - public function getFieldName() - { - return $this->fieldName; - } - - public function setFilename($filename) - { - // Remove leading @ symbol - if (strpos($filename, '@') === 0) { - $filename = substr($filename, 1); - } - - if (!is_readable($filename)) { - throw new InvalidArgumentException("Unable to open {$filename} for reading"); - } - - $this->filename = $filename; - - return $this; - } - - public function getFilename() - { - return $this->filename; - } - - public function setContentType($type) - { - $this->contentType = $type; - - return $this; - } - - public function getContentType() - { - return $this->contentType; - } - - public function getCurlValue() - { - // PHP 5.5 introduced a CurlFile object that deprecates the old @filename syntax - // See: https://wiki.php.net/rfc/curl-file-upload - if (function_exists('curl_file_create')) { - return curl_file_create($this->filename, $this->contentType, basename($this->filename)); - } - - // Use the old style if using an older version of PHP - $value = "@{$this->filename};filename=" . basename($this->filename); - if ($this->contentType) { - $value .= ';type=' . $this->contentType; - } - - return $value; - } - - /** - * @deprecated - * @codeCoverageIgnore - */ - public function getCurlString() - { - Version::warn(__METHOD__ . ' is deprecated. Use getCurlValue()'); - return $this->getCurlValue(); - } - - /** - * Determine the Content-Type of the file - */ - protected function guessContentType() - { - return Mimetypes::getInstance()->fromFilename($this->filename) ?: 'application/octet-stream'; - } -} diff --git a/core/vendor/guzzle/http/Guzzle/Http/Message/PostFileInterface.php b/core/vendor/guzzle/http/Guzzle/Http/Message/PostFileInterface.php deleted file mode 100644 index 99dc706946f..00000000000 --- a/core/vendor/guzzle/http/Guzzle/Http/Message/PostFileInterface.php +++ /dev/null @@ -1,67 +0,0 @@ -method = strtoupper($method); - $this->curlOptions = new Collection(); - $this->setUrl($url); - - if ($headers) { - // Special handling for multi-value headers - foreach ($headers as $key => $value) { - // Deal with collisions with Host and Authorization - if ($key == 'host' || $key == 'Host') { - $this->setHeader($key, $value); - } elseif ($value instanceof HeaderInterface) { - $this->addHeader($key, $value); - } else { - foreach ((array) $value as $v) { - $this->addHeader($key, $v); - } - } - } - } - - $this->setState(self::STATE_NEW); - } - - public function __clone() - { - if ($this->eventDispatcher) { - $this->eventDispatcher = clone $this->eventDispatcher; - } - $this->curlOptions = clone $this->curlOptions; - $this->params = clone $this->params; - $this->url = clone $this->url; - $this->response = $this->responseBody = null; - $this->headers = clone $this->headers; - - $this->setState(RequestInterface::STATE_NEW); - $this->dispatch('request.clone', array('request' => $this)); - } - - /** - * Get the HTTP request as a string - * - * @return string - */ - public function __toString() - { - return $this->getRawHeaders() . "\r\n\r\n"; - } - - /** - * Default method that will throw exceptions if an unsuccessful response is received. - * - * @param Event $event Received - * @throws BadResponseException if the response is not successful - */ - public static function onRequestError(Event $event) - { - $e = BadResponseException::factory($event['request'], $event['response']); - $event['request']->setState(self::STATE_ERROR, array('exception' => $e) + $event->toArray()); - throw $e; - } - - public function setClient(ClientInterface $client) - { - $this->client = $client; - - return $this; - } - - public function getClient() - { - return $this->client; - } - - public function getRawHeaders() - { - $protocolVersion = $this->protocolVersion ?: '1.1'; - - return trim($this->method . ' ' . $this->getResource()) . ' ' - . strtoupper(str_replace('https', 'http', $this->url->getScheme())) - . '/' . $protocolVersion . "\r\n" . implode("\r\n", $this->getHeaderLines()); - } - - public function setUrl($url) - { - if ($url instanceof Url) { - $this->url = $url; - } else { - $this->url = Url::factory($url); - } - - // Update the port and host header - $this->setPort($this->url->getPort()); - - if ($this->url->getUsername() || $this->url->getPassword()) { - $this->setAuth($this->url->getUsername(), $this->url->getPassword()); - // Remove the auth info from the URL - $this->url->setUsername(null); - $this->url->setPassword(null); - } - - return $this; - } - - public function send() - { - if (!$this->client) { - throw new RuntimeException('A client must be set on the request'); - } - - return $this->client->send($this); - } - - public function getResponse() - { - return $this->response; - } - - public function getQuery($asString = false) - { - return $asString - ? (string) $this->url->getQuery() - : $this->url->getQuery(); - } - - public function getMethod() - { - return $this->method; - } - - public function getScheme() - { - return $this->url->getScheme(); - } - - public function setScheme($scheme) - { - $this->url->setScheme($scheme); - - return $this; - } - - public function getHost() - { - return $this->url->getHost(); - } - - public function setHost($host) - { - $this->url->setHost($host); - $this->setPort($this->url->getPort()); - - return $this; - } - - public function getProtocolVersion() - { - return $this->protocolVersion; - } - - public function setProtocolVersion($protocol) - { - $this->protocolVersion = $protocol; - - return $this; - } - - public function getPath() - { - return '/' . ltrim($this->url->getPath(), '/'); - } - - public function setPath($path) - { - $this->url->setPath($path); - - return $this; - } - - public function getPort() - { - return $this->url->getPort(); - } - - public function setPort($port) - { - $this->url->setPort($port); - - // Include the port in the Host header if it is not the default port for the scheme of the URL - $scheme = $this->url->getScheme(); - if (($scheme == 'http' && $port != 80) || ($scheme == 'https' && $port != 443)) { - $this->headers['host'] = $this->headerFactory->createHeader('Host', $this->url->getHost() . ':' . $port); - } else { - $this->headers['host'] = $this->headerFactory->createHeader('Host', $this->url->getHost()); - } - - return $this; - } - - public function getUsername() - { - return $this->username; - } - - public function getPassword() - { - return $this->password; - } - - public function setAuth($user, $password = '', $scheme = CURLAUTH_BASIC) - { - static $authMap = array( - 'basic' => CURLAUTH_BASIC, - 'digest' => CURLAUTH_DIGEST, - 'ntlm' => CURLAUTH_NTLM, - 'any' => CURLAUTH_ANY - ); - - // If we got false or null, disable authentication - if (!$user) { - $this->password = $this->username = null; - $this->removeHeader('Authorization'); - $this->getCurlOptions()->remove(CURLOPT_HTTPAUTH); - return $this; - } - - if (!is_numeric($scheme)) { - $scheme = strtolower($scheme); - if (!isset($authMap[$scheme])) { - throw new InvalidArgumentException($scheme . ' is not a valid authentication type'); - } - $scheme = $authMap[$scheme]; - } - - $this->username = $user; - $this->password = $password; - - // Bypass CURL when using basic auth to promote connection reuse - if ($scheme == CURLAUTH_BASIC) { - $this->getCurlOptions()->remove(CURLOPT_HTTPAUTH); - $this->setHeader('Authorization', 'Basic ' . base64_encode($this->username . ':' . $this->password)); - } else { - $this->getCurlOptions() - ->set(CURLOPT_HTTPAUTH, $scheme) - ->set(CURLOPT_USERPWD, $this->username . ':' . $this->password); - } - - return $this; - } - - public function getResource() - { - $resource = $this->getPath(); - if ($query = (string) $this->url->getQuery()) { - $resource .= '?' . $query; - } - - return $resource; - } - - public function getUrl($asObject = false) - { - return $asObject ? clone $this->url : (string) $this->url; - } - - public function getState() - { - return $this->state; - } - - public function setState($state, array $context = array()) - { - $oldState = $this->state; - $this->state = $state; - - switch ($state) { - case self::STATE_NEW: - $this->response = null; - break; - case self::STATE_TRANSFER: - if ($oldState !== $state) { - // Fix Content-Length and Transfer-Encoding collisions - if ($this->hasHeader('Transfer-Encoding') && $this->hasHeader('Content-Length')) { - $this->removeHeader('Transfer-Encoding'); - } - $this->dispatch('request.before_send', array('request' => $this)); - } - break; - case self::STATE_COMPLETE: - if ($oldState !== $state) { - $this->processResponse($context); - $this->responseBody = null; - } - break; - case self::STATE_ERROR: - if (isset($context['exception'])) { - $this->dispatch('request.exception', array( - 'request' => $this, - 'response' => isset($context['response']) ? $context['response'] : $this->response, - 'exception' => isset($context['exception']) ? $context['exception'] : null - )); - } - } - - return $this->state; - } - - public function getCurlOptions() - { - return $this->curlOptions; - } - - public function startResponse(Response $response) - { - $this->state = self::STATE_TRANSFER; - $response->setEffectiveUrl((string) $this->getUrl()); - $this->response = $response; - - return $this; - } - - public function setResponse(Response $response, $queued = false) - { - $response->setEffectiveUrl((string) $this->url); - - if ($queued) { - $ed = $this->getEventDispatcher(); - $ed->addListener('request.before_send', $f = function ($e) use ($response, &$f, $ed) { - $e['request']->setResponse($response); - $ed->removeListener('request.before_send', $f); - }, -9999); - } else { - $this->response = $response; - // If a specific response body is specified, then use it instead of the response's body - if ($this->responseBody && !$this->responseBody->getCustomData('default') && !$response->isRedirect()) { - $this->getResponseBody()->write((string) $this->response->getBody()); - } else { - $this->responseBody = $this->response->getBody(); - } - $this->setState(self::STATE_COMPLETE); - } - - return $this; - } - - public function setResponseBody($body) - { - // Attempt to open a file for writing if a string was passed - if (is_string($body)) { - // @codeCoverageIgnoreStart - if (!($body = fopen($body, 'w+'))) { - throw new InvalidArgumentException('Could not open ' . $body . ' for writing'); - } - // @codeCoverageIgnoreEnd - } - - $this->responseBody = EntityBody::factory($body); - - return $this; - } - - public function getResponseBody() - { - if ($this->responseBody === null) { - $this->responseBody = EntityBody::factory()->setCustomData('default', true); - } - - return $this->responseBody; - } - - /** - * Determine if the response body is repeatable (readable + seekable) - * - * @return bool - * @deprecated Use getResponseBody()->isSeekable() - * @codeCoverageIgnore - */ - public function isResponseBodyRepeatable() - { - Version::warn(__METHOD__ . ' is deprecated. Use $request->getResponseBody()->isRepeatable()'); - return !$this->responseBody ? true : $this->responseBody->isRepeatable(); - } - - public function getCookies() - { - if ($cookie = $this->getHeader('Cookie')) { - $data = ParserRegistry::getInstance()->getParser('cookie')->parseCookie($cookie); - return $data['cookies']; - } - - return array(); - } - - public function getCookie($name) - { - $cookies = $this->getCookies(); - - return isset($cookies[$name]) ? $cookies[$name] : null; - } - - public function addCookie($name, $value) - { - if (!$this->hasHeader('Cookie')) { - $this->setHeader('Cookie', "{$name}={$value}"); - } else { - $this->getHeader('Cookie')->add("{$name}={$value}"); - } - - // Always use semicolons to separate multiple cookie headers - $this->getHeader('Cookie')->setGlue(';'); - - return $this; - } - - public function removeCookie($name) - { - if ($cookie = $this->getHeader('Cookie')) { - foreach ($cookie as $cookieValue) { - if (strpos($cookieValue, $name . '=') === 0) { - $cookie->removeValue($cookieValue); - } - } - } - - return $this; - } - - public function setEventDispatcher(EventDispatcherInterface $eventDispatcher) - { - $this->eventDispatcher = $eventDispatcher; - $this->eventDispatcher->addListener('request.error', array(__CLASS__, 'onRequestError'), -255); - - return $this; - } - - public function getEventDispatcher() - { - if (!$this->eventDispatcher) { - $this->setEventDispatcher(new EventDispatcher()); - } - - return $this->eventDispatcher; - } - - public function dispatch($eventName, array $context = array()) - { - $context['request'] = $this; - $this->getEventDispatcher()->dispatch($eventName, new Event($context)); - } - - public function addSubscriber(EventSubscriberInterface $subscriber) - { - $this->getEventDispatcher()->addSubscriber($subscriber); - - return $this; - } - - /** - * Get an array containing the request and response for event notifications - * - * @return array - */ - protected function getEventArray() - { - return array( - 'request' => $this, - 'response' => $this->response - ); - } - - /** - * Process a received response - * - * @param array $context Contextual information - * @throws RequestException|BadResponseException on unsuccessful responses - */ - protected function processResponse(array $context = array()) - { - if (!$this->response) { - // If no response, then processResponse shouldn't have been called - $e = new RequestException('Error completing request'); - $e->setRequest($this); - throw $e; - } - - $this->state = self::STATE_COMPLETE; - - // A request was sent, but we don't know if we'll send more or if the final response will be successful - $this->dispatch('request.sent', $this->getEventArray() + $context); - - // Some response processors will remove the response or reset the state (example: ExponentialBackoffPlugin) - if ($this->state == RequestInterface::STATE_COMPLETE) { - - // The request completed, so the HTTP transaction is complete - $this->dispatch('request.complete', $this->getEventArray()); - - // If the response is bad, allow listeners to modify it or throw exceptions. You can change the response by - // modifying the Event object in your listeners or calling setResponse() on the request - if ($this->response->isError()) { - $event = new Event($this->getEventArray()); - $this->getEventDispatcher()->dispatch('request.error', $event); - // Allow events of request.error to quietly change the response - if ($event['response'] !== $this->response) { - $this->response = $event['response']; - } - } - - // If a successful response was received, dispatch an event - if ($this->response->isSuccessful()) { - $this->dispatch('request.success', $this->getEventArray()); - } - } - } - - /** - * @deprecated Use Guzzle\Plugin\Cache\DefaultCanCacheStrategy - * @codeCoverageIgnore - */ - public function canCache() - { - Version::warn(__METHOD__ . ' is deprecated. Use Guzzle\Plugin\Cache\DefaultCanCacheStrategy.'); - if (class_exists('Guzzle\Plugin\Cache\DefaultCanCacheStrategy')) { - $canCache = new \Guzzle\Plugin\Cache\DefaultCanCacheStrategy(); - return $canCache->canCacheRequest($this); - } else { - return false; - } - } - - /** - * @deprecated Use the history plugin (not emitting a warning as this is built-into the RedirectPlugin for now) - * @codeCoverageIgnore - */ - public function setIsRedirect($isRedirect) - { - $this->isRedirect = $isRedirect; - - return $this; - } - - /** - * @deprecated Use the history plugin - * @codeCoverageIgnore - */ - public function isRedirect() - { - Version::warn(__METHOD__ . ' is deprecated. Use the HistoryPlugin to track this.'); - return $this->isRedirect; - } -} diff --git a/core/vendor/guzzle/http/Guzzle/Http/Message/RequestFactory.php b/core/vendor/guzzle/http/Guzzle/Http/Message/RequestFactory.php deleted file mode 100644 index 5fae2d25873..00000000000 --- a/core/vendor/guzzle/http/Guzzle/Http/Message/RequestFactory.php +++ /dev/null @@ -1,356 +0,0 @@ -methods = array_flip(get_class_methods(__CLASS__)); - } - - public function fromMessage($message) - { - $parsed = ParserRegistry::getInstance()->getParser('message')->parseRequest($message); - - if (!$parsed) { - return false; - } - - $request = $this->fromParts($parsed['method'], $parsed['request_url'], - $parsed['headers'], $parsed['body'], $parsed['protocol'], - $parsed['version']); - - // EntityEnclosingRequest adds an "Expect: 100-Continue" header when using a raw request body for PUT or POST - // requests. This factory method should accurately reflect the message, so here we are removing the Expect - // header if one was not supplied in the message. - if (!isset($parsed['headers']['Expect']) && !isset($parsed['headers']['expect'])) { - $request->removeHeader('Expect'); - } - - return $request; - } - - public function fromParts( - $method, - array $urlParts, - $headers = null, - $body = null, - $protocol = 'HTTP', - $protocolVersion = '1.1' - ) { - return $this->create($method, Url::buildUrl($urlParts), $headers, $body) - ->setProtocolVersion($protocolVersion); - } - - public function create($method, $url, $headers = null, $body = null, array $options = array()) - { - $method = strtoupper($method); - - if ($method == 'GET' || $method == 'HEAD' || $method == 'TRACE' || $method == 'OPTIONS') { - // Handle non-entity-enclosing request methods - $request = new $this->requestClass($method, $url, $headers); - if ($body) { - // The body is where the response body will be stored - $type = gettype($body); - if ($type == 'string' || $type == 'resource' || $type == 'object') { - $request->setResponseBody($body); - } - } - } else { - // Create an entity enclosing request by default - $request = new $this->entityEnclosingRequestClass($method, $url, $headers); - if ($body) { - // Add POST fields and files to an entity enclosing request if an array is used - if (is_array($body) || $body instanceof Collection) { - // Normalize PHP style cURL uploads with a leading '@' symbol - foreach ($body as $key => $value) { - if (is_string($value) && substr($value, 0, 1) == '@') { - $request->addPostFile($key, $value); - unset($body[$key]); - } - } - // Add the fields if they are still present and not all files - $request->addPostFields($body); - } else { - // Add a raw entity body body to the request - $request->setBody($body, (string) $request->getHeader('Content-Type')); - if ((string) $request->getHeader('Transfer-Encoding') == 'chunked') { - $request->removeHeader('Content-Length'); - } - } - } - } - - if ($options) { - $this->applyOptions($request, $options); - } - - return $request; - } - - /** - * Clone a request while changing the method. Emulates the behavior of - * {@see Guzzle\Http\Message\Request::clone}, but can change the HTTP method. - * - * @param RequestInterface $request Request to clone - * @param string $method Method to set - * - * @return RequestInterface - */ - public function cloneRequestWithMethod(RequestInterface $request, $method) - { - // Create the request with the same client if possible - if ($client = $request->getClient()) { - $cloned = $request->getClient()->createRequest($method, $request->getUrl(), $request->getHeaders()); - } else { - $cloned = $this->create($method, $request->getUrl(), $request->getHeaders()); - } - - $cloned->getCurlOptions()->replace($request->getCurlOptions()->toArray()); - $cloned->setEventDispatcher(clone $request->getEventDispatcher()); - // Ensure that that the Content-Length header is not copied if changing to GET or HEAD - if (!($cloned instanceof EntityEnclosingRequestInterface)) { - $cloned->removeHeader('Content-Length'); - } elseif ($request instanceof EntityEnclosingRequestInterface) { - $cloned->setBody($request->getBody()); - } - $cloned->getParams()->replace($request->getParams()->toArray()); - $cloned->dispatch('request.clone', array('request' => $cloned)); - - return $cloned; - } - - public function applyOptions(RequestInterface $request, array $options = array(), $flags = self::OPTIONS_NONE) - { - // Iterate over each key value pair and attempt to apply a config using function visitors - foreach ($options as $key => $value) { - $method = "visit_{$key}"; - if (isset($this->methods[$method])) { - $this->{$method}($request, $value, $flags); - } - } - } - - protected function visit_headers(RequestInterface $request, $value, $flags) - { - if (!is_array($value)) { - throw new InvalidArgumentException('headers value must be an array'); - } - - if ($flags & self::OPTIONS_AS_DEFAULTS) { - // Merge headers in but do not overwrite existing values - foreach ($value as $key => $header) { - if (!$request->hasHeader($key)) { - $request->setHeader($key, $header); - } - } - } else { - $request->addHeaders($value); - } - } - - protected function visit_body(RequestInterface $request, $value, $flags) - { - if ($request instanceof EntityEnclosingRequestInterface) { - $request->setBody($value); - } else { - throw new InvalidArgumentException('Attempting to set a body on a non-entity-enclosing request'); - } - } - - protected function visit_allow_redirects(RequestInterface $request, $value, $flags) - { - if ($value === false) { - $request->getParams()->set(RedirectPlugin::DISABLE, true); - } - } - - protected function visit_auth(RequestInterface $request, $value, $flags) - { - if (!is_array($value)) { - throw new InvalidArgumentException('auth value must be an array'); - } - - $request->setAuth($value[0], isset($value[1]) ? $value[1] : null, isset($value[2]) ? $value[2] : 'basic'); - } - - protected function visit_query(RequestInterface $request, $value, $flags) - { - if (!is_array($value)) { - throw new InvalidArgumentException('query value must be an array'); - } - - if ($flags & self::OPTIONS_AS_DEFAULTS) { - // Merge query string values in but do not overwrite existing values - $query = $request->getQuery(); - $query->overwriteWith(array_diff_key($value, $query->toArray())); - } else { - $request->getQuery()->overwriteWith($value); - } - } - - protected function visit_cookies(RequestInterface $request, $value, $flags) - { - if (!is_array($value)) { - throw new InvalidArgumentException('cookies value must be an array'); - } - - foreach ($value as $name => $v) { - $request->addCookie($name, $v); - } - } - - protected function visit_events(RequestInterface $request, $value, $flags) - { - if (!is_array($value)) { - throw new InvalidArgumentException('events value must be an array'); - } - - foreach ($value as $name => $method) { - if (is_array($method)) { - $request->getEventDispatcher()->addListener($name, $method[0], $method[1]); - } else { - $request->getEventDispatcher()->addListener($name, $method); - } - } - } - - protected function visit_plugins(RequestInterface $request, $value, $flags) - { - if (!is_array($value)) { - throw new InvalidArgumentException('plugins value must be an array'); - } - - foreach ($value as $plugin) { - $request->addSubscriber($plugin); - } - } - - protected function visit_exceptions(RequestInterface $request, $value, $flags) - { - if ($value === false || $value === 0) { - $dispatcher = $request->getEventDispatcher(); - foreach ($dispatcher->getListeners('request.error') as $listener) { - if ($listener[0] == 'Guzzle\Http\Message\Request' && $listener[1] = 'onRequestError') { - $dispatcher->removeListener('request.error', $listener); - break; - } - } - } - } - - protected function visit_save_to(RequestInterface $request, $value, $flags) - { - $request->setResponseBody($value); - } - - protected function visit_params(RequestInterface $request, $value, $flags) - { - if (!is_array($value)) { - throw new InvalidArgumentException('params value must be an array'); - } - - $request->getParams()->overwriteWith($value); - } - - protected function visit_timeout(RequestInterface $request, $value, $flags) - { - $request->getCurlOptions()->set(CURLOPT_TIMEOUT_MS, $value * 1000); - } - - protected function visit_connect_timeout(RequestInterface $request, $value, $flags) - { - $request->getCurlOptions()->set(CURLOPT_CONNECTTIMEOUT_MS, $value * 1000); - } - - protected function visit_debug(RequestInterface $request, $value, $flags) - { - if (class_exists('Guzzle\Plugin\Log\LogPlugin')) { - $request->addSubscriber(LogPlugin::getDebugPlugin()); - } else { - // @codeCoverageIgnoreStart - $request->getCurlOptions()->set(CURLOPT_VERBOSE, true); - // @codeCoverageIgnoreEnd - } - } - - protected function visit_verify(RequestInterface $request, $value, $flags) - { - $curl = $request->getCurlOptions(); - if ($value === true || is_string($value)) { - $curl[CURLOPT_SSL_VERIFYHOST] = 2; - $curl[CURLOPT_SSL_VERIFYPEER] = true; - if ($value !== true) { - $curl[CURLOPT_CAINFO] = $value; - } - } elseif ($value === false) { - unset($curl[CURLOPT_CAINFO]); - $curl[CURLOPT_SSL_VERIFYHOST] = 0; - $curl[CURLOPT_SSL_VERIFYPEER] = false; - } - } - - protected function visit_proxy(RequestInterface $request, $value, $flags) - { - $request->getCurlOptions()->set(CURLOPT_PROXY, $value, $flags); - } - - protected function visit_cert(RequestInterface $request, $value, $flags) - { - if (is_array($value)) { - $request->getCurlOptions()->set(CURLOPT_SSLCERT, $value[0]); - $request->getCurlOptions()->set(CURLOPT_SSLCERTPASSWD, $value[1]); - } else { - $request->getCurlOptions()->set(CURLOPT_SSLCERT, $value); - } - } - - protected function visit_ssl_key(RequestInterface $request, $value, $flags) - { - if (is_array($value)) { - $request->getCurlOptions()->set(CURLOPT_SSLKEY, $value[0]); - $request->getCurlOptions()->set(CURLOPT_SSLKEYPASSWD, $value[1]); - } else { - $request->getCurlOptions()->set(CURLOPT_SSLKEY, $value); - } - } -} diff --git a/core/vendor/guzzle/http/Guzzle/Http/Message/RequestFactoryInterface.php b/core/vendor/guzzle/http/Guzzle/Http/Message/RequestFactoryInterface.php deleted file mode 100644 index 6088f10e994..00000000000 --- a/core/vendor/guzzle/http/Guzzle/Http/Message/RequestFactoryInterface.php +++ /dev/null @@ -1,105 +0,0 @@ - 'Continue', - 101 => 'Switching Protocols', - 102 => 'Processing', - 200 => 'OK', - 201 => 'Created', - 202 => 'Accepted', - 203 => 'Non-Authoritative Information', - 204 => 'No Content', - 205 => 'Reset Content', - 206 => 'Partial Content', - 207 => 'Multi-Status', - 208 => 'Already Reported', - 226 => 'IM Used', - 300 => 'Multiple Choices', - 301 => 'Moved Permanently', - 302 => 'Found', - 303 => 'See Other', - 304 => 'Not Modified', - 305 => 'Use Proxy', - 307 => 'Temporary Redirect', - 308 => 'Permanent Redirect', - 400 => 'Bad Request', - 401 => 'Unauthorized', - 402 => 'Payment Required', - 403 => 'Forbidden', - 404 => 'Not Found', - 405 => 'Method Not Allowed', - 406 => 'Not Acceptable', - 407 => 'Proxy Authentication Required', - 408 => 'Request Timeout', - 409 => 'Conflict', - 410 => 'Gone', - 411 => 'Length Required', - 412 => 'Precondition Failed', - 413 => 'Request Entity Too Large', - 414 => 'Request-URI Too Long', - 415 => 'Unsupported Media Type', - 416 => 'Requested Range Not Satisfiable', - 417 => 'Expectation Failed', - 422 => 'Unprocessable Entity', - 423 => 'Locked', - 424 => 'Failed Dependency', - 425 => 'Reserved for WebDAV advanced collections expired proposal', - 426 => 'Upgrade required', - 428 => 'Precondition Required', - 429 => 'Too Many Requests', - 431 => 'Request Header Fields Too Large', - 500 => 'Internal Server Error', - 501 => 'Not Implemented', - 502 => 'Bad Gateway', - 503 => 'Service Unavailable', - 504 => 'Gateway Timeout', - 505 => 'HTTP Version Not Supported', - 506 => 'Variant Also Negotiates (Experimental)', - 507 => 'Insufficient Storage', - 508 => 'Loop Detected', - 510 => 'Not Extended', - 511 => 'Network Authentication Required', - ); - - /** @var EntityBodyInterface The response body */ - protected $body; - - /** @var string The reason phrase of the response (human readable code) */ - protected $reasonPhrase; - - /** @var string The status code of the response */ - protected $statusCode; - - /** @var array Information about the request */ - protected $info = array(); - - /** @var string The effective URL that returned this response */ - protected $effectiveUrl; - - /** @var array Cacheable response codes (see RFC 2616:13.4) */ - protected static $cacheResponseCodes = array(200, 203, 206, 300, 301, 410); - - /** - * Create a new Response based on a raw response message - * - * @param string $message Response message - * - * @return self|bool Returns false on error - */ - public static function fromMessage($message) - { - $data = ParserRegistry::getInstance()->getParser('message')->parseResponse($message); - if (!$data) { - return false; - } - - $response = new static($data['code'], $data['headers'], $data['body']); - $response->setProtocol($data['protocol'], $data['version']) - ->setStatus($data['code'], $data['reason_phrase']); - - // Set the appropriate Content-Length if the one set is inaccurate (e.g. setting to X) - $contentLength = (string) $response->getHeader('Content-Length'); - $actualLength = strlen($data['body']); - if (strlen($data['body']) > 0 && $contentLength != $actualLength) { - $response->setHeader('Content-Length', $actualLength); - } - - return $response; - } - - /** - * Construct the response - * - * @param string $statusCode The response status code (e.g. 200, 404, etc) - * @param ToArrayInterface|array $headers The response headers - * @param string|resource|EntityBodyInterface $body The body of the response - * - * @throws BadResponseException if an invalid response code is given - */ - public function __construct($statusCode, $headers = null, $body = null) - { - parent::__construct(); - $this->setStatus($statusCode); - $this->body = EntityBody::factory($body !== null ? $body : ''); - - if ($headers) { - if (is_array($headers)) { - $this->setHeaders($headers); - } elseif ($headers instanceof ToArrayInterface) { - $this->setHeaders($headers->toArray()); - } else { - throw new BadResponseException('Invalid headers argument received'); - } - } - } - - /** - * @return string - */ - public function __toString() - { - return $this->getMessage(); - } - - public function serialize() - { - return json_encode(array( - 'status' => $this->statusCode, - 'body' => (string) $this->body, - 'headers' => $this->headers->toArray() - )); - } - - public function unserialize($serialize) - { - $data = json_decode($serialize, true); - $this->__construct($data['status'], $data['headers'], $data['body']); - } - - /** - * Get the response entity body - * - * @param bool $asString Set to TRUE to return a string of the body rather than a full body object - * - * @return EntityBodyInterface|string - */ - public function getBody($asString = false) - { - return $asString ? (string) $this->body : $this->body; - } - - /** - * Set the response entity body - * - * @param EntityBodyInterface|string $body Body to set - * - * @return self - */ - public function setBody($body) - { - $this->body = EntityBody::factory($body); - - return $this; - } - - /** - * Set the protocol and protocol version of the response - * - * @param string $protocol Response protocol - * @param string $version Protocol version - * - * @return self - */ - public function setProtocol($protocol, $version) - { - $this->protocol = $protocol; - $this->protocolVersion = $version; - - return $this; - } - - /** - * Get the protocol used for the response (e.g. HTTP) - * - * @return string - */ - public function getProtocol() - { - return $this->protocol; - } - - /** - * Get the HTTP protocol version - * - * @return string - */ - public function getProtocolVersion() - { - return $this->protocolVersion; - } - - /** - * Get a cURL transfer information - * - * @param string $key A single statistic to check - * - * @return array|string|null Returns all stats if no key is set, a single stat if a key is set, or null if a key - * is set and not found - * @link http://www.php.net/manual/en/function.curl-getinfo.php - */ - public function getInfo($key = null) - { - if ($key === null) { - return $this->info; - } elseif (array_key_exists($key, $this->info)) { - return $this->info[$key]; - } else { - return null; - } - } - - /** - * Set the transfer information - * - * @param array $info Array of cURL transfer stats - * - * @return self - */ - public function setInfo(array $info) - { - $this->info = $info; - - return $this; - } - - /** - * Set the response status - * - * @param int $statusCode Response status code to set - * @param string $reasonPhrase Response reason phrase - * - * @return self - * @throws BadResponseException when an invalid response code is received - */ - public function setStatus($statusCode, $reasonPhrase = '') - { - $this->statusCode = (int) $statusCode; - - if (!$reasonPhrase && isset(self::$statusTexts[$this->statusCode])) { - $this->reasonPhrase = self::$statusTexts[$this->statusCode]; - } else { - $this->reasonPhrase = $reasonPhrase; - } - - return $this; - } - - /** - * Get the response status code - * - * @return integer - */ - public function getStatusCode() - { - return $this->statusCode; - } - - /** - * Get the entire response as a string - * - * @return string - */ - public function getMessage() - { - $message = $this->getRawHeaders(); - - // Only include the body in the message if the size is < 2MB - $size = $this->body->getSize(); - if ($size < 2097152) { - $message .= (string) $this->body; - } - - return $message; - } - - /** - * Get the the raw message headers as a string - * - * @return string - */ - public function getRawHeaders() - { - $headers = 'HTTP/1.1 ' . $this->statusCode . ' ' . $this->reasonPhrase . "\r\n"; - $lines = $this->getHeaderLines(); - if (!empty($lines)) { - $headers .= implode("\r\n", $lines) . "\r\n"; - } - - return $headers . "\r\n"; - } - - /** - * Get the response reason phrase- a human readable version of the numeric - * status code - * - * @return string - */ - public function getReasonPhrase() - { - return $this->reasonPhrase; - } - - /** - * Get the Accept-Ranges HTTP header - * - * @return string Returns what partial content range types this server supports. - */ - public function getAcceptRanges() - { - return (string) $this->getHeader('Accept-Ranges'); - } - - /** - * Calculate the age of the response - * - * @return integer - */ - public function calculateAge() - { - $age = $this->getHeader('Age'); - - if ($age === null && $this->getDate()) { - $age = time() - strtotime($this->getDate()); - } - - return $age === null ? null : (int) (string) $age; - } - - /** - * Get the Age HTTP header - * - * @return integer|null Returns the age the object has been in a proxy cache in seconds. - */ - public function getAge() - { - return (string) $this->getHeader('Age'); - } - - /** - * Get the Allow HTTP header - * - * @return string|null Returns valid actions for a specified resource. To be used for a 405 Method not allowed. - */ - public function getAllow() - { - return (string) $this->getHeader('Allow'); - } - - /** - * Check if an HTTP method is allowed by checking the Allow response header - * - * @param string $method Method to check - * - * @return bool - */ - public function isMethodAllowed($method) - { - $allow = $this->getHeader('Allow'); - if ($allow) { - foreach (explode(',', $allow) as $allowable) { - if (!strcasecmp(trim($allowable), $method)) { - return true; - } - } - } - - return false; - } - - /** - * Get the Cache-Control HTTP header - * - * @return string - */ - public function getCacheControl() - { - return (string) $this->getHeader('Cache-Control'); - } - - /** - * Get the Connection HTTP header - * - * @return string - */ - public function getConnection() - { - return (string) $this->getHeader('Connection'); - } - - /** - * Get the Content-Encoding HTTP header - * - * @return string|null - */ - public function getContentEncoding() - { - return (string) $this->getHeader('Content-Encoding'); - } - - /** - * Get the Content-Language HTTP header - * - * @return string|null Returns the language the content is in. - */ - public function getContentLanguage() - { - return (string) $this->getHeader('Content-Language'); - } - - /** - * Get the Content-Length HTTP header - * - * @return integer Returns the length of the response body in bytes - */ - public function getContentLength() - { - return (int) (string) $this->getHeader('Content-Length'); - } - - /** - * Get the Content-Location HTTP header - * - * @return string|null Returns an alternate location for the returned data (e.g /index.htm) - */ - public function getContentLocation() - { - return (string) $this->getHeader('Content-Location'); - } - - /** - * Get the Content-Disposition HTTP header - * - * @return string|null Returns the Content-Disposition header - */ - public function getContentDisposition() - { - return (string) $this->getHeader('Content-Disposition'); - } - - /** - * Get the Content-MD5 HTTP header - * - * @return string|null Returns a Base64-encoded binary MD5 sum of the content of the response. - */ - public function getContentMd5() - { - return (string) $this->getHeader('Content-MD5'); - } - - /** - * Get the Content-Range HTTP header - * - * @return string Returns where in a full body message this partial message belongs (e.g. bytes 21010-47021/47022). - */ - public function getContentRange() - { - return (string) $this->getHeader('Content-Range'); - } - - /** - * Get the Content-Type HTTP header - * - * @return string Returns the mime type of this content. - */ - public function getContentType() - { - return (string) $this->getHeader('Content-Type'); - } - - /** - * Checks if the Content-Type is of a certain type. This is useful if the - * Content-Type header contains charset information and you need to know if - * the Content-Type matches a particular type. - * - * @param string $type Content type to check against - * - * @return bool - */ - public function isContentType($type) - { - return stripos($this->getHeader('Content-Type'), $type) !== false; - } - - /** - * Get the Date HTTP header - * - * @return string|null Returns the date and time that the message was sent. - */ - public function getDate() - { - return (string) $this->getHeader('Date'); - } - - /** - * Get the ETag HTTP header - * - * @return string|null Returns an identifier for a specific version of a resource, often a Message digest. - */ - public function getEtag() - { - return (string) $this->getHeader('ETag'); - } - - /** - * Get the Expires HTTP header - * - * @return string|null Returns the date/time after which the response is considered stale. - */ - public function getExpires() - { - return (string) $this->getHeader('Expires'); - } - - /** - * Get the Last-Modified HTTP header - * - * @return string|null Returns the last modified date for the requested object, in RFC 2822 format - * (e.g. Tue, 15 Nov 1994 12:45:26 GMT) - */ - public function getLastModified() - { - return (string) $this->getHeader('Last-Modified'); - } - - /** - * Get the Location HTTP header - * - * @return string|null Used in redirection, or when a new resource has been created. - */ - public function getLocation() - { - return (string) $this->getHeader('Location'); - } - - /** - * Get the Pragma HTTP header - * - * @return Header|null Returns the implementation-specific headers that may have various effects anywhere along - * the request-response chain. - */ - public function getPragma() - { - return (string) $this->getHeader('Pragma'); - } - - /** - * Get the Proxy-Authenticate HTTP header - * - * @return string|null Authentication to access the proxy (e.g. Basic) - */ - public function getProxyAuthenticate() - { - return (string) $this->getHeader('Proxy-Authenticate'); - } - - /** - * Get the Retry-After HTTP header - * - * @return int|null If an entity is temporarily unavailable, this instructs the client to try again after a - * specified period of time. - */ - public function getRetryAfter() - { - return (string) $this->getHeader('Retry-After'); - } - - /** - * Get the Server HTTP header - * - * @return string|null A name for the server - */ - public function getServer() - { - return (string) $this->getHeader('Server'); - } - - /** - * Get the Set-Cookie HTTP header - * - * @return string|null An HTTP cookie. - */ - public function getSetCookie() - { - return (string) $this->getHeader('Set-Cookie'); - } - - /** - * Get the Trailer HTTP header - * - * @return string|null The Trailer general field value indicates that the given set of header fields is present in - * the trailer of a message encoded with chunked transfer-coding. - */ - public function getTrailer() - { - return (string) $this->getHeader('Trailer'); - } - - /** - * Get the Transfer-Encoding HTTP header - * - * @return string|null The form of encoding used to safely transfer the entity to the user - */ - public function getTransferEncoding() - { - return (string) $this->getHeader('Transfer-Encoding'); - } - - /** - * Get the Vary HTTP header - * - * @return string|null Tells downstream proxies how to match future request headers to decide whether the cached - * response can be used rather than requesting a fresh one from the origin server. - */ - public function getVary() - { - return (string) $this->getHeader('Vary'); - } - - /** - * Get the Via HTTP header - * - * @return string|null Informs the client of proxies through which the response was sent. - */ - public function getVia() - { - return (string) $this->getHeader('Via'); - } - - /** - * Get the Warning HTTP header - * - * @return string|null A general warning about possible problems with the entity body - */ - public function getWarning() - { - return (string) $this->getHeader('Warning'); - } - - /** - * Get the WWW-Authenticate HTTP header - * - * @return string|null Indicates the authentication scheme that should be used to access the requested entity - */ - public function getWwwAuthenticate() - { - return (string) $this->getHeader('WWW-Authenticate'); - } - - /** - * Checks if HTTP Status code is a Client Error (4xx) - * - * @return bool - */ - public function isClientError() - { - return $this->statusCode >= 400 && $this->statusCode < 500; - } - - /** - * Checks if HTTP Status code is Server OR Client Error (4xx or 5xx) - * - * @return boolean - */ - public function isError() - { - return $this->isClientError() || $this->isServerError(); - } - - /** - * Checks if HTTP Status code is Information (1xx) - * - * @return bool - */ - public function isInformational() - { - return $this->statusCode < 200; - } - - /** - * Checks if HTTP Status code is a Redirect (3xx) - * - * @return bool - */ - public function isRedirect() - { - return $this->statusCode >= 300 && $this->statusCode < 400; - } - - /** - * Checks if HTTP Status code is Server Error (5xx) - * - * @return bool - */ - public function isServerError() - { - return $this->statusCode >= 500 && $this->statusCode < 600; - } - - /** - * Checks if HTTP Status code is Successful (2xx | 304) - * - * @return bool - */ - public function isSuccessful() - { - return ($this->statusCode >= 200 && $this->statusCode < 300) || $this->statusCode == 304; - } - - /** - * Check if the response can be cached based on the response headers - * - * @return bool Returns TRUE if the response can be cached or false if not - */ - public function canCache() - { - // Check if the response is cacheable based on the code - if (!in_array((int) $this->getStatusCode(), self::$cacheResponseCodes)) { - return false; - } - - // Make sure a valid body was returned and can be cached - if ((!$this->getBody()->isReadable() || !$this->getBody()->isSeekable()) - && ($this->getContentLength() > 0 || $this->getTransferEncoding() == 'chunked')) { - return false; - } - - // Never cache no-store resources (this is a private cache, so private - // can be cached) - if ($this->getHeader('Cache-Control') && $this->getHeader('Cache-Control')->hasDirective('no-store')) { - return false; - } - - return $this->isFresh() || $this->getFreshness() === null || $this->canValidate(); - } - - /** - * Gets the number of seconds from the current time in which this response is still considered fresh - * - * @return int|null Returns the number of seconds - */ - public function getMaxAge() - { - if ($header = $this->getHeader('Cache-Control')) { - // s-max-age, then max-age, then Expires - if ($age = $header->getDirective('s-maxage')) { - return $age; - } - if ($age = $header->getDirective('max-age')) { - return $age; - } - } - - if ($this->getHeader('Expires')) { - return strtotime($this->getExpires()) - time(); - } - - return null; - } - - /** - * Check if the response is considered fresh. - * - * A response is considered fresh when its age is less than or equal to the freshness lifetime (maximum age) of the - * response. - * - * @return bool|null - */ - public function isFresh() - { - $fresh = $this->getFreshness(); - - return $fresh === null ? null : $fresh >= 0; - } - - /** - * Check if the response can be validated against the origin server using a conditional GET request. - * - * @return bool - */ - public function canValidate() - { - return $this->getEtag() || $this->getLastModified(); - } - - /** - * Get the freshness of the response by returning the difference of the maximum lifetime of the response and the - * age of the response (max-age - age). - * - * Freshness values less than 0 mean that the response is no longer fresh and is ABS(freshness) seconds expired. - * Freshness values of greater than zero is the number of seconds until the response is no longer fresh. A NULL - * result means that no freshness information is available. - * - * @return int - */ - public function getFreshness() - { - $maxAge = $this->getMaxAge(); - $age = $this->calculateAge(); - - return $maxAge && $age ? ($maxAge - $age) : null; - } - - /** - * Parse the JSON response body and return an array - * - * @return array|string|int|bool|float - * @throws RuntimeException if the response body is not in JSON format - */ - public function json() - { - $data = json_decode((string) $this->body, true); - if (JSON_ERROR_NONE !== json_last_error()) { - throw new RuntimeException('Unable to parse response body into JSON: ' . json_last_error()); - } - - return $data === null ? array() : $data; - } - - /** - * Parse the XML response body and return a SimpleXMLElement - * - * @return \SimpleXMLElement - * @throws RuntimeException if the response body is not in XML format - */ - public function xml() - { - try { - // Allow XML to be retrieved even if there is no response body - $xml = new \SimpleXMLElement((string) $this->body ?: ''); - } catch (\Exception $e) { - throw new RuntimeException('Unable to parse response body into XML: ' . $e->getMessage()); - } - - return $xml; - } - - /** - * Get the redirect count of this response - * - * @return int - */ - public function getRedirectCount() - { - return (int) $this->params->get(RedirectPlugin::REDIRECT_COUNT); - } - - /** - * Set the effective URL that resulted in this response (e.g. the last redirect URL) - * - * @param string $url The effective URL - * - * @return self - */ - public function setEffectiveUrl($url) - { - $this->effectiveUrl = $url; - - return $this; - } - - /** - * Get the effective URL that resulted in this response (e.g. the last redirect URL) - * - * @return string - */ - public function getEffectiveUrl() - { - return $this->effectiveUrl; - } - - /** - * @deprecated - * @codeCoverageIgnore - */ - public function getPreviousResponse() - { - Version::warn(__METHOD__ . ' is deprecated. Use the HistoryPlugin.'); - return null; - } - - /** - * @deprecated - * @codeCoverageIgnore - */ - public function setRequest($request) - { - Version::warn(__METHOD__ . ' is deprecated'); - return $this; - } - - /** - * @deprecated - * @codeCoverageIgnore - */ - public function getRequest() - { - Version::warn(__METHOD__ . ' is deprecated'); - return null; - } -} diff --git a/core/vendor/guzzle/http/Guzzle/Http/QueryAggregator/CommaAggregator.php b/core/vendor/guzzle/http/Guzzle/Http/QueryAggregator/CommaAggregator.php deleted file mode 100644 index 4b4e49d0520..00000000000 --- a/core/vendor/guzzle/http/Guzzle/Http/QueryAggregator/CommaAggregator.php +++ /dev/null @@ -1,20 +0,0 @@ -isUrlEncoding()) { - return array($query->encodeValue($key) => implode(',', array_map(array($query, 'encodeValue'), $value))); - } else { - return array($key => implode(',', $value)); - } - } -} diff --git a/core/vendor/guzzle/http/Guzzle/Http/QueryAggregator/DuplicateAggregator.php b/core/vendor/guzzle/http/Guzzle/Http/QueryAggregator/DuplicateAggregator.php deleted file mode 100644 index 1bf1730e4e6..00000000000 --- a/core/vendor/guzzle/http/Guzzle/Http/QueryAggregator/DuplicateAggregator.php +++ /dev/null @@ -1,22 +0,0 @@ -isUrlEncoding()) { - return array($query->encodeValue($key) => array_map(array($query, 'encodeValue'), $value)); - } else { - return array($key => $value); - } - } -} diff --git a/core/vendor/guzzle/http/Guzzle/Http/QueryAggregator/PhpAggregator.php b/core/vendor/guzzle/http/Guzzle/Http/QueryAggregator/PhpAggregator.php deleted file mode 100644 index 133ea2bd962..00000000000 --- a/core/vendor/guzzle/http/Guzzle/Http/QueryAggregator/PhpAggregator.php +++ /dev/null @@ -1,27 +0,0 @@ - $v) { - $k = "{$key}[{$k}]"; - if (is_array($v)) { - $ret = array_merge($ret, self::aggregate($k, $v, $query)); - } else { - $ret[$query->encodeValue($k)] = $query->encodeValue($v); - } - } - - return $ret; - } -} diff --git a/core/vendor/guzzle/http/Guzzle/Http/QueryAggregator/QueryAggregatorInterface.php b/core/vendor/guzzle/http/Guzzle/Http/QueryAggregator/QueryAggregatorInterface.php deleted file mode 100644 index 72bee620c82..00000000000 --- a/core/vendor/guzzle/http/Guzzle/Http/QueryAggregator/QueryAggregatorInterface.php +++ /dev/null @@ -1,22 +0,0 @@ -hasKey($key)) { - $value = array($value); - } - $q->add($key, $value); - } else { - $q->add($key, null); - } - } - } - - return $q; - } - - /** - * Convert the query string parameters to a query string string - * - * @return string - */ - public function __toString() - { - if (!$this->data) { - return ''; - } - - $queryString = ''; - - foreach ($this->prepareData($this->data) as $name => $value) { - foreach ((array) $value as $v) { - if ($queryString) { - $queryString .= $this->fieldSeparator; - } - $queryString .= $name; - if ($v !== self::BLANK) { - $queryString .= $this->valueSeparator . $v; - } - } - } - - return $queryString; - } - - /** - * Get the query string field separator - * - * @return string - */ - public function getFieldSeparator() - { - return $this->fieldSeparator; - } - - /** - * Get the query string value separator - * - * @return string - */ - public function getValueSeparator() - { - return $this->valueSeparator; - } - - /** - * Returns the type of URL encoding used by the query string - * - * One of: false, "RFC 3986", or "application/x-www-form-urlencoded" - * - * @return bool|string - */ - public function getUrlEncoding() - { - return $this->urlEncode; - } - - /** - * Returns true or false if using URL encoding - * - * @return bool - */ - public function isUrlEncoding() - { - return $this->urlEncode !== false; - } - - /** - * Provide a function for combining multi-valued query string parameters into a single or multiple fields - * - * @param null|QueryAggregatorInterface $aggregator Pass in a QueryAggregatorInterface object to handle converting - * deeply nested query string variables into a flattened array. - * Pass null to use the default PHP style aggregator. For legacy - * reasons, this function accepts a callable that must accepts a - * $key, $value, and query object. - * @return self - * @see \Guzzle\Http\QueryString::aggregateUsingComma() - */ - public function setAggregator(QueryAggregatorInterface $aggregator = null) - { - // Use the default aggregator if none was set - if (!$aggregator) { - if (!self::$defaultAggregator) { - self::$defaultAggregator = new PhpAggregator(); - } - $aggregator = self::$defaultAggregator; - } - - $this->aggregator = $aggregator; - - return $this; - } - - /** - * Set whether or not field names and values should be rawurlencoded - * - * @param bool|string $encode Set to TRUE to use RFC 3986 encoding (rawurlencode), false to disable encoding, or - * form_urlencoding to use application/x-www-form-urlencoded encoding (urlencode) - * @return self - */ - public function useUrlEncoding($encode) - { - $this->urlEncode = ($encode === true) ? self::RFC_3986 : $encode; - - return $this; - } - - /** - * Set the query string separator - * - * @param string $separator The query string separator that will separate fields - * - * @return self - */ - public function setFieldSeparator($separator) - { - $this->fieldSeparator = $separator; - - return $this; - } - - /** - * Set the query string value separator - * - * @param string $separator The query string separator that will separate values from fields - * - * @return self - */ - public function setValueSeparator($separator) - { - $this->valueSeparator = $separator; - - return $this; - } - - /** - * Returns an array of url encoded field names and values - * - * @return array - */ - public function urlEncode() - { - return $this->prepareData($this->data); - } - - /** - * URL encodes a value based on the url encoding type of the query string object - * - * @param string $value Value to encode - * - * @return string - */ - public function encodeValue($value) - { - if ($this->urlEncode == self::RFC_3986) { - return rawurlencode($value); - } elseif ($this->urlEncode == self::FORM_URLENCODED) { - return urlencode($value); - } else { - return (string) $value; - } - } - - /** - * Url encode parameter data and convert nested query strings into a flattened hash. - * - * @param array $data The data to encode - * - * @return array Returns an array of encoded values and keys - */ - protected function prepareData(array $data) - { - // If no aggregator is present then set the default - if (!$this->aggregator) { - $this->setAggregator(null); - } - - $temp = array(); - foreach ($data as $key => $value) { - if (is_array($value)) { - $temp = array_merge($temp, $this->aggregator->aggregate($key, $value, $this)); - } else { - $temp[$this->encodeValue($key)] = $this->encodeValue($value); - } - } - - return $temp; - } -} diff --git a/core/vendor/guzzle/http/Guzzle/Http/ReadLimitEntityBody.php b/core/vendor/guzzle/http/Guzzle/Http/ReadLimitEntityBody.php deleted file mode 100644 index d0bc867e3aa..00000000000 --- a/core/vendor/guzzle/http/Guzzle/Http/ReadLimitEntityBody.php +++ /dev/null @@ -1,106 +0,0 @@ -setLimit($limit)->setOffset($offset); - $this->body->seek($offset); - } - - /** - * Returns only a subset of the decorated entity body when cast as a string - * {@inheritdoc} - */ - public function __toString() - { - return substr((string) $this->body, $this->offset, $this->limit) ?: ''; - } - - public function isConsumed() - { - return (($this->offset + $this->limit) - $this->body->ftell()) <= 0; - } - - /** - * Returns the Content-Length of the limited subset of data - * {@inheritdoc} - */ - public function getContentLength() - { - $length = $this->body->getContentLength(); - - return $length === false - ? $this->limit - : min($this->limit, min($length, $this->offset + $this->limit) - $this->offset); - } - - /** - * Allow for a bounded seek on the read limited entity body - * {@inheritdoc} - */ - public function seek($offset, $whence = SEEK_SET) - { - return $whence === SEEK_SET - ? $this->body->seek(max($this->offset, min($this->offset + $this->limit, $offset))) - : false; - } - - /** - * Set the offset to start limiting from - * - * @param int $offset Offset to seek to and begin byte limiting from - * - * @return self - */ - public function setOffset($offset) - { - $this->body->seek($offset); - $this->offset = $offset; - - return $this; - } - - /** - * Set the limit of bytes that the decorator allows to be read from the stream - * - * @param int $limit Total number of bytes to allow to be read from the stream - * - * @return self - */ - public function setLimit($limit) - { - $this->limit = $limit; - - return $this; - } - - public function read($length) - { - // Check if the current position is less than the total allowed bytes + original offset - $remaining = ($this->offset + $this->limit) - $this->body->ftell(); - if ($remaining > 0) { - // Only return the amount of requested data, ensuring that the byte limit is not exceeded - return $this->body->read(min($remaining, $length)); - } else { - return false; - } - } -} diff --git a/core/vendor/guzzle/http/Guzzle/Http/RedirectPlugin.php b/core/vendor/guzzle/http/Guzzle/Http/RedirectPlugin.php deleted file mode 100644 index 391edb152b7..00000000000 --- a/core/vendor/guzzle/http/Guzzle/Http/RedirectPlugin.php +++ /dev/null @@ -1,250 +0,0 @@ - array('onRequestSent', 100), - 'request.clone' => 'cleanupRequest', - 'request.before_send' => 'cleanupRequest' - ); - } - - /** - * Clean up the parameters of a request when it is cloned - * - * @param Event $event Event emitted - */ - public function cleanupRequest(Event $event) - { - $params = $event['request']->getParams(); - unset($params[self::REDIRECT_COUNT]); - unset($params[self::PARENT_REQUEST]); - } - - /** - * Called when a request receives a redirect response - * - * @param Event $event Event emitted - */ - public function onRequestSent(Event $event) - { - $response = $event['response']; - $request = $event['request']; - - // Only act on redirect requests with Location headers - if (!$response || $request->getParams()->get(self::DISABLE)) { - return; - } - - // Trace the original request based on parameter history - $original = $this->getOriginalRequest($request); - - // Terminating condition to set the effective repsonse on the original request - if (!$response->isRedirect() || !$response->hasHeader('Location')) { - if ($request !== $original) { - // This is a terminating redirect response, so set it on the original request - $response->getParams()->set(self::REDIRECT_COUNT, $original->getParams()->get(self::REDIRECT_COUNT)); - $original->setResponse($response); - $response->setEffectiveUrl($request->getUrl()); - } - return; - } - - $this->sendRedirectRequest($original, $request, $response); - } - - /** - * Get the original request that initiated a series of redirects - * - * @param RequestInterface $request Request to get the original request from - * - * @return RequestInterface - */ - protected function getOriginalRequest(RequestInterface $request) - { - $original = $request; - // The number of redirects is held on the original request, so determine which request that is - while ($parent = $original->getParams()->get(self::PARENT_REQUEST)) { - $original = $parent; - } - - return $original; - } - - /** - * 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 Request being redirected - * @param RequestInterface $original Original request - * @param int $statusCode Status code of the redirect - * @param string $location Location header of the redirect - * - * @return RequestInterface Returns a new redirect request - * @throws CouldNotRewindStreamException If the body needs to be rewound but cannot - */ - protected function createRedirectRequest( - RequestInterface $request, - $statusCode, - $location, - RequestInterface $original - ) { - $redirectRequest = null; - $strict = $original->getParams()->get(self::STRICT_REDIRECTS); - - // 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 - if ($request instanceof EntityEnclosingRequestInterface && !$strict && $statusCode <= 302) { - $redirectRequest = RequestFactory::getInstance()->cloneRequestWithMethod($request, 'GET'); - } else { - $redirectRequest = clone $request; - } - - $redirectRequest->setIsRedirect(true); - // Always use the same response body when redirecting - $redirectRequest->setResponseBody($request->getResponseBody()); - - $location = Url::factory($location); - // If the location is not absolute, then combine it with the original URL - if (!$location->isAbsolute()) { - $originalUrl = $redirectRequest->getUrl(true); - // Remove query string parameters and just take what is present on the redirect Location header - $originalUrl->getQuery()->clear(); - $location = $originalUrl->combine((string) $location); - } - - $redirectRequest->setUrl($location); - - // Add the parent request to the request before it sends (make sure it's before the onRequestClone event too) - $redirectRequest->getEventDispatcher()->addListener( - 'request.before_send', - $func = function ($e) use (&$func, $request, $redirectRequest) { - $redirectRequest->getEventDispatcher()->removeListener('request.before_send', $func); - $e['request']->getParams()->set(RedirectPlugin::PARENT_REQUEST, $request); - } - ); - - // Rewind the entity body of the request if needed - if ($redirectRequest instanceof EntityEnclosingRequestInterface && $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->ftell() && !$body->rewind()) { - throw new CouldNotRewindStreamException( - 'Unable to rewind the non-seekable entity body of the request after redirecting. cURL probably ' - . 'sent part of body before the redirect occurred. Try adding acustom rewind function using on the ' - . 'entity body of the request using setRewindFunction().' - ); - } - } - - return $redirectRequest; - } - - /** - * Prepare the request for redirection and enforce the maximum number of allowed redirects per client - * - * @param RequestInterface $original Origina request - * @param RequestInterface $request Request to prepare and validate - * @param Response $response The current response - * - * @return RequestInterface - */ - protected function prepareRedirection(RequestInterface $original, RequestInterface $request, Response $response) - { - $params = $original->getParams(); - // This is a new redirect, so increment the redirect counter - $current = $params[self::REDIRECT_COUNT] + 1; - $params[self::REDIRECT_COUNT] = $current; - // Use a provided maximum value or default to a max redirect count of 5 - $max = isset($params[self::MAX_REDIRECTS]) ? $params[self::MAX_REDIRECTS] : $this->defaultMaxRedirects; - - // Throw an exception if the redirect count is exceeded - if ($current > $max) { - $this->throwTooManyRedirectsException($original, $max); - return false; - } else { - // Create a redirect request based on the redirect rules set on the request - return $this->createRedirectRequest( - $request, - $response->getStatusCode(), - trim($response->getLocation()), - $original - ); - } - } - - /** - * Send a redirect request and handle any errors - * - * @param RequestInterface $original The originating request - * @param RequestInterface $request The current request being redirected - * @param Response $response The response of the current request - * - * @throws BadResponseException|\Exception - */ - protected function sendRedirectRequest(RequestInterface $original, RequestInterface $request, Response $response) - { - // Validate and create a redirect request based on the original request and current response - if ($redirectRequest = $this->prepareRedirection($original, $request, $response)) { - try { - $redirectRequest->send(); - } catch (BadResponseException $e) { - $e->getResponse(); - if (!$e->getResponse()) { - throw $e; - } - } - } - } - - /** - * Throw a too many redirects exception for a request - * - * @param RequestInterface $original Request - * @param int $max Max allowed redirects - * - * @throws TooManyRedirectsException when too many redirects have been issued - */ - protected function throwTooManyRedirectsException(RequestInterface $original, $max) - { - $original->getEventDispatcher()->addListener( - 'request.complete', - $func = function ($e) use (&$func, $original, $max) { - $original->getEventDispatcher()->removeListener('request.complete', $func); - $str = "{$max} redirects were issued for this request:\n" . $e['request']->getRawHeaders(); - throw new TooManyRedirectsException($str); - } - ); - } -} diff --git a/core/vendor/guzzle/http/Guzzle/Http/Resources/cacert.pem.md5 b/core/vendor/guzzle/http/Guzzle/Http/Resources/cacert.pem.md5 deleted file mode 100644 index 56f626a9348..00000000000 --- a/core/vendor/guzzle/http/Guzzle/Http/Resources/cacert.pem.md5 +++ /dev/null @@ -1 +0,0 @@ -47961e7ef15667c93cd99be01b51f00a diff --git a/core/vendor/guzzle/http/Guzzle/Http/StaticClient.php b/core/vendor/guzzle/http/Guzzle/Http/StaticClient.php deleted file mode 100644 index dbd4c18413a..00000000000 --- a/core/vendor/guzzle/http/Guzzle/Http/StaticClient.php +++ /dev/null @@ -1,157 +0,0 @@ -createRequest($method, $url, null, null, $options); - - if (isset($options['stream'])) { - if ($options['stream'] instanceof StreamRequestFactoryInterface) { - return $options['stream']->fromRequest($request); - } elseif ($options['stream'] == true) { - $streamFactory = new PhpStreamRequestFactory(); - return $streamFactory->fromRequest($request); - } - } - - return $request->send(); - } - - /** - * Send a GET request - * - * @param string $url URL of the request - * @param array $options Array of request options - * - * @return \Guzzle\Http\Message\Response - * @see Guzzle::request for a list of available options - */ - public static function get($url, $options = array()) - { - return self::request('GET', $url, $options); - } - - /** - * Send a HEAD request - * - * @param string $url URL of the request - * @param array $options Array of request options - * - * @return \Guzzle\Http\Message\Response - * @see Guzzle::request for a list of available options - */ - public static function head($url, $options = array()) - { - return self::request('HEAD', $url, $options); - } - - /** - * Send a DELETE request - * - * @param string $url URL of the request - * @param array $options Array of request options - * - * @return \Guzzle\Http\Message\Response - * @see Guzzle::request for a list of available options - */ - public static function delete($url, $options = array()) - { - return self::request('DELETE', $url, $options); - } - - /** - * Send a POST request - * - * @param string $url URL of the request - * @param array $options Array of request options - * - * @return \Guzzle\Http\Message\Response - * @see Guzzle::request for a list of available options - */ - public static function post($url, $options = array()) - { - return self::request('POST', $url, $options); - } - - /** - * Send a PUT request - * - * @param string $url URL of the request - * @param array $options Array of request options - * - * @return \Guzzle\Http\Message\Response - * @see Guzzle::request for a list of available options - */ - public static function put($url, $options = array()) - { - return self::request('PUT', $url, $options); - } - - /** - * Send a PATCH request - * - * @param string $url URL of the request - * @param array $options Array of request options - * - * @return \Guzzle\Http\Message\Response - * @see Guzzle::request for a list of available options - */ - public static function patch($url, $options = array()) - { - return self::request('PATCH', $url, $options); - } - - /** - * Send an OPTIONS request - * - * @param string $url URL of the request - * @param array $options Array of request options - * - * @return \Guzzle\Http\Message\Response - * @see Guzzle::request for a list of available options - */ - public static function options($url, $options = array()) - { - return self::request('OPTIONS', $url, $options); - } -} diff --git a/core/vendor/guzzle/http/Guzzle/Http/composer.json b/core/vendor/guzzle/http/Guzzle/Http/composer.json deleted file mode 100644 index 9384a5bf918..00000000000 --- a/core/vendor/guzzle/http/Guzzle/Http/composer.json +++ /dev/null @@ -1,32 +0,0 @@ -{ - "name": "guzzle/http", - "description": "HTTP libraries used by Guzzle", - "homepage": "http://guzzlephp.org/", - "keywords": ["http client", "http", "client", "Guzzle", "curl"], - "license": "MIT", - "authors": [ - { - "name": "Michael Dowling", - "email": "mtdowling@gmail.com", - "homepage": "https://github.com/mtdowling" - } - ], - "require": { - "php": ">=5.3.2", - "guzzle/common": "self.version", - "guzzle/parser": "self.version", - "guzzle/stream": "self.version" - }, - "suggest": { - "ext-curl": "*" - }, - "autoload": { - "psr-0": { "Guzzle\\Http": "" } - }, - "target-dir": "Guzzle/Http", - "extra": { - "branch-alias": { - "dev-master": "3.7-dev" - } - } -} diff --git a/core/vendor/guzzle/parser/Guzzle/Parser/Cookie/CookieParser.php b/core/vendor/guzzle/parser/Guzzle/Parser/Cookie/CookieParser.php deleted file mode 100644 index 8e825f9bdea..00000000000 --- a/core/vendor/guzzle/parser/Guzzle/Parser/Cookie/CookieParser.php +++ /dev/null @@ -1,86 +0,0 @@ - 'Domain', - 'path' => 'Path', - 'max_age' => 'Max-Age', - 'expires' => 'Expires', - 'version' => 'Version', - 'secure' => 'Secure', - 'port' => 'Port', - 'discard' => 'Discard', - 'comment' => 'Comment', - 'comment_url' => 'Comment-Url', - 'http_only' => 'HttpOnly' - ); - - public function parseCookie($cookie, $host = null, $path = null, $decode = false) - { - // Explode the cookie string using a series of semicolons - $pieces = array_filter(array_map('trim', explode(';', $cookie))); - - // The name of the cookie (first kvp) must include an equal sign. - if (empty($pieces) || !strpos($pieces[0], '=')) { - return false; - } - - // Create the default return array - $data = array_merge(array_fill_keys(array_keys(self::$cookieParts), null), array( - 'cookies' => array(), - 'data' => array(), - 'path' => $path ?: '/', - 'http_only' => false, - 'discard' => false, - 'domain' => $host - )); - $foundNonCookies = 0; - - // Add the cookie pieces into the parsed data array - foreach ($pieces as $part) { - - $cookieParts = explode('=', $part, 2); - $key = trim($cookieParts[0]); - - if (count($cookieParts) == 1) { - // Can be a single value (e.g. secure, httpOnly) - $value = true; - } else { - // Be sure to strip wrapping quotes - $value = trim($cookieParts[1], " \n\r\t\0\x0B\""); - if ($decode) { - $value = urldecode($value); - } - } - - // Only check for non-cookies when cookies have been found - if (!empty($data['cookies'])) { - foreach (self::$cookieParts as $mapValue => $search) { - if (!strcasecmp($search, $key)) { - $data[$mapValue] = $mapValue == 'port' ? array_map('trim', explode(',', $value)) : $value; - $foundNonCookies++; - continue 2; - } - } - } - - // If cookies have not yet been retrieved, or this value was not found in the pieces array, treat it as a - // cookie. IF non-cookies have been parsed, then this isn't a cookie, it's cookie data. Cookies then data. - $data[$foundNonCookies ? 'data' : 'cookies'][$key] = $value; - } - - // Calculate the expires date - if (!$data['expires'] && $data['max_age']) { - $data['expires'] = time() + (int) $data['max_age']; - } - - return $data; - } -} diff --git a/core/vendor/guzzle/parser/Guzzle/Parser/Cookie/CookieParserInterface.php b/core/vendor/guzzle/parser/Guzzle/Parser/Cookie/CookieParserInterface.php deleted file mode 100644 index d21ffe21c1c..00000000000 --- a/core/vendor/guzzle/parser/Guzzle/Parser/Cookie/CookieParserInterface.php +++ /dev/null @@ -1,33 +0,0 @@ - $requestUrl, - 'scheme' => 'http' - ); - - // Check for the Host header - if (isset($parts['headers']['Host'])) { - $urlParts['host'] = $parts['headers']['Host']; - } elseif (isset($parts['headers']['host'])) { - $urlParts['host'] = $parts['headers']['host']; - } else { - $urlParts['host'] = null; - } - - if (false === strpos($urlParts['host'], ':')) { - $urlParts['port'] = ''; - } else { - $hostParts = explode(':', $urlParts['host']); - $urlParts['host'] = trim($hostParts[0]); - $urlParts['port'] = (int) trim($hostParts[1]); - if ($urlParts['port'] == 443) { - $urlParts['scheme'] = 'https'; - } - } - - // Check if a query is present - $path = $urlParts['path']; - $qpos = strpos($path, '?'); - if ($qpos) { - $urlParts['query'] = substr($path, $qpos + 1); - $urlParts['path'] = substr($path, 0, $qpos); - } else { - $urlParts['query'] = ''; - } - - return $urlParts; - } -} diff --git a/core/vendor/guzzle/parser/Guzzle/Parser/Message/MessageParser.php b/core/vendor/guzzle/parser/Guzzle/Parser/Message/MessageParser.php deleted file mode 100644 index 104740068e8..00000000000 --- a/core/vendor/guzzle/parser/Guzzle/Parser/Message/MessageParser.php +++ /dev/null @@ -1,110 +0,0 @@ -parseMessage($message); - - // Parse the protocol and protocol version - if (isset($parts['start_line'][2])) { - $startParts = explode('/', $parts['start_line'][2]); - $protocol = strtoupper($startParts[0]); - $version = isset($startParts[1]) ? $startParts[1] : '1.1'; - } else { - $protocol = 'HTTP'; - $version = '1.1'; - } - - $parsed = array( - 'method' => strtoupper($parts['start_line'][0]), - 'protocol' => $protocol, - 'version' => $version, - 'headers' => $parts['headers'], - 'body' => $parts['body'] - ); - - $parsed['request_url'] = $this->getUrlPartsFromMessage($parts['start_line'][1], $parsed); - - return $parsed; - } - - public function parseResponse($message) - { - if (!$message) { - return false; - } - - $parts = $this->parseMessage($message); - list($protocol, $version) = explode('/', trim($parts['start_line'][0])); - - return array( - 'protocol' => $protocol, - 'version' => $version, - 'code' => $parts['start_line'][1], - 'reason_phrase' => isset($parts['start_line'][2]) ? $parts['start_line'][2] : '', - 'headers' => $parts['headers'], - 'body' => $parts['body'] - ); - } - - /** - * Parse a message into parts - * - * @param string $message Message to parse - * - * @return array - */ - protected function parseMessage($message) - { - $startLine = null; - $headers = array(); - $body = ''; - - // Iterate over each line in the message, accounting for line endings - $lines = preg_split('/(\\r?\\n)/', $message, -1, PREG_SPLIT_DELIM_CAPTURE); - for ($i = 0, $totalLines = count($lines); $i < $totalLines; $i += 2) { - - $line = $lines[$i]; - - // If two line breaks were encountered, then this is the end of body - if (empty($line)) { - if ($i < $totalLines - 1) { - $body = implode('', array_slice($lines, $i + 2)); - } - break; - } - - // Parse message headers - if (!$startLine) { - $startLine = explode(' ', $line, 3); - } elseif (strpos($line, ':')) { - $parts = explode(':', $line, 2); - $key = trim($parts[0]); - $value = isset($parts[1]) ? trim($parts[1]) : ''; - if (!isset($headers[$key])) { - $headers[$key] = $value; - } elseif (!is_array($headers[$key])) { - $headers[$key] = array($headers[$key], $value); - } else { - $headers[$key][] = $value; - } - } - } - - return array( - 'start_line' => $startLine, - 'headers' => $headers, - 'body' => $body - ); - } -} diff --git a/core/vendor/guzzle/parser/Guzzle/Parser/Message/MessageParserInterface.php b/core/vendor/guzzle/parser/Guzzle/Parser/Message/MessageParserInterface.php deleted file mode 100644 index cc448088dbd..00000000000 --- a/core/vendor/guzzle/parser/Guzzle/Parser/Message/MessageParserInterface.php +++ /dev/null @@ -1,27 +0,0 @@ - $parts->requestMethod, - 'protocol' => 'HTTP', - 'version' => number_format($parts->httpVersion, 1), - 'headers' => $parts->headers, - 'body' => $parts->body - ); - - $parsed['request_url'] = $this->getUrlPartsFromMessage($parts->requestUrl, $parsed); - - return $parsed; - } - - public function parseResponse($message) - { - if (!$message) { - return false; - } - - $parts = http_parse_message($message); - - return array( - 'protocol' => 'HTTP', - 'version' => number_format($parts->httpVersion, 1), - 'code' => $parts->responseCode, - 'reason_phrase' => $parts->responseStatus, - 'headers' => $parts->headers, - 'body' => $parts->body - ); - } -} diff --git a/core/vendor/guzzle/parser/Guzzle/Parser/ParserRegistry.php b/core/vendor/guzzle/parser/Guzzle/Parser/ParserRegistry.php deleted file mode 100644 index f8386831c22..00000000000 --- a/core/vendor/guzzle/parser/Guzzle/Parser/ParserRegistry.php +++ /dev/null @@ -1,75 +0,0 @@ - 'Guzzle\\Parser\\Message\\MessageParser', - 'cookie' => 'Guzzle\\Parser\\Cookie\\CookieParser', - 'url' => 'Guzzle\\Parser\\Url\\UrlParser', - 'uri_template' => 'Guzzle\\Parser\\UriTemplate\\UriTemplate', - ); - - /** - * @return self - * @codeCoverageIgnore - */ - public static function getInstance() - { - if (!self::$instance) { - self::$instance = new static; - } - - return self::$instance; - } - - public function __construct() - { - // Use the PECL URI template parser if available - if (extension_loaded('uri_template')) { - $this->mapping['uri_template'] = 'Guzzle\\Parser\\UriTemplate\\PeclUriTemplate'; - } - } - - /** - * Get a parser by name from an instance - * - * @param string $name Name of the parser to retrieve - * - * @return mixed|null - */ - public function getParser($name) - { - if (!isset($this->instances[$name])) { - if (!isset($this->mapping[$name])) { - return null; - } - $class = $this->mapping[$name]; - $this->instances[$name] = new $class(); - } - - return $this->instances[$name]; - } - - /** - * Register a custom parser by name with the register - * - * @param string $name Name or handle of the parser to register - * @param mixed $parser Instantiated parser to register - */ - public function registerParser($name, $parser) - { - $this->instances[$name] = $parser; - } -} diff --git a/core/vendor/guzzle/parser/Guzzle/Parser/UriTemplate/PeclUriTemplate.php b/core/vendor/guzzle/parser/Guzzle/Parser/UriTemplate/PeclUriTemplate.php deleted file mode 100644 index b0764e8377c..00000000000 --- a/core/vendor/guzzle/parser/Guzzle/Parser/UriTemplate/PeclUriTemplate.php +++ /dev/null @@ -1,26 +0,0 @@ -utf8 = $utf8; - } - - public function parseUrl($url) - { - Version::warn(__CLASS__ . ' is deprecated. Just use parse_url()'); - - static $defaults = array('scheme' => null, 'host' => null, 'path' => null, 'port' => null, 'query' => null, - 'user' => null, 'pass' => null, 'fragment' => null); - - $parts = parse_url($url); - - // Need to handle query parsing specially for UTF-8 requirements - if ($this->utf8 && isset($parts['query'])) { - $queryPos = strpos($url, '?'); - if (isset($parts['fragment'])) { - $parts['query'] = substr($url, $queryPos + 1, strpos($url, '#') - $queryPos - 1); - } else { - $parts['query'] = substr($url, $queryPos + 1); - } - } - - return $parts + $defaults; - } -} diff --git a/core/vendor/guzzle/parser/Guzzle/Parser/Url/UrlParserInterface.php b/core/vendor/guzzle/parser/Guzzle/Parser/Url/UrlParserInterface.php deleted file mode 100644 index 89ac4b30771..00000000000 --- a/core/vendor/guzzle/parser/Guzzle/Parser/Url/UrlParserInterface.php +++ /dev/null @@ -1,19 +0,0 @@ -=5.3.2" - }, - "autoload": { - "psr-0": { "Guzzle\\Parser": "" } - }, - "target-dir": "Guzzle/Parser", - "extra": { - "branch-alias": { - "dev-master": "3.7-dev" - } - } -} diff --git a/core/vendor/guzzle/stream/Guzzle/Stream/PhpStreamRequestFactory.php b/core/vendor/guzzle/stream/Guzzle/Stream/PhpStreamRequestFactory.php deleted file mode 100644 index 91461c6498e..00000000000 --- a/core/vendor/guzzle/stream/Guzzle/Stream/PhpStreamRequestFactory.php +++ /dev/null @@ -1,270 +0,0 @@ -contextOptions = stream_context_get_options($context); - $this->context = $context; - } elseif (is_array($context) || !$context) { - $this->contextOptions = $context; - $this->createContext($params); - } elseif ($context) { - throw new InvalidArgumentException('$context must be an array or resource'); - } - - // Dispatch the before send event - $request->dispatch('request.before_send', array( - 'request' => $request, - 'context' => $this->context, - 'context_options' => $this->contextOptions - )); - - $this->setUrl($request); - $this->addDefaultContextOptions($request); - $this->addSslOptions($request); - $this->addBodyOptions($request); - $this->addProxyOptions($request); - - // Create the file handle but silence errors - return $this->createStream($params) - ->setCustomData('request', $request) - ->setCustomData('response_headers', $this->getLastResponseHeaders()); - } - - /** - * Set an option on the context and the internal options array - * - * @param string $wrapper Stream wrapper name of http - * @param string $name Context name - * @param mixed $value Context value - * @param bool $overwrite Set to true to overwrite an existing value - */ - protected function setContextValue($wrapper, $name, $value, $overwrite = false) - { - if (!isset($this->contextOptions[$wrapper])) { - $this->contextOptions[$wrapper] = array($name => $value); - } elseif (!$overwrite && isset($this->contextOptions[$wrapper][$name])) { - return; - } - $this->contextOptions[$wrapper][$name] = $value; - stream_context_set_option($this->context, $wrapper, $name, $value); - } - - /** - * Create a stream context - * - * @param array $params Parameter array - */ - protected function createContext(array $params) - { - $options = $this->contextOptions; - $this->context = $this->createResource(function () use ($params, $options) { - return stream_context_create($options, $params); - }); - } - - /** - * Get the last response headers received by the HTTP request - * - * @return array - */ - public function getLastResponseHeaders() - { - return $this->lastResponseHeaders; - } - - /** - * Adds the default context options to the stream context options - * - * @param RequestInterface $request Request - */ - protected function addDefaultContextOptions(RequestInterface $request) - { - $this->setContextValue('http', 'method', $request->getMethod()); - $this->setContextValue('http', 'header', $request->getHeaderLines()); - // Force 1.0 for now until PHP fully support chunked transfer-encoding decoding - $this->setContextValue('http', 'protocol_version', '1.0'); - $this->setContextValue('http', 'ignore_errors', true); - } - - /** - * Set the URL to use with the factory - * - * @param RequestInterface $request Request that owns the URL - */ - protected function setUrl(RequestInterface $request) - { - $this->url = $request->getUrl(true); - - // Check for basic Auth username - if ($request->getUsername()) { - $this->url->setUsername($request->getUsername()); - } - - // Check for basic Auth password - if ($request->getPassword()) { - $this->url->setPassword($request->getPassword()); - } - } - - /** - * Add SSL options to the stream context - * - * @param RequestInterface $request Request - */ - protected function addSslOptions(RequestInterface $request) - { - if ($verify = $request->getCurlOptions()->get(CURLOPT_SSL_VERIFYPEER)) { - $this->setContextValue('ssl', 'verify_peer', true, true); - if ($cafile = $request->getCurlOptions()->get(CURLOPT_CAINFO)) { - $this->setContextValue('ssl', 'cafile', $cafile, true); - } - } else { - $this->setContextValue('ssl', 'verify_peer', false, true); - } - } - - /** - * Add body (content) specific options to the context options - * - * @param RequestInterface $request - */ - protected function addBodyOptions(RequestInterface $request) - { - // Add the content for the request if needed - if (!($request instanceof EntityEnclosingRequestInterface)) { - return; - } - - if (count($request->getPostFields())) { - $this->setContextValue('http', 'content', (string) $request->getPostFields(), true); - } elseif ($request->getBody()) { - $this->setContextValue('http', 'content', (string) $request->getBody(), true); - } - - // Always ensure a content-length header is sent - if (isset($this->contextOptions['http']['content'])) { - $headers = isset($this->contextOptions['http']['header']) ? $this->contextOptions['http']['header'] : array(); - $headers[] = 'Content-Length: ' . strlen($this->contextOptions['http']['content']); - $this->setContextValue('http', 'header', $headers, true); - } - } - - /** - * Add proxy parameters to the context if needed - * - * @param RequestInterface $request Request - */ - protected function addProxyOptions(RequestInterface $request) - { - if ($proxy = $request->getCurlOptions()->get(CURLOPT_PROXY)) { - $this->setContextValue('http', 'proxy', $proxy); - } - } - - /** - * Create the stream for the request with the context options - * - * @param array $params Parameters of the stream - * - * @return StreamInterface - */ - protected function createStream(array $params) - { - $http_response_header = null; - $url = $this->url; - $context = $this->context; - $fp = $this->createResource(function () use ($context, $url, &$http_response_header) { - return fopen((string) $url, 'r', false, $context); - }); - - // Determine the class to instantiate - $className = isset($params['stream_class']) ? $params['stream_class'] : __NAMESPACE__ . '\\Stream'; - - /** @var $stream StreamInterface */ - $stream = new $className($fp); - - // Track the response headers of the request - if (isset($http_response_header)) { - $this->lastResponseHeaders = $http_response_header; - $this->processResponseHeaders($stream); - } - - return $stream; - } - - /** - * Process response headers - * - * @param StreamInterface $stream - */ - protected function processResponseHeaders(StreamInterface $stream) - { - // Set the size on the stream if it was returned in the response - foreach ($this->lastResponseHeaders as $header) { - if (($pos = stripos($header, 'Content-Length:')) === 0) { - $stream->setSize(trim(substr($header, 15))); - } - } - } - - /** - * Create a resource and check to ensure it was created successfully - * - * @param callable $callback Closure to invoke that must return a valid resource - * - * @return resource - * @throws RuntimeException on error - */ - protected function createResource($callback) - { - // Turn off error reporting while we try to initiate the request - $level = error_reporting(0); - $resource = call_user_func($callback); - error_reporting($level); - - // If the resource could not be created, then grab the last error and throw an exception - if (false === $resource) { - $message = 'Error creating resource. '; - foreach (error_get_last() as $key => $value) { - $message .= "[{$key}] {$value} "; - } - throw new RuntimeException(trim($message)); - } - - return $resource; - } -} diff --git a/core/vendor/guzzle/stream/Guzzle/Stream/Stream.php b/core/vendor/guzzle/stream/Guzzle/Stream/Stream.php deleted file mode 100644 index 299f3b39a66..00000000000 --- a/core/vendor/guzzle/stream/Guzzle/Stream/Stream.php +++ /dev/null @@ -1,293 +0,0 @@ - array( - 'r' => true, 'w+' => true, 'r+' => true, 'x+' => true, 'c+' => true, - 'rb' => true, 'w+b' => true, 'r+b' => true, 'x+b' => true, 'c+b' => true, - 'rt' => true, 'w+t' => true, 'r+t' => true, 'x+t' => true, 'c+t' => true, 'a+' => true - ), - 'write' => array( - 'w' => true, 'w+' => true, 'rw' => true, 'r+' => true, 'x+' => true, 'c+' => true, - 'wb' => true, 'w+b' => true, 'r+b' => true, 'x+b' => true, 'c+b' => true, - 'w+t' => true, 'r+t' => true, 'x+t' => true, 'c+t' => true, 'a' => true, 'a+' => true - ) - ); - - /** - * @param resource $stream Stream resource to wrap - * @param int $size Size of the stream in bytes. Only pass if the size cannot be obtained from the stream. - * - * @throws InvalidArgumentException if the stream is not a stream resource - */ - public function __construct($stream, $size = null) - { - $this->setStream($stream, $size); - } - - /** - * Closes the stream when the helper is destructed - */ - public function __destruct() - { - $this->close(); - } - - public function __toString() - { - if (!$this->isReadable() || (!$this->isSeekable() && $this->isConsumed())) { - return ''; - } - - $originalPos = $this->ftell(); - $body = stream_get_contents($this->stream, -1, 0); - $this->seek($originalPos); - - return $body; - } - - public function close() - { - if (is_resource($this->stream)) { - fclose($this->stream); - } - $this->cache[self::IS_READABLE] = false; - $this->cache[self::IS_WRITABLE] = false; - } - - /** - * Calculate a hash of a Stream - * - * @param StreamInterface $stream Stream to calculate the hash for - * @param string $algo Hash algorithm (e.g. md5, crc32, etc) - * @param bool $rawOutput Whether or not to use raw output - * - * @return bool|string Returns false on failure or a hash string on success - */ - public static function getHash(StreamInterface $stream, $algo, $rawOutput = false) - { - $pos = $stream->ftell(); - if (!$stream->seek(0)) { - return false; - } - - $ctx = hash_init($algo); - while ($data = $stream->read(8192)) { - hash_update($ctx, $data); - } - - $out = hash_final($ctx, (bool) $rawOutput); - $stream->seek($pos); - - return $out; - } - - public function getMetaData($key = null) - { - $meta = stream_get_meta_data($this->stream); - - return !$key ? $meta : (array_key_exists($key, $meta) ? $meta[$key] : null); - } - - public function getStream() - { - return $this->stream; - } - - public function setStream($stream, $size = null) - { - if (!is_resource($stream)) { - throw new InvalidArgumentException('Stream must be a resource'); - } - - $this->size = $size; - $this->stream = $stream; - $this->rebuildCache(); - - return $this; - } - - public function detachStream() - { - $this->stream = null; - - return $this; - } - - public function getWrapper() - { - return $this->cache[self::WRAPPER_TYPE]; - } - - public function getWrapperData() - { - return $this->getMetaData('wrapper_data') ?: array(); - } - - public function getStreamType() - { - return $this->cache[self::STREAM_TYPE]; - } - - public function getUri() - { - return $this->cache['uri']; - } - - public function getSize() - { - if ($this->size !== null) { - return $this->size; - } - - // If the stream is a file based stream and local, then use fstat - clearstatcache(true, $this->cache['uri']); - $stats = fstat($this->stream); - if (isset($stats['size'])) { - $this->size = $stats['size']; - return $this->size; - } elseif ($this->cache[self::IS_READABLE] && $this->cache[self::SEEKABLE]) { - // Only get the size based on the content if the the stream is readable and seekable - $pos = $this->ftell(); - $this->size = strlen((string) $this); - $this->seek($pos); - return $this->size; - } - - return false; - } - - public function isReadable() - { - return $this->cache[self::IS_READABLE]; - } - - public function isRepeatable() - { - return $this->cache[self::IS_READABLE] && $this->cache[self::SEEKABLE]; - } - - public function isWritable() - { - return $this->cache[self::IS_WRITABLE]; - } - - public function isConsumed() - { - return feof($this->stream); - } - - public function feof() - { - return $this->isConsumed(); - } - - public function isLocal() - { - return $this->cache[self::IS_LOCAL]; - } - - public function isSeekable() - { - return $this->cache[self::SEEKABLE]; - } - - public function setSize($size) - { - $this->size = $size; - - return $this; - } - - public function seek($offset, $whence = SEEK_SET) - { - return $this->cache[self::SEEKABLE] ? fseek($this->stream, $offset, $whence) === 0 : false; - } - - public function read($length) - { - return $this->cache[self::IS_READABLE] ? fread($this->stream, $length) : false; - } - - public function write($string) - { - if (!$this->cache[self::IS_WRITABLE]) { - return 0; - } - - // We can't know the size after writing anything - $this->size = null; - - return fwrite($this->stream, $string); - } - - public function ftell() - { - return ftell($this->stream); - } - - public function rewind() - { - return $this->seek(0); - } - - public function readLine($maxLength = null) - { - if (!$this->cache[self::IS_READABLE]) { - return false; - } else { - return $maxLength ? fgets($this->getStream(), $maxLength) : fgets($this->getStream()); - } - } - - public function setCustomData($key, $value) - { - $this->customData[$key] = $value; - - return $this; - } - - public function getCustomData($key) - { - return isset($this->customData[$key]) ? $this->customData[$key] : null; - } - - /** - * Reprocess stream metadata - */ - protected function rebuildCache() - { - $this->cache = stream_get_meta_data($this->stream); - $this->cache[self::IS_LOCAL] = stream_is_local($this->stream); - $this->cache[self::IS_READABLE] = isset(self::$readWriteHash['read'][$this->cache['mode']]); - $this->cache[self::IS_WRITABLE] = isset(self::$readWriteHash['write'][$this->cache['mode']]); - } -} diff --git a/core/vendor/guzzle/stream/Guzzle/Stream/StreamInterface.php b/core/vendor/guzzle/stream/Guzzle/Stream/StreamInterface.php deleted file mode 100644 index 6d7dc37613c..00000000000 --- a/core/vendor/guzzle/stream/Guzzle/Stream/StreamInterface.php +++ /dev/null @@ -1,218 +0,0 @@ -=5.3.2", - "guzzle/common": "self.version" - }, - "suggest": { - "guzzle/http": "To convert Guzzle request objects to PHP streams" - }, - "autoload": { - "psr-0": { "Guzzle\\Stream": "" } - }, - "target-dir": "Guzzle/Stream", - "extra": { - "branch-alias": { - "dev-master": "3.7-dev" - } - } -} diff --git a/core/vendor/guzzlehttp/guzzle/.gitignore b/core/vendor/guzzlehttp/guzzle/.gitignore new file mode 100644 index 00000000000..f344b89b919 --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/.gitignore @@ -0,0 +1,11 @@ +phpunit.xml +composer.phar +composer.lock +composer-test.lock +vendor/ +build/ +artifacts/ +docs/_build +docs/*.pyc +.idea +.DS_STORE diff --git a/core/vendor/guzzlehttp/guzzle/.travis.yml b/core/vendor/guzzlehttp/guzzle/.travis.yml new file mode 100644 index 00000000000..1e683366eb9 --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/.travis.yml @@ -0,0 +1,22 @@ +language: php + +php: + - 5.4 + - 5.5 + - 5.6 + - hhvm + +before_script: + - curl --version + - pear config-set php_ini ~/.phpenv/versions/`php -r 'echo phpversion();'`/etc/php.ini || echo 'Error modifying PEAR' + - pecl install uri_template || echo 'Error installing uri_template' + - composer install + - ~/.nvm/nvm.sh install v0.6.14 + - ~/.nvm/nvm.sh run v0.6.14 + +script: make test + +matrix: + allow_failures: + - php: hhvm + fast_finish: true diff --git a/core/vendor/guzzlehttp/guzzle/CHANGELOG.md b/core/vendor/guzzlehttp/guzzle/CHANGELOG.md new file mode 100644 index 00000000000..d2fe5a49b7e --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/CHANGELOG.md @@ -0,0 +1,805 @@ +CHANGELOG +========= + +4.0.0 (2014-03-29) +------------------ + +* For more information on the 4.0 transition, see: + http://mtdowling.com/blog/2014/03/15/guzzle-4-rc/ +* For information on changes and upgrading, see: + https://github.com/guzzle/guzzle/blob/master/UPGRADING.md#3x-to-40 +* Added `GuzzleHttp\batch()` as a convenience function for sending requests in + parallel without needing to write asynchronous code. +* Restructured how events are added to `GuzzleHttp\ClientInterface::sendAll()`. + You can now pass a callable or an array of associative arrays where each + associative array contains the "fn", "priority", and "once" keys. + +4.0.0.rc-2 (2014-03-25) +----------------------- + +* Removed `getConfig()` and `setConfig()` from clients to avoid confusion + around whether things like base_url, message_factory, etc should be able to + be retrieved or modified. +* Added `getDefaultOption()` and `setDefaultOption()` to ClientInterface +* functions.php functions were renamed using snake_case to match PHP idioms +* Added support for `HTTP_PROXY`, `HTTPS_PROXY`, and + `GUZZLE_CURL_SELECT_TIMEOUT` environment variables +* Added the ability to specify custom `sendAll()` event priorities +* Added the ability to specify custom stream context options to the stream + adapter. +* Added a functions.php function for `get_path()` and `set_path()` +* CurlAdapter and MultiAdapter now use a callable to generate curl resources +* MockAdapter now properly reads a body and emits a `headers` event +* Updated Url class to check if a scheme and host are set before adding ":" + and "//". This allows empty Url (e.g., "") to be serialized as "". +* Parsing invalid XML no longer emits warnings +* Curl classes now properly throw AdapterExceptions +* Various performance optimizations +* Streams are created with the faster `Stream\create()` function +* Marked deprecation_proxy() as internal +* Test server is now a collection of static methods on a class + +4.0.0-rc.1 (2014-03-15) +----------------------- + +* See https://github.com/guzzle/guzzle/blob/master/UPGRADING.md#3x-to-40 + +3.8.1 (2014-01-28) +------------------ + +* Bug: Always using GET requests when redirecting from a 303 response +* Bug: CURLOPT_SSL_VERIFYHOST is now correctly set to false when setting `$certificateAuthority` to false in + `Guzzle\Http\ClientInterface::setSslVerification()` +* Bug: RedirectPlugin now uses strict RFC 3986 compliance when combining a base URL with a relative URL +* Bug: The body of a request can now be set to `"0"` +* Sending PHP stream requests no longer forces `HTTP/1.0` +* Adding more information to ExceptionCollection exceptions so that users have more context, including a stack trace of + each sub-exception +* Updated the `$ref` attribute in service descriptions to merge over any existing parameters of a schema (rather than + clobbering everything). +* Merging URLs will now use the query string object from the relative URL (thus allowing custom query aggregators) +* Query strings are now parsed in a way that they do no convert empty keys with no value to have a dangling `=`. + For example `foo&bar=baz` is now correctly parsed and recognized as `foo&bar=baz` rather than `foo=&bar=baz`. +* Now properly escaping the regular expression delimiter when matching Cookie domains. +* Network access is now disabled when loading XML documents + +3.8.0 (2013-12-05) +------------------ + +* Added the ability to define a POST name for a file +* JSON response parsing now properly walks additionalProperties +* cURL error code 18 is now retried automatically in the BackoffPlugin +* Fixed a cURL error when URLs contain fragments +* Fixed an issue in the BackoffPlugin retry event where it was trying to access all exceptions as if they were + CurlExceptions +* CURLOPT_PROGRESS function fix for PHP 5.5 (69fcc1e) +* Added the ability for Guzzle to work with older versions of cURL that do not support `CURLOPT_TIMEOUT_MS` +* Fixed a bug that was encountered when parsing empty header parameters +* UriTemplate now has a `setRegex()` method to match the docs +* The `debug` request parameter now checks if it is truthy rather than if it exists +* Setting the `debug` request parameter to true shows verbose cURL output instead of using the LogPlugin +* Added the ability to combine URLs using strict RFC 3986 compliance +* Command objects can now return the validation errors encountered by the command +* Various fixes to cache revalidation (#437 and 29797e5) +* Various fixes to the AsyncPlugin +* Cleaned up build scripts + +3.7.4 (2013-10-02) +------------------ + +* Bug fix: 0 is now an allowed value in a description parameter that has a default value (#430) +* Bug fix: SchemaFormatter now returns an integer when formatting to a Unix timestamp + (see https://github.com/aws/aws-sdk-php/issues/147) +* Bug fix: Cleaned up and fixed URL dot segment removal to properly resolve internal dots +* Minimum PHP version is now properly specified as 5.3.3 (up from 5.3.2) (#420) +* Updated the bundled cacert.pem (#419) +* OauthPlugin now supports adding authentication to headers or query string (#425) + +3.7.3 (2013-09-08) +------------------ + +* Added the ability to get the exception associated with a request/command when using `MultiTransferException` and + `CommandTransferException`. +* Setting `additionalParameters` of a response to false is now honored when parsing responses with a service description +* Schemas are only injected into response models when explicitly configured. +* No longer guessing Content-Type based on the path of a request. Content-Type is now only guessed based on the path of + an EntityBody. +* Bug fix: ChunkedIterator can now properly chunk a \Traversable as well as an \Iterator. +* Bug fix: FilterIterator now relies on `\Iterator` instead of `\Traversable`. +* Bug fix: Gracefully handling malformed responses in RequestMediator::writeResponseBody() +* Bug fix: Replaced call to canCache with canCacheRequest in the CallbackCanCacheStrategy of the CachePlugin +* Bug fix: Visiting XML attributes first before visting XML children when serializing requests +* Bug fix: Properly parsing headers that contain commas contained in quotes +* Bug fix: mimetype guessing based on a filename is now case-insensitive + +3.7.2 (2013-08-02) +------------------ + +* Bug fix: Properly URL encoding paths when using the PHP-only version of the UriTemplate expander + See https://github.com/guzzle/guzzle/issues/371 +* Bug fix: Cookie domains are now matched correctly according to RFC 6265 + See https://github.com/guzzle/guzzle/issues/377 +* Bug fix: GET parameters are now used when calculating an OAuth signature +* Bug fix: Fixed an issue with cache revalidation where the If-None-Match header was being double quoted +* `Guzzle\Common\AbstractHasDispatcher::dispatch()` now returns the event that was dispatched +* `Guzzle\Http\QueryString::factory()` now guesses the most appropriate query aggregator to used based on the input. + See https://github.com/guzzle/guzzle/issues/379 +* Added a way to add custom domain objects to service description parsing using the `operation.parse_class` event. See + https://github.com/guzzle/guzzle/pull/380 +* cURL multi cleanup and optimizations + +3.7.1 (2013-07-05) +------------------ + +* Bug fix: Setting default options on a client now works +* Bug fix: Setting options on HEAD requests now works. See #352 +* Bug fix: Moving stream factory before send event to before building the stream. See #353 +* Bug fix: Cookies no longer match on IP addresses per RFC 6265 +* Bug fix: Correctly parsing header parameters that are in `<>` and quotes +* Added `cert` and `ssl_key` as request options +* `Host` header can now diverge from the host part of a URL if the header is set manually +* `Guzzle\Service\Command\LocationVisitor\Request\XmlVisitor` was rewritten to change from using SimpleXML to XMLWriter +* OAuth parameters are only added via the plugin if they aren't already set +* Exceptions are now thrown when a URL cannot be parsed +* Returning `false` if `Guzzle\Http\EntityBody::getContentMd5()` fails +* Not setting a `Content-MD5` on a command if calculating the Content-MD5 fails via the CommandContentMd5Plugin + +3.7.0 (2013-06-10) +------------------ + +* See UPGRADING.md for more information on how to upgrade. +* Requests now support the ability to specify an array of $options when creating a request to more easily modify a + request. You can pass a 'request.options' configuration setting to a client to apply default request options to + every request created by a client (e.g. default query string variables, headers, curl options, etc). +* Added a static facade class that allows you to use Guzzle with static methods and mount the class to `\Guzzle`. + See `Guzzle\Http\StaticClient::mount`. +* Added `command.request_options` to `Guzzle\Service\Command\AbstractCommand` to pass request options to requests + created by a command (e.g. custom headers, query string variables, timeout settings, etc). +* Stream size in `Guzzle\Stream\PhpStreamRequestFactory` will now be set if Content-Length is returned in the + headers of a response +* Added `Guzzle\Common\Collection::setPath($path, $value)` to set a value into an array using a nested key + (e.g. `$collection->setPath('foo/baz/bar', 'test'); echo $collection['foo']['bar']['bar'];`) +* ServiceBuilders now support storing and retrieving arbitrary data +* CachePlugin can now purge all resources for a given URI +* CachePlugin can automatically purge matching cached items when a non-idempotent request is sent to a resource +* CachePlugin now uses the Vary header to determine if a resource is a cache hit +* `Guzzle\Http\Message\Response` now implements `\Serializable` +* Added `Guzzle\Cache\CacheAdapterFactory::fromCache()` to more easily create cache adapters +* `Guzzle\Service\ClientInterface::execute()` now accepts an array, single command, or Traversable +* Fixed a bug in `Guzzle\Http\Message\Header\Link::addLink()` +* Better handling of calculating the size of a stream in `Guzzle\Stream\Stream` using fstat() and caching the size +* `Guzzle\Common\Exception\ExceptionCollection` now creates a more readable exception message +* Fixing BC break: Added back the MonologLogAdapter implementation rather than extending from PsrLog so that older + Symfony users can still use the old version of Monolog. +* Fixing BC break: Added the implementation back in for `Guzzle\Http\Message\AbstractMessage::getTokenizedHeader()`. + Now triggering an E_USER_DEPRECATED warning when used. Use `$message->getHeader()->parseParams()`. +* Several performance improvements to `Guzzle\Common\Collection` +* Added an `$options` argument to the end of the following methods of `Guzzle\Http\ClientInterface`: + createRequest, head, delete, put, patch, post, options, prepareRequest +* Added an `$options` argument to the end of `Guzzle\Http\Message\Request\RequestFactoryInterface::createRequest()` +* Added an `applyOptions()` method to `Guzzle\Http\Message\Request\RequestFactoryInterface` +* Changed `Guzzle\Http\ClientInterface::get($uri = null, $headers = null, $body = null)` to + `Guzzle\Http\ClientInterface::get($uri = null, $headers = null, $options = array())`. You can still pass in a + resource, string, or EntityBody into the $options parameter to specify the download location of the response. +* Changed `Guzzle\Common\Collection::__construct($data)` to no longer accepts a null value for `$data` but a + default `array()` +* Added `Guzzle\Stream\StreamInterface::isRepeatable` +* Removed `Guzzle\Http\ClientInterface::setDefaultHeaders(). Use + $client->getConfig()->setPath('request.options/headers/{header_name}', 'value')`. or + $client->getConfig()->setPath('request.options/headers', array('header_name' => 'value'))`. +* Removed `Guzzle\Http\ClientInterface::getDefaultHeaders(). Use $client->getConfig()->getPath('request.options/headers')`. +* Removed `Guzzle\Http\ClientInterface::expandTemplate()` +* Removed `Guzzle\Http\ClientInterface::setRequestFactory()` +* Removed `Guzzle\Http\ClientInterface::getCurlMulti()` +* Removed `Guzzle\Http\Message\RequestInterface::canCache` +* Removed `Guzzle\Http\Message\RequestInterface::setIsRedirect` +* Removed `Guzzle\Http\Message\RequestInterface::isRedirect` +* Made `Guzzle\Http\Client::expandTemplate` and `getUriTemplate` protected methods. +* You can now enable E_USER_DEPRECATED warnings to see if you are using a deprecated method by setting + `Guzzle\Common\Version::$emitWarnings` to true. +* Marked `Guzzle\Http\Message\Request::isResponseBodyRepeatable()` as deprecated. Use + `$request->getResponseBody()->isRepeatable()` instead. +* Marked `Guzzle\Http\Message\Request::canCache()` as deprecated. Use + `Guzzle\Plugin\Cache\DefaultCanCacheStrategy->canCacheRequest()` instead. +* Marked `Guzzle\Http\Message\Request::canCache()` as deprecated. Use + `Guzzle\Plugin\Cache\DefaultCanCacheStrategy->canCacheRequest()` instead. +* Marked `Guzzle\Http\Message\Request::setIsRedirect()` as deprecated. Use the HistoryPlugin instead. +* Marked `Guzzle\Http\Message\Request::isRedirect()` as deprecated. Use the HistoryPlugin instead. +* Marked `Guzzle\Cache\CacheAdapterFactory::factory()` as deprecated +* Marked 'command.headers', 'command.response_body' and 'command.on_complete' as deprecated for AbstractCommand. + These will work through Guzzle 4.0 +* Marked 'request.params' for `Guzzle\Http\Client` as deprecated. Use [request.options][params]. +* Marked `Guzzle\Service\Client::enableMagicMethods()` as deprecated. Magic methods can no longer be disabled on a Guzzle\Service\Client. +* Marked `Guzzle\Service\Client::getDefaultHeaders()` as deprecated. Use $client->getConfig()->getPath('request.options/headers')`. +* Marked `Guzzle\Service\Client::setDefaultHeaders()` as deprecated. Use $client->getConfig()->setPath('request.options/headers/{header_name}', 'value')`. +* Marked `Guzzle\Parser\Url\UrlParser` as deprecated. Just use PHP's `parse_url()` and percent encode your UTF-8. +* Marked `Guzzle\Common\Collection::inject()` as deprecated. +* Marked `Guzzle\Plugin\CurlAuth\CurlAuthPlugin` as deprecated. Use `$client->getConfig()->setPath('request.options/auth', array('user', 'pass', 'Basic|Digest');` +* CacheKeyProviderInterface and DefaultCacheKeyProvider are no longer used. All of this logic is handled in a + CacheStorageInterface. These two objects and interface will be removed in a future version. +* Always setting X-cache headers on cached responses +* Default cache TTLs are now handled by the CacheStorageInterface of a CachePlugin +* `CacheStorageInterface::cache($key, Response $response, $ttl = null)` has changed to `cache(RequestInterface + $request, Response $response);` +* `CacheStorageInterface::fetch($key)` has changed to `fetch(RequestInterface $request);` +* `CacheStorageInterface::delete($key)` has changed to `delete(RequestInterface $request);` +* Added `CacheStorageInterface::purge($url)` +* `DefaultRevalidation::__construct(CacheKeyProviderInterface $cacheKey, CacheStorageInterface $cache, CachePlugin + $plugin)` has changed to `DefaultRevalidation::__construct(CacheStorageInterface $cache, + CanCacheStrategyInterface $canCache = null)` +* Added `RevalidationInterface::shouldRevalidate(RequestInterface $request, Response $response)` + +3.6.0 (2013-05-29) +------------------ + +* ServiceDescription now implements ToArrayInterface +* Added command.hidden_params to blacklist certain headers from being treated as additionalParameters +* Guzzle can now correctly parse incomplete URLs +* Mixed casing of headers are now forced to be a single consistent casing across all values for that header. +* Messages internally use a HeaderCollection object to delegate handling case-insensitive header resolution +* Removed the whole changedHeader() function system of messages because all header changes now go through addHeader(). +* Specific header implementations can be created for complex headers. When a message creates a header, it uses a + HeaderFactory which can map specific headers to specific header classes. There is now a Link header and + CacheControl header implementation. +* Removed from interface: Guzzle\Http\ClientInterface::setUriTemplate +* Removed from interface: Guzzle\Http\ClientInterface::setCurlMulti() +* Removed Guzzle\Http\Message\Request::receivedRequestHeader() and implemented this functionality in + Guzzle\Http\Curl\RequestMediator +* Removed the optional $asString parameter from MessageInterface::getHeader(). Just cast the header to a string. +* Removed the optional $tryChunkedTransfer option from Guzzle\Http\Message\EntityEnclosingRequestInterface +* Removed the $asObjects argument from Guzzle\Http\Message\MessageInterface::getHeaders() +* Removed Guzzle\Parser\ParserRegister::get(). Use getParser() +* Removed Guzzle\Parser\ParserRegister::set(). Use registerParser(). +* All response header helper functions return a string rather than mixing Header objects and strings inconsistently +* Removed cURL blacklist support. This is no longer necessary now that Expect, Accept, etc are managed by Guzzle + directly via interfaces +* Removed the injecting of a request object onto a response object. The methods to get and set a request still exist + but are a no-op until removed. +* Most classes that used to require a ``Guzzle\Service\Command\CommandInterface` typehint now request a + `Guzzle\Service\Command\ArrayCommandInterface`. +* Added `Guzzle\Http\Message\RequestInterface::startResponse()` to the RequestInterface to handle injecting a response + on a request while the request is still being transferred +* The ability to case-insensitively search for header values +* Guzzle\Http\Message\Header::hasExactHeader +* Guzzle\Http\Message\Header::raw. Use getAll() +* Deprecated cache control specific methods on Guzzle\Http\Message\AbstractMessage. Use the CacheControl header object + instead. +* `Guzzle\Service\Command\CommandInterface` now extends from ToArrayInterface and ArrayAccess +* Added the ability to cast Model objects to a string to view debug information. + +3.5.0 (2013-05-13) +------------------ + +* Bug: Fixed a regression so that request responses are parsed only once per oncomplete event rather than multiple times +* Bug: Better cleanup of one-time events accross the board (when an event is meant to fire once, it will now remove + itself from the EventDispatcher) +* Bug: `Guzzle\Log\MessageFormatter` now properly writes "total_time" and "connect_time" values +* Bug: Cloning an EntityEnclosingRequest now clones the EntityBody too +* Bug: Fixed an undefined index error when parsing nested JSON responses with a sentAs parameter that reference a + non-existent key +* Bug: All __call() method arguments are now required (helps with mocking frameworks) +* Deprecating Response::getRequest() and now using a shallow clone of a request object to remove a circular reference + to help with refcount based garbage collection of resources created by sending a request +* Deprecating ZF1 cache and log adapters. These will be removed in the next major version. +* Deprecating `Response::getPreviousResponse()` (method signature still exists, but it'sdeprecated). Use the + HistoryPlugin for a history. +* Added a `responseBody` alias for the `response_body` location +* Refactored internals to no longer rely on Response::getRequest() +* HistoryPlugin can now be cast to a string +* HistoryPlugin now logs transactions rather than requests and responses to more accurately keep track of the requests + and responses that are sent over the wire +* Added `getEffectiveUrl()` and `getRedirectCount()` to Response objects + +3.4.3 (2013-04-30) +------------------ + +* Bug fix: Fixing bug introduced in 3.4.2 where redirect responses are duplicated on the final redirected response +* Added a check to re-extract the temp cacert bundle from the phar before sending each request + +3.4.2 (2013-04-29) +------------------ + +* Bug fix: Stream objects now work correctly with "a" and "a+" modes +* Bug fix: Removing `Transfer-Encoding: chunked` header when a Content-Length is present +* Bug fix: AsyncPlugin no longer forces HEAD requests +* Bug fix: DateTime timezones are now properly handled when using the service description schema formatter +* Bug fix: CachePlugin now properly handles stale-if-error directives when a request to the origin server fails +* Setting a response on a request will write to the custom request body from the response body if one is specified +* LogPlugin now writes to php://output when STDERR is undefined +* Added the ability to set multiple POST files for the same key in a single call +* application/x-www-form-urlencoded POSTs now use the utf-8 charset by default +* Added the ability to queue CurlExceptions to the MockPlugin +* Cleaned up how manual responses are queued on requests (removed "queued_response" and now using request.before_send) +* Configuration loading now allows remote files + +3.4.1 (2013-04-16) +------------------ + +* Large refactoring to how CurlMulti handles work. There is now a proxy that sits in front of a pool of CurlMulti + handles. This greatly simplifies the implementation, fixes a couple bugs, and provides a small performance boost. +* Exceptions are now properly grouped when sending requests in parallel +* Redirects are now properly aggregated when a multi transaction fails +* Redirects now set the response on the original object even in the event of a failure +* Bug fix: Model names are now properly set even when using $refs +* Added support for PHP 5.5's CurlFile to prevent warnings with the deprecated @ syntax +* Added support for oauth_callback in OAuth signatures +* Added support for oauth_verifier in OAuth signatures +* Added support to attempt to retrieve a command first literally, then ucfirst, the with inflection + +3.4.0 (2013-04-11) +------------------ + +* Bug fix: URLs are now resolved correctly based on http://tools.ietf.org/html/rfc3986#section-5.2. #289 +* Bug fix: Absolute URLs with a path in a service description will now properly override the base URL. #289 +* Bug fix: Parsing a query string with a single PHP array value will now result in an array. #263 +* Bug fix: Better normalization of the User-Agent header to prevent duplicate headers. #264. +* Bug fix: Added `number` type to service descriptions. +* Bug fix: empty parameters are removed from an OAuth signature +* Bug fix: Revalidating a cache entry prefers the Last-Modified over the Date header +* Bug fix: Fixed "array to string" error when validating a union of types in a service description +* Bug fix: Removed code that attempted to determine the size of a stream when data is written to the stream +* Bug fix: Not including an `oauth_token` if the value is null in the OauthPlugin. +* Bug fix: Now correctly aggregating successful requests and failed requests in CurlMulti when a redirect occurs. +* The new default CURLOPT_TIMEOUT setting has been increased to 150 seconds so that Guzzle works on poor connections. +* Added a feature to EntityEnclosingRequest::setBody() that will automatically set the Content-Type of the request if + the Content-Type can be determined based on the entity body or the path of the request. +* Added the ability to overwrite configuration settings in a client when grabbing a throwaway client from a builder. +* Added support for a PSR-3 LogAdapter. +* Added a `command.after_prepare` event +* Added `oauth_callback` parameter to the OauthPlugin +* Added the ability to create a custom stream class when using a stream factory +* Added a CachingEntityBody decorator +* Added support for `additionalParameters` in service descriptions to define how custom parameters are serialized. +* The bundled SSL certificate is now provided in the phar file and extracted when running Guzzle from a phar. +* You can now send any EntityEnclosingRequest with POST fields or POST files and cURL will handle creating bodies +* POST requests using a custom entity body are now treated exactly like PUT requests but with a custom cURL method. This + means that the redirect behavior of POST requests with custom bodies will not be the same as POST requests that use + POST fields or files (the latter is only used when emulating a form POST in the browser). +* Lots of cleanup to CurlHandle::factory and RequestFactory::createRequest + +3.3.1 (2013-03-10) +------------------ + +* Added the ability to create PHP streaming responses from HTTP requests +* Bug fix: Running any filters when parsing response headers with service descriptions +* Bug fix: OauthPlugin fixes to allow for multi-dimensional array signing, and sorting parameters before signing +* Bug fix: Removed the adding of default empty arrays and false Booleans to responses in order to be consistent across + response location visitors. +* Bug fix: Removed the possibility of creating configuration files with circular dependencies +* RequestFactory::create() now uses the key of a POST file when setting the POST file name +* Added xmlAllowEmpty to serialize an XML body even if no XML specific parameters are set + +3.3.0 (2013-03-03) +------------------ + +* A large number of performance optimizations have been made +* Bug fix: Added 'wb' as a valid write mode for streams +* Bug fix: `Guzzle\Http\Message\Response::json()` now allows scalar values to be returned +* Bug fix: Fixed bug in `Guzzle\Http\Message\Response` where wrapping quotes were stripped from `getEtag()` +* BC: Removed `Guzzle\Http\Utils` class +* BC: Setting a service description on a client will no longer modify the client's command factories. +* BC: Emitting IO events from a RequestMediator is now a parameter that must be set in a request's curl options using + the 'emit_io' key. This was previously set under a request's parameters using 'curl.emit_io' +* BC: `Guzzle\Stream\Stream::getWrapper()` and `Guzzle\Stream\Stream::getSteamType()` are no longer converted to + lowercase +* Operation parameter objects are now lazy loaded internally +* Added ErrorResponsePlugin that can throw errors for responses defined in service description operations' errorResponses +* Added support for instantiating responseType=class responseClass classes. Classes must implement + `Guzzle\Service\Command\ResponseClassInterface` +* Added support for additionalProperties for top-level parameters in responseType=model responseClasses. These + additional properties also support locations and can be used to parse JSON responses where the outermost part of the + JSON is an array +* Added support for nested renaming of JSON models (rename sentAs to name) +* CachePlugin + * Added support for stale-if-error so that the CachePlugin can now serve stale content from the cache on error + * Debug headers can now added to cached response in the CachePlugin + +3.2.0 (2013-02-14) +------------------ + +* CurlMulti is no longer reused globally. A new multi object is created per-client. This helps to isolate clients. +* URLs with no path no longer contain a "/" by default +* Guzzle\Http\QueryString does no longer manages the leading "?". This is now handled in Guzzle\Http\Url. +* BadResponseException no longer includes the full request and response message +* Adding setData() to Guzzle\Service\Description\ServiceDescriptionInterface +* Adding getResponseBody() to Guzzle\Http\Message\RequestInterface +* Various updates to classes to use ServiceDescriptionInterface type hints rather than ServiceDescription +* Header values can now be normalized into distinct values when multiple headers are combined with a comma separated list +* xmlEncoding can now be customized for the XML declaration of a XML service description operation +* Guzzle\Http\QueryString now uses Guzzle\Http\QueryAggregator\QueryAggregatorInterface objects to add custom value + aggregation and no longer uses callbacks +* The URL encoding implementation of Guzzle\Http\QueryString can now be customized +* Bug fix: Filters were not always invoked for array service description parameters +* Bug fix: Redirects now use a target response body rather than a temporary response body +* Bug fix: The default exponential backoff BackoffPlugin was not giving when the request threshold was exceeded +* Bug fix: Guzzle now takes the first found value when grabbing Cache-Control directives + +3.1.2 (2013-01-27) +------------------ + +* Refactored how operation responses are parsed. Visitors now include a before() method responsible for parsing the + response body. For example, the XmlVisitor now parses the XML response into an array in the before() method. +* Fixed an issue where cURL would not automatically decompress responses when the Accept-Encoding header was sent +* CURLOPT_SSL_VERIFYHOST is never set to 1 because it is deprecated (see 5e0ff2ef20f839e19d1eeb298f90ba3598784444) +* Fixed a bug where redirect responses were not chained correctly using getPreviousResponse() +* Setting default headers on a client after setting the user-agent will not erase the user-agent setting + +3.1.1 (2013-01-20) +------------------ + +* Adding wildcard support to Guzzle\Common\Collection::getPath() +* Adding alias support to ServiceBuilder configs +* Adding Guzzle\Service\Resource\CompositeResourceIteratorFactory and cleaning up factory interface + +3.1.0 (2013-01-12) +------------------ + +* BC: CurlException now extends from RequestException rather than BadResponseException +* BC: Renamed Guzzle\Plugin\Cache\CanCacheStrategyInterface::canCache() to canCacheRequest() and added CanCacheResponse() +* Added getData to ServiceDescriptionInterface +* Added context array to RequestInterface::setState() +* Bug: Removing hard dependency on the BackoffPlugin from Guzzle\Http +* Bug: Adding required content-type when JSON request visitor adds JSON to a command +* Bug: Fixing the serialization of a service description with custom data +* Made it easier to deal with exceptions thrown when transferring commands or requests in parallel by providing + an array of successful and failed responses +* Moved getPath from Guzzle\Service\Resource\Model to Guzzle\Common\Collection +* Added Guzzle\Http\IoEmittingEntityBody +* Moved command filtration from validators to location visitors +* Added `extends` attributes to service description parameters +* Added getModels to ServiceDescriptionInterface + +3.0.7 (2012-12-19) +------------------ + +* Fixing phar detection when forcing a cacert to system if null or true +* Allowing filename to be passed to `Guzzle\Http\Message\Request::setResponseBody()` +* Cleaning up `Guzzle\Common\Collection::inject` method +* Adding a response_body location to service descriptions + +3.0.6 (2012-12-09) +------------------ + +* CurlMulti performance improvements +* Adding setErrorResponses() to Operation +* composer.json tweaks + +3.0.5 (2012-11-18) +------------------ + +* Bug: Fixing an infinite recursion bug caused from revalidating with the CachePlugin +* Bug: Response body can now be a string containing "0" +* Bug: Using Guzzle inside of a phar uses system by default but now allows for a custom cacert +* Bug: QueryString::fromString now properly parses query string parameters that contain equal signs +* Added support for XML attributes in service description responses +* DefaultRequestSerializer now supports array URI parameter values for URI template expansion +* Added better mimetype guessing to requests and post files + +3.0.4 (2012-11-11) +------------------ + +* Bug: Fixed a bug when adding multiple cookies to a request to use the correct glue value +* Bug: Cookies can now be added that have a name, domain, or value set to "0" +* Bug: Using the system cacert bundle when using the Phar +* Added json and xml methods to Response to make it easier to parse JSON and XML response data into data structures +* Enhanced cookie jar de-duplication +* Added the ability to enable strict cookie jars that throw exceptions when invalid cookies are added +* Added setStream to StreamInterface to actually make it possible to implement custom rewind behavior for entity bodies +* Added the ability to create any sort of hash for a stream rather than just an MD5 hash + +3.0.3 (2012-11-04) +------------------ + +* Implementing redirects in PHP rather than cURL +* Added PECL URI template extension and using as default parser if available +* Bug: Fixed Content-Length parsing of Response factory +* Adding rewind() method to entity bodies and streams. Allows for custom rewinding of non-repeatable streams. +* Adding ToArrayInterface throughout library +* Fixing OauthPlugin to create unique nonce values per request + +3.0.2 (2012-10-25) +------------------ + +* Magic methods are enabled by default on clients +* Magic methods return the result of a command +* Service clients no longer require a base_url option in the factory +* Bug: Fixed an issue with URI templates where null template variables were being expanded + +3.0.1 (2012-10-22) +------------------ + +* Models can now be used like regular collection objects by calling filter, map, etc +* Models no longer require a Parameter structure or initial data in the constructor +* Added a custom AppendIterator to get around a PHP bug with the `\AppendIterator` + +3.0.0 (2012-10-15) +------------------ + +* Rewrote service description format to be based on Swagger + * Now based on JSON schema + * Added nested input structures and nested response models + * Support for JSON and XML input and output models + * Renamed `commands` to `operations` + * Removed dot class notation + * Removed custom types +* Broke the project into smaller top-level namespaces to be more component friendly +* Removed support for XML configs and descriptions. Use arrays or JSON files. +* Removed the Validation component and Inspector +* Moved all cookie code to Guzzle\Plugin\Cookie +* Magic methods on a Guzzle\Service\Client now return the command un-executed. +* Calling getResult() or getResponse() on a command will lazily execute the command if needed. +* Now shipping with cURL's CA certs and using it by default +* Added previousResponse() method to response objects +* No longer sending Accept and Accept-Encoding headers on every request +* Only sending an Expect header by default when a payload is greater than 1MB +* Added/moved client options: + * curl.blacklist to curl.option.blacklist + * Added ssl.certificate_authority +* Added a Guzzle\Iterator component +* Moved plugins from Guzzle\Http\Plugin to Guzzle\Plugin +* Added a more robust backoff retry strategy (replaced the ExponentialBackoffPlugin) +* Added a more robust caching plugin +* Added setBody to response objects +* Updating LogPlugin to use a more flexible MessageFormatter +* Added a completely revamped build process +* Cleaning up Collection class and removing default values from the get method +* Fixed ZF2 cache adapters + +2.8.8 (2012-10-15) +------------------ + +* Bug: Fixed a cookie issue that caused dot prefixed domains to not match where popular browsers did + +2.8.7 (2012-09-30) +------------------ + +* Bug: Fixed config file aliases for JSON includes +* Bug: Fixed cookie bug on a request object by using CookieParser to parse cookies on requests +* Bug: Removing the path to a file when sending a Content-Disposition header on a POST upload +* Bug: Hardening request and response parsing to account for missing parts +* Bug: Fixed PEAR packaging +* Bug: Fixed Request::getInfo +* Bug: Fixed cases where CURLM_CALL_MULTI_PERFORM return codes were causing curl transactions to fail +* Adding the ability for the namespace Iterator factory to look in multiple directories +* Added more getters/setters/removers from service descriptions +* Added the ability to remove POST fields from OAuth signatures +* OAuth plugin now supports 2-legged OAuth + +2.8.6 (2012-09-05) +------------------ + +* Added the ability to modify and build service descriptions +* Added the use of visitors to apply parameters to locations in service descriptions using the dynamic command +* Added a `json` parameter location +* Now allowing dot notation for classes in the CacheAdapterFactory +* Using the union of two arrays rather than an array_merge when extending service builder services and service params +* Ensuring that a service is a string before doing strpos() checks on it when substituting services for references + in service builder config files. +* Services defined in two different config files that include one another will by default replace the previously + defined service, but you can now create services that extend themselves and merge their settings over the previous +* The JsonLoader now supports aliasing filenames with different filenames. This allows you to alias something like + '_default' with a default JSON configuration file. + +2.8.5 (2012-08-29) +------------------ + +* Bug: Suppressed empty arrays from URI templates +* Bug: Added the missing $options argument from ServiceDescription::factory to enable caching +* Added support for HTTP responses that do not contain a reason phrase in the start-line +* AbstractCommand commands are now invokable +* Added a way to get the data used when signing an Oauth request before a request is sent + +2.8.4 (2012-08-15) +------------------ + +* Bug: Custom delay time calculations are no longer ignored in the ExponentialBackoffPlugin +* Added the ability to transfer entity bodies as a string rather than streamed. This gets around curl error 65. Set `body_as_string` in a request's curl options to enable. +* Added a StreamInterface, EntityBodyInterface, and added ftell() to Guzzle\Common\Stream +* Added an AbstractEntityBodyDecorator and a ReadLimitEntityBody decorator to transfer only a subset of a decorated stream +* Stream and EntityBody objects will now return the file position to the previous position after a read required operation (e.g. getContentMd5()) +* Added additional response status codes +* Removed SSL information from the default User-Agent header +* DELETE requests can now send an entity body +* Added an EventDispatcher to the ExponentialBackoffPlugin and added an ExponentialBackoffLogger to log backoff retries +* Added the ability of the MockPlugin to consume mocked request bodies +* LogPlugin now exposes request and response objects in the extras array + +2.8.3 (2012-07-30) +------------------ + +* Bug: Fixed a case where empty POST requests were sent as GET requests +* Bug: Fixed a bug in ExponentialBackoffPlugin that caused fatal errors when retrying an EntityEnclosingRequest that does not have a body +* Bug: Setting the response body of a request to null after completing a request, not when setting the state of a request to new +* Added multiple inheritance to service description commands +* Added an ApiCommandInterface and added ``getParamNames()`` and ``hasParam()`` +* Removed the default 2mb size cutoff from the Md5ValidatorPlugin so that it now defaults to validating everything +* Changed CurlMulti::perform to pass a smaller timeout to CurlMulti::executeHandles + +2.8.2 (2012-07-24) +------------------ + +* Bug: Query string values set to 0 are no longer dropped from the query string +* Bug: A Collection object is no longer created each time a call is made to ``Guzzle\Service\Command\AbstractCommand::getRequestHeaders()`` +* Bug: ``+`` is now treated as an encoded space when parsing query strings +* QueryString and Collection performance improvements +* Allowing dot notation for class paths in filters attribute of a service descriptions + +2.8.1 (2012-07-16) +------------------ + +* Loosening Event Dispatcher dependency +* POST redirects can now be customized using CURLOPT_POSTREDIR + +2.8.0 (2012-07-15) +------------------ + +* BC: Guzzle\Http\Query + * Query strings with empty variables will always show an equal sign unless the variable is set to QueryString::BLANK (e.g. ?acl= vs ?acl) + * Changed isEncodingValues() and isEncodingFields() to isUrlEncoding() + * Changed setEncodeValues(bool) and setEncodeFields(bool) to useUrlEncoding(bool) + * Changed the aggregation functions of QueryString to be static methods + * Can now use fromString() with querystrings that have a leading ? +* cURL configuration values can be specified in service descriptions using ``curl.`` prefixed parameters +* Content-Length is set to 0 before emitting the request.before_send event when sending an empty request body +* Cookies are no longer URL decoded by default +* Bug: URI template variables set to null are no longer expanded + +2.7.2 (2012-07-02) +------------------ + +* BC: Moving things to get ready for subtree splits. Moving Inflection into Common. Moving Guzzle\Http\Parser to Guzzle\Parser. +* BC: Removing Guzzle\Common\Batch\Batch::count() and replacing it with isEmpty() +* CachePlugin now allows for a custom request parameter function to check if a request can be cached +* Bug fix: CachePlugin now only caches GET and HEAD requests by default +* Bug fix: Using header glue when transferring headers over the wire +* Allowing deeply nested arrays for composite variables in URI templates +* Batch divisors can now return iterators or arrays + +2.7.1 (2012-06-26) +------------------ + +* Minor patch to update version number in UA string +* Updating build process + +2.7.0 (2012-06-25) +------------------ + +* BC: Inflection classes moved to Guzzle\Inflection. No longer static methods. Can now inject custom inflectors into classes. +* BC: Removed magic setX methods from commands +* BC: Magic methods mapped to service description commands are now inflected in the command factory rather than the client __call() method +* Verbose cURL options are no longer enabled by default. Set curl.debug to true on a client to enable. +* Bug: Now allowing colons in a response start-line (e.g. HTTP/1.1 503 Service Unavailable: Back-end server is at capacity) +* Guzzle\Service\Resource\ResourceIteratorApplyBatched now internally uses the Guzzle\Common\Batch namespace +* Added Guzzle\Service\Plugin namespace and a PluginCollectionPlugin +* Added the ability to set POST fields and files in a service description +* Guzzle\Http\EntityBody::factory() now accepts objects with a __toString() method +* Adding a command.before_prepare event to clients +* Added BatchClosureTransfer and BatchClosureDivisor +* BatchTransferException now includes references to the batch divisor and transfer strategies +* Fixed some tests so that they pass more reliably +* Added Guzzle\Common\Log\ArrayLogAdapter + +2.6.6 (2012-06-10) +------------------ + +* BC: Removing Guzzle\Http\Plugin\BatchQueuePlugin +* BC: Removing Guzzle\Service\Command\CommandSet +* Adding generic batching system (replaces the batch queue plugin and command set) +* Updating ZF cache and log adapters and now using ZF's composer repository +* Bug: Setting the name of each ApiParam when creating through an ApiCommand +* Adding result_type, result_doc, deprecated, and doc_url to service descriptions +* Bug: Changed the default cookie header casing back to 'Cookie' + +2.6.5 (2012-06-03) +------------------ + +* BC: Renaming Guzzle\Http\Message\RequestInterface::getResourceUri() to getResource() +* BC: Removing unused AUTH_BASIC and AUTH_DIGEST constants from +* BC: Guzzle\Http\Cookie is now used to manage Set-Cookie data, not Cookie data +* BC: Renaming methods in the CookieJarInterface +* Moving almost all cookie logic out of the CookiePlugin and into the Cookie or CookieJar implementations +* Making the default glue for HTTP headers ';' instead of ',' +* Adding a removeValue to Guzzle\Http\Message\Header +* Adding getCookies() to request interface. +* Making it easier to add event subscribers to HasDispatcherInterface classes. Can now directly call addSubscriber() + +2.6.4 (2012-05-30) +------------------ + +* BC: Cleaning up how POST files are stored in EntityEnclosingRequest objects. Adding PostFile class. +* BC: Moving ApiCommand specific functionality from the Inspector and on to the ApiCommand +* Bug: Fixing magic method command calls on clients +* Bug: Email constraint only validates strings +* Bug: Aggregate POST fields when POST files are present in curl handle +* Bug: Fixing default User-Agent header +* Bug: Only appending or prepending parameters in commands if they are specified +* Bug: Not requiring response reason phrases or status codes to match a predefined list of codes +* Allowing the use of dot notation for class namespaces when using instance_of constraint +* Added any_match validation constraint +* Added an AsyncPlugin +* Passing request object to the calculateWait method of the ExponentialBackoffPlugin +* Allowing the result of a command object to be changed +* Parsing location and type sub values when instantiating a service description rather than over and over at runtime + +2.6.3 (2012-05-23) +------------------ + +* [BC] Guzzle\Common\FromConfigInterface no longer requires any config options. +* [BC] Refactoring how POST files are stored on an EntityEnclosingRequest. They are now separate from POST fields. +* You can now use an array of data when creating PUT request bodies in the request factory. +* Removing the requirement that HTTPS requests needed a Cache-Control: public directive to be cacheable. +* [Http] Adding support for Content-Type in multipart POST uploads per upload +* [Http] Added support for uploading multiple files using the same name (foo[0], foo[1]) +* Adding more POST data operations for easier manipulation of POST data. +* You can now set empty POST fields. +* The body of a request is only shown on EntityEnclosingRequest objects that do not use POST files. +* Split the Guzzle\Service\Inspector::validateConfig method into two methods. One to initialize when a command is created, and one to validate. +* CS updates + +2.6.2 (2012-05-19) +------------------ + +* [Http] Better handling of nested scope requests in CurlMulti. Requests are now always prepares in the send() method rather than the addRequest() method. + +2.6.1 (2012-05-19) +------------------ + +* [BC] Removing 'path' support in service descriptions. Use 'uri'. +* [BC] Guzzle\Service\Inspector::parseDocBlock is now protected. Adding getApiParamsForClass() with cache. +* [BC] Removing Guzzle\Common\NullObject. Use https://github.com/mtdowling/NullObject if you need it. +* [BC] Removing Guzzle\Common\XmlElement. +* All commands, both dynamic and concrete, have ApiCommand objects. +* Adding a fix for CurlMulti so that if all of the connections encounter some sort of curl error, then the loop exits. +* Adding checks to EntityEnclosingRequest so that empty POST files and fields are ignored. +* Making the method signature of Guzzle\Service\Builder\ServiceBuilder::factory more flexible. + +2.6.0 (2012-05-15) +------------------ + +* [BC] Moving Guzzle\Service\Builder to Guzzle\Service\Builder\ServiceBuilder +* [BC] Executing a Command returns the result of the command rather than the command +* [BC] Moving all HTTP parsing logic to Guzzle\Http\Parsers. Allows for faster C implementations if needed. +* [BC] Changing the Guzzle\Http\Message\Response::setProtocol() method to accept a protocol and version in separate args. +* [BC] Moving ResourceIterator* to Guzzle\Service\Resource +* [BC] Completely refactored ResourceIterators to iterate over a cloned command object +* [BC] Moved Guzzle\Http\UriTemplate to Guzzle\Http\Parser\UriTemplate\UriTemplate +* [BC] Guzzle\Guzzle is now deprecated +* Moving Guzzle\Common\Guzzle::inject to Guzzle\Common\Collection::inject +* Adding Guzzle\Version class to give version information about Guzzle +* Adding Guzzle\Http\Utils class to provide getDefaultUserAgent() and getHttpDate() +* Adding Guzzle\Curl\CurlVersion to manage caching curl_version() data +* ServiceDescription and ServiceBuilder are now cacheable using similar configs +* Changing the format of XML and JSON service builder configs. Backwards compatible. +* Cleaned up Cookie parsing +* Trimming the default Guzzle User-Agent header +* Adding a setOnComplete() method to Commands that is called when a command completes +* Keeping track of requests that were mocked in the MockPlugin +* Fixed a caching bug in the CacheAdapterFactory +* Inspector objects can be injected into a Command object +* Refactoring a lot of code and tests to be case insensitive when dealing with headers +* Adding Guzzle\Http\Message\HeaderComparison for easy comparison of HTTP headers using a DSL +* Adding the ability to set global option overrides to service builder configs +* Adding the ability to include other service builder config files from within XML and JSON files +* Moving the parseQuery method out of Url and on to QueryString::fromString() as a static factory method. + +2.5.0 (2012-05-08) +------------------ + +* Major performance improvements +* [BC] Simplifying Guzzle\Common\Collection. Please check to see if you are using features that are now deprecated. +* [BC] Using a custom validation system that allows a flyweight implementation for much faster validation. No longer using Symfony2 Validation component. +* [BC] No longer supporting "{{ }}" for injecting into command or UriTemplates. Use "{}" +* Added the ability to passed parameters to all requests created by a client +* Added callback functionality to the ExponentialBackoffPlugin +* Using microtime in ExponentialBackoffPlugin to allow more granular backoff strategies. +* Rewinding request stream bodies when retrying requests +* Exception is thrown when JSON response body cannot be decoded +* Added configurable magic method calls to clients and commands. This is off by default. +* Fixed a defect that added a hash to every parsed URL part +* Fixed duplicate none generation for OauthPlugin. +* Emitting an event each time a client is generated by a ServiceBuilder +* Using an ApiParams object instead of a Collection for parameters of an ApiCommand +* cache.* request parameters should be renamed to params.cache.* +* Added the ability to set arbitrary curl options on requests (disable_wire, progress, etc). See CurlHandle. +* Added the ability to disable type validation of service descriptions +* ServiceDescriptions and ServiceBuilders are now Serializable diff --git a/core/vendor/guzzlehttp/guzzle/LICENSE b/core/vendor/guzzlehttp/guzzle/LICENSE new file mode 100644 index 00000000000..71d3b783cb5 --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2014 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. diff --git a/core/vendor/guzzlehttp/guzzle/Makefile b/core/vendor/guzzlehttp/guzzle/Makefile new file mode 100644 index 00000000000..e21e9dfbf7f --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/Makefile @@ -0,0 +1,37 @@ +all: clean coverage docs + +start-server: + @ps aux | grep 'node tests/server.js' | grep -v grep > /dev/null \ + || 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=artifacts/coverage + $(MAKE) stop-server + +view-coverage: + open artifacts/coverage/index.html + +clean: + rm -rf artifacts/* + +docs: + cd docs && make html && cd .. + +view-docs: + open docs/_build/html/index.html + +perf: start-server + php tests/perf.php + $(MAKE) stop-server + +.PHONY: docs diff --git a/core/vendor/guzzlehttp/guzzle/README.md b/core/vendor/guzzlehttp/guzzle/README.md new file mode 100644 index 00000000000..017720bab06 --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/README.md @@ -0,0 +1,68 @@ +Guzzle, PHP HTTP client and webservice framework +================================================ + +[![Build Status](https://secure.travis-ci.org/guzzle/guzzle.png?branch=master)](http://travis-ci.org/guzzle/guzzle) + +Guzzle is a PHP HTTP client that makes it easy to work with HTTP/1.1 and takes +the pain out of consuming web services. + +```php +$client = new GuzzleHttp\Client(); +$response = $client->get('http://guzzlephp.org'); +$res = $client->get('https://api.github.com/user', ['auth' => ['user', 'pass']]); +echo $res->getStatusCode(); +// 200 +echo $res->getHeader('content-type'); +// 'application/json; charset=utf8' +echo $res->getBody(); +// {"type":"User"...' +var_export($res->json()); +// Outputs the JSON decoded data +``` + +- Pluggable HTTP adapters that can send requests serially or in parallel +- Doesn't require cURL, but uses cURL by default +- Streams data for both uploads and downloads +- Provides event hooks & plugins for cookies, caching, logging, OAuth, mocks, + etc... +- Keep-Alive & connection pooling +- SSL Verification +- Automatic decompression of response bodies +- Streaming multipart file uploads +- Connection timeouts + +Get more information and answers with the +[Documentation](http://guzzlephp.org/), +[Forums](https://groups.google.com/forum/?hl=en#!forum/guzzle), +and IRC ([#guzzlephp](irc://irc.freenode.net/#guzzlephp) @ irc.freenode.net). + +### Installing via Composer + +The recommended way to install Guzzle is through +[Composer](http://getcomposer.org). + +```bash +# Install Composer +curl -sS https://getcomposer.org/installer | php +``` + +Next, update your project's composer.json file to include Guzzle: + +```javascript +{ + "require": { + "guzzlehttp/guzzle": "~4.0" + } +} +``` + +After installing, you need to require Composer's autoloader: + +```php +require 'vendor/autoload.php'; +``` + +### Documentation + +More information can be found in the online documentation at +http://guzzlephp.org/. diff --git a/core/vendor/guzzlehttp/guzzle/UPGRADING.md b/core/vendor/guzzlehttp/guzzle/UPGRADING.md new file mode 100644 index 00000000000..0b1c1156bda --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/UPGRADING.md @@ -0,0 +1,987 @@ +Guzzle Upgrade Guide +==================== + +3.x to 4.0 +---------- + +## Overarching changes: + +- Now requires PHP 5.4 or greater. +- No longer requires cURL to send requests. +- Guzzle no longer wraps every exception it throws. Only exceptions that are + recoverable are now wrapped by Guzzle. +- Various namespaces have been removed or renamed. +- No longer requiring the Symfony EventDispatcher. A custom event dispatcher + based on the Symfony EventDispatcher is + now utilized in `GuzzleHttp\Event\EmitterInterface` (resulting in significant + speed and functionality improvements). + +Changes per Guzzle 3.x namespace are described below. + +## Batch + +The `Guzzle\Batch` namespace has been removed. This is best left to +third-parties to implement on top of Guzzle's core HTTP library. + +## Cache + +The `Guzzle\Cache` namespace has been removed. (Todo: No suitable replacement +has been implemented yet, but hoping to utilize a PSR cache interface). + +## Common + +- Removed all of the wrapped exceptions. It's better to use the standard PHP + library for unrecoverable exceptions. +- `FromConfigInterface` has been removed. +- `Guzzle\Common\Version` has been removed. The VERSION constant can be found + at `GuzzleHttp\ClientInterface::VERSION`. + +### Collection + +- `getAll` has been removed. Use `toArray` to convert a collection to an array. +- `inject` has been removed. +- `keySearch` has been removed. +- `getPath` no longer supports wildcard expressions. Use something better like + JMESPath for this. +- `setPath` now supports appending to an existing array via the `[]` notation. + +### Events + +Guzzle no longer requires Symfony's EventDispatcher component. Guzzle now uses +`GuzzleHttp\Event\Emitter`. + +- `Symfony\Component\EventDispatcher\EventDispatcherInterface` is replaced by + `GuzzleHttp\Event\EmitterInterface`. +- `Symfony\Component\EventDispatcher\EventDispatcher` is replaced by + `GuzzleHttp\Event\Emitter`. +- `Symfony\Component\EventDispatcher\Event` is replaced by + `GuzzleHttp\Event\Event`, and Guzzle now has an EventInterface in + `GuzzleHttp\Event\EventInterface`. +- `AbstractHasDispatcher` has moved to a trait, `HasEmitterTrait`, and + `HasDispatcherInterface` has moved to `HasEmitterInterface`. Retrieving the + event emitter of a request, client, etc now uses the `getEmitter` method + rather than the `getDispatcher` method. + +#### Emitter + +- Use the `once()` method to add a listener that automatically removes itself + the first time it is invoked. +- Use the `listeners()` method to retrieve a list of event listeners rather than + the `getListeners()` method. +- Use `emit()` instead of `dispatch()` to emit an event from an emitter. +- Use `attach()` instead of `addSubscriber()` and `detach()` instead of + `removeSubscriber()`. + +```php +$mock = new Mock(); +// 3.x +$request->getEventDispatcher()->addSubscriber($mock); +$request->getEventDispatcher()->removeSubscriber($mock); +// 4.x +$request->getEmitter()->attach($mock); +$request->getEmitter()->detach($mock); +``` + +Use the `on()` method to add a listener rather than the `addListener()` method. + +```php +// 3.x +$request->getEventDispatcher()->addListener('foo', function (Event $event) { /* ... */ } ); +// 4.x +$request->getEmitter()->on('foo', function (Event $event, $name) { /* ... */ } ); +``` + +## Http + +### General changes + +- The cacert.pem certificate has been moved to `src/cacert.pem`. +- Added the concept of adapters that are used to transfer requests over the + wire. +- Simplified the event system. +- Sending requests in parallel is still possible, but batching is no longer a + concept of the HTTP layer. Instead, you must use the `complete` and `error` + events to asynchronously manage parallel request transfers. +- `Guzzle\Http\Url` has moved to `GuzzleHttp\Url`. +- `Guzzle\Http\QueryString` has moved to `GuzzleHttp\Query`. +- QueryAggregators have been rewritten so that they are simply callable + functions. +- `GuzzleHttp\StaticClient` has been removed. Use the functions provided in + `functions.php` for an easy to use static client instance. +- Exceptions in `GuzzleHttp\Exception` have been updated to all extend from + `GuzzleHttp\Exception\TransferException`. + +### Client + +Calling methods like `get()`, `post()`, `head()`, etc. no longer create and +return a request, but rather creates a request, sends the request, and returns +the response. + +```php +// 3.0 +$request = $client->get('/'); +$response = $request->send(); + +// 4.0 +$response = $client->get('/'); + +// or, to mirror the previous behavior +$request = $client->createRequest('GET', '/'); +$response = $client->send($request); +``` + +`GuzzleHttp\ClientInterface` has changed. + +- The `send` method no longer accepts more than one request. Use `sendAll` to + send multiple requests in parallel. +- `setUserAgent()` has been removed. Use a default request option instead. You + could, for example, do something like: + `$client->setConfig('defaults/headers/User-Agent', 'Foo/Bar ' . $client::getDefaultUserAgent())`. +- `setSslVerification()` has been removed. Use default request options instead, + like `$client->setConfig('defaults/verify', true)`. + +`GuzzleHttp\Client` has changed. + +- The constructor now accepts only an associative array. You can include a + `base_url` string or array to use a URI template as the base URL of a client. + You can also specify a `defaults` key that is an associative array of default + request options. You can pass an `adapter` to use a custom adapter, + `batch_adapter` to use a custom adapter for sending requests in parallel, or + a `message_factory` to change the factory used to create HTTP requests and + responses. +- The client no longer emits a `client.create_request` event. +- Creating requests with a client no longer automatically utilize a URI + template. You must pass an array into a creational method (e.g., + `createRequest`, `get`, `put`, etc...) in order to expand a URI template. + +### Messages + +Messages no longer have references to their counterparts (i.e., a request no +longer has a reference to it's response, and a response no loger has a +reference to its request). This association is now managed through a +`GuzzleHttp\Adapter\TransactionInterface` object. You can get references to +these transaction objects using request events that are emitted over the +lifecycle of a request. + +#### Requests with a body + +- `GuzzleHttp\Message\EntityEnclosingRequest` and + `GuzzleHttp\Message\EntityEnclosingRequestInterface` have been removed. The + separation between requests that contain a body and requests that do not + contain a body has been removed, and now `GuzzleHttp\Message\RequestInterface` + handles both use cases. +- Any method that previously accepts a `GuzzleHttp\Response` object now accept a + `GuzzleHttp\Message\ResponseInterface`. +- `GuzzleHttp\Message\RequestFactoryInterface` has been renamed to + `GuzzleHttp\Message\MessageFactoryInterface`. This interface is used to create + both requests and responses and is implemented in + `GuzzleHttp\Message\MessageFactory`. +- POST field and file methods have been removed from the request object. You + must now use the methods made available to `GuzzleHttp\Post\PostBodyInterface` + to control the format of a POST body. Requests that are created using a + standard `GuzzleHttp\Message\MessageFactoryInterface` will automatically use + a `GuzzleHttp\Post\PostBody` body if the body was passed as an array or if + the method is POST and no body is provided. + +```php +$request = $client->createRequest('POST', '/'); +$request->getBody()->setField('foo', 'bar'); +$request->getBody()->addFile(new PostFile('file_key', fopen('/path/to/content', 'r'))); +``` + +#### Headers + +- `GuzzleHttp\Message\Header` has been removed. Header values are now simply + represented by an array of values or as a string. Header values are returned + as a string by default when retrieving a header value from a message. You can + pass an optional argument of `true` to retrieve a header value as an array + of strings instead of a single concatenated string. +- `GuzzleHttp\PostFile` and `GuzzleHttp\PostFileInterface` have been moved to + `GuzzleHttp\Post`. This interface has been simplified and now allows the + addition of arbitrary headers. +- Custom headers like `GuzzleHttp\Message\Header\Link` have been removed. Most + of the custom headers are now handled separately in specific + subscribers/plugins, and `GuzzleHttp\Message\HeaderValues::parseParams()` has + been updated to properly handle headers that contain parameters (like the + `Link` header). + +#### Responses + +- `GuzzleHttp\Message\Response::getInfo()` and + `GuzzleHttp\Message\Response::setInfo()` have been removed. Use the event + system to retrieve this type of information. +- `GuzzleHttp\Message\Response::getRawHeaders()` has been removed. +- `GuzzleHttp\Message\Response::getMessage()` has been removed. +- `GuzzleHttp\Message\Response::calculateAge()` and other cache specific + methods have moved to the CacheSubscriber. +- Header specific helper functions like `getContentMd5()` have been removed. + Just use `getHeader('Content-MD5')` instead. +- `GuzzleHttp\Message\Response::setRequest()` and + `GuzzleHttp\Message\Response::getRequest()` have been removed. Use the event + system to work with request and response objects as a transaction. +- `GuzzleHttp\Message\Response::getRedirectCount()` has been removed. Use the + Redirect subscriber instead. +- `GuzzleHttp\Message\Response::isSuccessful()` and other related methods have + been removed. Use `getStatusCode()` instead. + +#### Streaming responses + +Streaming requests can now be created by a client directly, returning a +`GuzzleHttp\Message\ResponseInterface` object that contains a body stream +referencing an open PHP HTTP stream. + +```php +// 3.0 +use Guzzle\Stream\PhpStreamRequestFactory; +$request = $client->get('/'); +$factory = new PhpStreamRequestFactory(); +$stream = $factory->fromRequest($request); +$data = $stream->read(1024); + +// 4.0 +$response = $client->get('/', ['stream' => true]); +// Read some data off of the stream in the response body +$data = $response->getBody()->read(1024); +``` + +#### Redirects + +The `configureRedirects()` method has been removed in favor of a +`allow_redirects` request option. + +```php +// Standard redirects with a default of a max of 5 redirects +$request = $client->createRequest('GET', '/', ['allow_redirects' => true]); + +// Strict redirects with a custom number of redirects +$request = $client->createRequest('GET', '/', [ + 'allow_redirects' => ['max' => 5, 'strict' => true] +]); +``` + +#### EntityBody + +EntityBody interfaces and classes have been removed or moved to +`GuzzleHttp\Stream`. All classes and interfaces that once required +`GuzzleHttp\EntityBodyInterface` now require +`GuzzleHttp\Stream\StreamInterface`. Creating a new body for a request no +longer uses `GuzzleHttp\EntityBody::factory` but now uses +`GuzzleHttp\Stream\Stream::factory` or even better: +`GuzzleHttp\Stream\create()`. + +- `Guzzle\Http\EntityBodyInterface` is now `GuzzleHttp\Stream\StreamInterface` +- `Guzzle\Http\EntityBody` is now `GuzzleHttp\Stream\Stream` +- `Guzzle\Http\CachingEntityBody` is now `GuzzleHttp\Stream\CachingStream` +- `Guzzle\Http\ReadLimitEntityBody` is now `GuzzleHttp\Stream\LimitStream` +- `Guzzle\Http\IoEmittyinEntityBody` has been removed. + +#### Request lifecycle events + +Requests previously submitted a large number of requests. The number of events +emitted over the lifecycle of a request has been significantly reduced to make +it easier to understand how to extend the behavior of a request. All events +emitted during the lifecycle of a request now emit a custom +`GuzzleHttp\Event\EventInterface` object that contains context providing +methods and a way in which to modify the transaction at that specific point in +time (e.g., intercept the request and set a response on the transaction). + +- `request.before_send` has been renamed to ``before`` and now emits a + `GuzzleHttp\Event\BeforeEvent` +- `request.complete` has been renamed to `complete` and now emits a + `GuzzleHttp\Event\CompleteEvent`. +- `request.sent` has been removed. Use `complete`. +- `request.success` has been removed. Use `complete`. +- `error` is now an event that emits a `GuzzleHttp\Event\ErrorEvent`. +- `request.exception` has been removed. Use `error`. +- `request.receive.status_line` has been removed. +- `curl.callback.progress` has been removed. Use a custom `StreamInterface` to + maintain a status update. +- `curl.callback.write` has been removed. Use a custom `StreamInterface` to + intercept writes. +- `curl.callback.read` has been removed. Use a custom `StreamInterface` to + intercept reads. + +`headers` is a new event that is emitted after the response headers of a +request have been received before the body of the response is downloaded. This +event emits a `GuzzleHttp\Event\HeadersEvent`. + +You can intercept a request and inject a response using the `intercept()` event +of a `GuzzleHttp\Event\BeforeEvent`, `GuzzleHttp\Event\CompleteEvent`, and +`GuzzleHttp\Event\ErrorEvent` event. + +See: http://docs.guzzlephp.org/en/latest/events.html + +## Inflection + +The `Guzzle\Inflection` namespace has been removed. This is not a core concern +of Guzzle. + +## Iterator + +The `Guzzle\Iterator` namespace has been removed. + +- `Guzzle\Iterator\AppendIterator`, `Guzzle\Iterator\ChunkedIterator`, and + `Guzzle\Iterator\MethodProxyIterator` are nice, but not a core requirement of + Guzzle itself. +- `Guzzle\Iterator\FilterIterator` is no longer needed because an equivalent + class is shipped with PHP 5.4. +- `Guzzle\Iterator\MapIterator` is not really needed when using PHP 5.5 because + it's easier to just wrap an iterator in a generator that maps values. + +For a replacement of these iterators, see https://github.com/nikic/iter + +## Log + +The LogPlugin has moved to https://github.com/guzzle/log-subscriber. The +`Guzzle\Log` namespace has been removed. Guzzle now relies on +`Psr\Log\LoggerInterface` for all logging. The MessageFormatter class has been +moved to `GuzzleHttp\Subscriber\Log\Formatter`. + +## Parser + +The `Guzzle\Parser` namespace has been removed. This was previously used to +make it possible to plug in custom parsers for cookies, messages, URI +templates, and URLs; however, this level of complexity is not needed in Guzzle +so it has been removed. + +- Cookie: Cookie parsing logic has been moved to + `GuzzleHttp\Cookie\SetCookie::fromString`. +- Message: Message parsing logic for both requests and responses has been moved + to `GuzzleHttp\Message\MessageFactory::fromMessage`. Message parsing is only + used in debugging or deserializing messages, so it doesn't make sense for + Guzzle as a library to add this level of complexity to parsing messages. +- UriTemplate: URI template parsing has been moved to + `GuzzleHttp\UriTemplate`. The Guzzle library will automatically use the PECL + URI template library if it is installed. +- Url: URL parsing is now performed in `GuzzleHttp\Url::fromString` (previously + it was `Guzzle\Http\Url::factory()`). If custom URL parsing is necessary, + then developers are free to subclass `GuzzleHttp\Url`. + +## Plugin + +The `Guzzle\Plugin` namespace has been renamed to `GuzzleHttp\Subscriber`. +Several plugins are shipping with the core Guzzle library under this namespace. + +- `GuzzleHttp\Subscriber\Cookie`: Replaces the old CookiePlugin. Cookie jar + code has moved to `GuzzleHttp\Cookie`. +- `GuzzleHttp\Subscriber\History`: Replaces the old HistoryPlugin. +- `GuzzleHttp\Subscriber\HttpError`: Throws errors when a bad HTTP response is + received. +- `GuzzleHttp\Subscriber\Mock`: Replaces the old MockPlugin. +- `GuzzleHttp\Subscriber\Prepare`: Prepares the body of a request just before + sending. This subscriber is attached to all requests by default. +- `GuzzleHttp\Subscriber\Redirect`: Replaces the RedirectPlugin. + +The following plugins have been removed (third-parties are free to re-implement +these if needed): + +- `GuzzleHttp\Plugin\Async` has been removed. +- `GuzzleHttp\Plugin\CurlAuth` has been removed. +- `GuzzleHttp\Plugin\ErrorResponse\ErrorResponsePlugin` has been removed. This + functionality should instead be implemented with event listeners that occur + after normal response parsing occurs in the guzzle/command package. + +The following plugins are not part of the core Guzzle package, but are provided +in separate repositories: + +- `Guzzle\Http\Plugin\BackoffPlugin` has been rewritten to be muchs simpler + to build custom retry policies using simple functions rather than various + chained classes. See: https://github.com/guzzle/retry-subscriber +- `Guzzle\Http\Plugin\Cache\CachePlugin` has moved to + https://github.com/guzzle/cache-subscriber +- `Guzzle\Http\Plugin\Log\LogPlugin` has moved to + https://github.com/guzzle/log-subscriber +- `Guzzle\Http\Plugin\Md5\Md5Plugin` has moved to + https://github.com/guzzle/message-integrity-subscriber +- `Guzzle\Http\Plugin\Mock\MockPlugin` has moved to + `GuzzleHttp\Subscriber\MockSubscriber`. +- `Guzzle\Http\Plugin\Oauth\OauthPlugin` has moved to + https://github.com/guzzle/oauth-subscriber + +## Service + +The service description layer of Guzzle has moved into two separate packages: + +- http://github.com/guzzle/command Provides a high level abstraction over web + services by representing web service operations using commands. +- http://github.com/guzzle/guzzle-services Provides an implementation of + guzzle/command that provides request serialization and response parsing using + Guzzle service descriptions. + +## Stream + +Stream have moved to a separate package available at +https://github.com/guzzle/streams. + +`Guzzle\Stream\StreamInterface` has been given a large update to cleanly take +on the responsibilities of `Guzzle\Http\EntityBody` and +`Guzzle\Http\EntityBodyInterface` now that they have been removed. The number +of methods implemented by the `StreamInterface` has been drastically reduced to +allow developers to more easily extend and decorate stream behavior. + +## Removed methods from StreamInterface + +- `getStream` and `setStream` have been removed to better encapsulate streams. +- `getMetadata` and `setMetadata` have been removed in favor of + `GuzzleHttp\Stream\MetadataStreamInterface`. +- `getWrapper`, `getWrapperData`, `getStreamType`, and `getUri` have all been + removed. This data is accessible when + using streams that implement `GuzzleHttp\Stream\MetadataStreamInterface`. +- `rewind` has been removed. Use `seek(0)` for a similar behavior. + +## Renamed methods + +- `detachStream` has been renamed to `detach`. +- `feof` has been renamed to `eof`. +- `ftell` has been renamed to `tell`. +- `readLine` has moved from an instance method to a static class method of + `GuzzleHttp\Stream\Stream`. + +## Metadata streams + +`GuzzleHttp\Stream\MetadataStreamInterface` has been added to denote streams +that contain additonal metadata accessible via `getMetadata()`. +`GuzzleHttp\Stream\StreamInterface::getMetadata` and +`GuzzleHttp\Stream\StreamInterface::setMetadata` have been removed. + +## SteamRequestFactory + +The entire concept of the StreamRequestFactory has been removed. The way this +was used in Guzzle 3 broke the actual interface of sending streaming requests +(instead of getting back a Response, you got a StreamInterface). Streeaming +PHP requests are now implemented throught the `GuzzleHttp\Adapter\StreamAdapter`. + +3.6 to 3.7 +---------- + +### Deprecations + +- You can now enable E_USER_DEPRECATED warnings to see if you are using any deprecated methods.: + +```php +\Guzzle\Common\Version::$emitWarnings = true; +``` + +The following APIs and options have been marked as deprecated: + +- Marked `Guzzle\Http\Message\Request::isResponseBodyRepeatable()` as deprecated. Use `$request->getResponseBody()->isRepeatable()` instead. +- Marked `Guzzle\Http\Message\Request::canCache()` as deprecated. Use `Guzzle\Plugin\Cache\DefaultCanCacheStrategy->canCacheRequest()` instead. +- Marked `Guzzle\Http\Message\Request::canCache()` as deprecated. Use `Guzzle\Plugin\Cache\DefaultCanCacheStrategy->canCacheRequest()` instead. +- Marked `Guzzle\Http\Message\Request::setIsRedirect()` as deprecated. Use the HistoryPlugin instead. +- Marked `Guzzle\Http\Message\Request::isRedirect()` as deprecated. Use the HistoryPlugin instead. +- Marked `Guzzle\Cache\CacheAdapterFactory::factory()` as deprecated +- Marked `Guzzle\Service\Client::enableMagicMethods()` as deprecated. Magic methods can no longer be disabled on a Guzzle\Service\Client. +- Marked `Guzzle\Parser\Url\UrlParser` as deprecated. Just use PHP's `parse_url()` and percent encode your UTF-8. +- Marked `Guzzle\Common\Collection::inject()` as deprecated. +- Marked `Guzzle\Plugin\CurlAuth\CurlAuthPlugin` as deprecated. Use + `$client->getConfig()->setPath('request.options/auth', array('user', 'pass', 'Basic|Digest|NTLM|Any'));` or + `$client->setDefaultOption('auth', array('user', 'pass', 'Basic|Digest|NTLM|Any'));` + +3.7 introduces `request.options` as a parameter for a client configuration and as an optional argument to all creational +request methods. When paired with a client's configuration settings, these options allow you to specify default settings +for various aspects of a request. Because these options make other previous configuration options redundant, several +configuration options and methods of a client and AbstractCommand have been deprecated. + +- Marked `Guzzle\Service\Client::getDefaultHeaders()` as deprecated. Use `$client->getDefaultOption('headers')`. +- Marked `Guzzle\Service\Client::setDefaultHeaders()` as deprecated. Use `$client->setDefaultOption('headers/{header_name}', 'value')`. +- Marked 'request.params' for `Guzzle\Http\Client` as deprecated. Use `$client->setDefaultOption('params/{param_name}', 'value')` +- Marked 'command.headers', 'command.response_body' and 'command.on_complete' as deprecated for AbstractCommand. These will work through Guzzle 4.0 + + $command = $client->getCommand('foo', array( + 'command.headers' => array('Test' => '123'), + 'command.response_body' => '/path/to/file' + )); + + // Should be changed to: + + $command = $client->getCommand('foo', array( + 'command.request_options' => array( + 'headers' => array('Test' => '123'), + 'save_as' => '/path/to/file' + ) + )); + +### Interface changes + +Additions and changes (you will need to update any implementations or subclasses you may have created): + +- Added an `$options` argument to the end of the following methods of `Guzzle\Http\ClientInterface`: + createRequest, head, delete, put, patch, post, options, prepareRequest +- Added an `$options` argument to the end of `Guzzle\Http\Message\Request\RequestFactoryInterface::createRequest()` +- Added an `applyOptions()` method to `Guzzle\Http\Message\Request\RequestFactoryInterface` +- Changed `Guzzle\Http\ClientInterface::get($uri = null, $headers = null, $body = null)` to + `Guzzle\Http\ClientInterface::get($uri = null, $headers = null, $options = array())`. You can still pass in a + resource, string, or EntityBody into the $options parameter to specify the download location of the response. +- Changed `Guzzle\Common\Collection::__construct($data)` to no longer accepts a null value for `$data` but a + default `array()` +- Added `Guzzle\Stream\StreamInterface::isRepeatable` +- Made `Guzzle\Http\Client::expandTemplate` and `getUriTemplate` protected methods. + +The following methods were removed from interfaces. All of these methods are still available in the concrete classes +that implement them, but you should update your code to use alternative methods: + +- Removed `Guzzle\Http\ClientInterface::setDefaultHeaders(). Use + `$client->getConfig()->setPath('request.options/headers/{header_name}', 'value')`. or + `$client->getConfig()->setPath('request.options/headers', array('header_name' => 'value'))` or + `$client->setDefaultOption('headers/{header_name}', 'value')`. or + `$client->setDefaultOption('headers', array('header_name' => 'value'))`. +- Removed `Guzzle\Http\ClientInterface::getDefaultHeaders(). Use `$client->getConfig()->getPath('request.options/headers')`. +- Removed `Guzzle\Http\ClientInterface::expandTemplate()`. This is an implementation detail. +- Removed `Guzzle\Http\ClientInterface::setRequestFactory()`. This is an implementation detail. +- Removed `Guzzle\Http\ClientInterface::getCurlMulti()`. This is a very specific implementation detail. +- Removed `Guzzle\Http\Message\RequestInterface::canCache`. Use the CachePlugin. +- Removed `Guzzle\Http\Message\RequestInterface::setIsRedirect`. Use the HistoryPlugin. +- Removed `Guzzle\Http\Message\RequestInterface::isRedirect`. Use the HistoryPlugin. + +### Cache plugin breaking changes + +- CacheKeyProviderInterface and DefaultCacheKeyProvider are no longer used. All of this logic is handled in a + CacheStorageInterface. These two objects and interface will be removed in a future version. +- Always setting X-cache headers on cached responses +- Default cache TTLs are now handled by the CacheStorageInterface of a CachePlugin +- `CacheStorageInterface::cache($key, Response $response, $ttl = null)` has changed to `cache(RequestInterface + $request, Response $response);` +- `CacheStorageInterface::fetch($key)` has changed to `fetch(RequestInterface $request);` +- `CacheStorageInterface::delete($key)` has changed to `delete(RequestInterface $request);` +- Added `CacheStorageInterface::purge($url)` +- `DefaultRevalidation::__construct(CacheKeyProviderInterface $cacheKey, CacheStorageInterface $cache, CachePlugin + $plugin)` has changed to `DefaultRevalidation::__construct(CacheStorageInterface $cache, + CanCacheStrategyInterface $canCache = null)` +- Added `RevalidationInterface::shouldRevalidate(RequestInterface $request, Response $response)` + +3.5 to 3.6 +---------- + +* Mixed casing of headers are now forced to be a single consistent casing across all values for that header. +* Messages internally use a HeaderCollection object to delegate handling case-insensitive header resolution +* Removed the whole changedHeader() function system of messages because all header changes now go through addHeader(). + For example, setHeader() first removes the header using unset on a HeaderCollection and then calls addHeader(). + Keeping the Host header and URL host in sync is now handled by overriding the addHeader method in Request. +* Specific header implementations can be created for complex headers. When a message creates a header, it uses a + HeaderFactory which can map specific headers to specific header classes. There is now a Link header and + CacheControl header implementation. +* Moved getLinks() from Response to just be used on a Link header object. + +If you previously relied on Guzzle\Http\Message\Header::raw(), then you will need to update your code to use the +HeaderInterface (e.g. toArray(), getAll(), etc). + +### Interface changes + +* Removed from interface: Guzzle\Http\ClientInterface::setUriTemplate +* Removed from interface: Guzzle\Http\ClientInterface::setCurlMulti() +* Removed Guzzle\Http\Message\Request::receivedRequestHeader() and implemented this functionality in + Guzzle\Http\Curl\RequestMediator +* Removed the optional $asString parameter from MessageInterface::getHeader(). Just cast the header to a string. +* Removed the optional $tryChunkedTransfer option from Guzzle\Http\Message\EntityEnclosingRequestInterface +* Removed the $asObjects argument from Guzzle\Http\Message\MessageInterface::getHeaders() + +### Removed deprecated functions + +* Removed Guzzle\Parser\ParserRegister::get(). Use getParser() +* Removed Guzzle\Parser\ParserRegister::set(). Use registerParser(). + +### Deprecations + +* The ability to case-insensitively search for header values +* Guzzle\Http\Message\Header::hasExactHeader +* Guzzle\Http\Message\Header::raw. Use getAll() +* Deprecated cache control specific methods on Guzzle\Http\Message\AbstractMessage. Use the CacheControl header object + instead. + +### Other changes + +* All response header helper functions return a string rather than mixing Header objects and strings inconsistently +* Removed cURL blacklist support. This is no longer necessary now that Expect, Accept, etc are managed by Guzzle + directly via interfaces +* Removed the injecting of a request object onto a response object. The methods to get and set a request still exist + but are a no-op until removed. +* Most classes that used to require a `Guzzle\Service\Command\CommandInterface` typehint now request a + `Guzzle\Service\Command\ArrayCommandInterface`. +* Added `Guzzle\Http\Message\RequestInterface::startResponse()` to the RequestInterface to handle injecting a response + on a request while the request is still being transferred +* `Guzzle\Service\Command\CommandInterface` now extends from ToArrayInterface and ArrayAccess + +3.3 to 3.4 +---------- + +Base URLs of a client now follow the rules of http://tools.ietf.org/html/rfc3986#section-5.2.2 when merging URLs. + +3.2 to 3.3 +---------- + +### Response::getEtag() quote stripping removed + +`Guzzle\Http\Message\Response::getEtag()` no longer strips quotes around the ETag response header + +### Removed `Guzzle\Http\Utils` + +The `Guzzle\Http\Utils` class was removed. This class was only used for testing. + +### Stream wrapper and type + +`Guzzle\Stream\Stream::getWrapper()` and `Guzzle\Stream\Stream::getSteamType()` are no longer converted to lowercase. + +### curl.emit_io became emit_io + +Emitting IO events from a RequestMediator is now a parameter that must be set in a request's curl options using the +'emit_io' key. This was previously set under a request's parameters using 'curl.emit_io' + +3.1 to 3.2 +---------- + +### CurlMulti is no longer reused globally + +Before 3.2, the same CurlMulti object was reused globally for each client. This can cause issue where plugins added +to a single client can pollute requests dispatched from other clients. + +If you still wish to reuse the same CurlMulti object with each client, then you can add a listener to the +ServiceBuilder's `service_builder.create_client` event to inject a custom CurlMulti object into each client as it is +created. + +```php +$multi = new Guzzle\Http\Curl\CurlMulti(); +$builder = Guzzle\Service\Builder\ServiceBuilder::factory('/path/to/config.json'); +$builder->addListener('service_builder.create_client', function ($event) use ($multi) { + $event['client']->setCurlMulti($multi); +} +}); +``` + +### No default path + +URLs no longer have a default path value of '/' if no path was specified. + +Before: + +```php +$request = $client->get('http://www.foo.com'); +echo $request->getUrl(); +// >> http://www.foo.com/ +``` + +After: + +```php +$request = $client->get('http://www.foo.com'); +echo $request->getUrl(); +// >> http://www.foo.com +``` + +### Less verbose BadResponseException + +The exception message for `Guzzle\Http\Exception\BadResponseException` no longer contains the full HTTP request and +response information. You can, however, get access to the request and response object by calling `getRequest()` or +`getResponse()` on the exception object. + +### Query parameter aggregation + +Multi-valued query parameters are no longer aggregated using a callback function. `Guzzle\Http\Query` now has a +setAggregator() method that accepts a `Guzzle\Http\QueryAggregator\QueryAggregatorInterface` object. This object is +responsible for handling the aggregation of multi-valued query string variables into a flattened hash. + +2.8 to 3.x +---------- + +### Guzzle\Service\Inspector + +Change `\Guzzle\Service\Inspector::fromConfig` to `\Guzzle\Common\Collection::fromConfig` + +**Before** + +```php +use Guzzle\Service\Inspector; + +class YourClient extends \Guzzle\Service\Client +{ + public static function factory($config = array()) + { + $default = array(); + $required = array('base_url', 'username', 'api_key'); + $config = Inspector::fromConfig($config, $default, $required); + + $client = new self( + $config->get('base_url'), + $config->get('username'), + $config->get('api_key') + ); + $client->setConfig($config); + + $client->setDescription(ServiceDescription::factory(__DIR__ . DIRECTORY_SEPARATOR . 'client.json')); + + return $client; + } +``` + +**After** + +```php +use Guzzle\Common\Collection; + +class YourClient extends \Guzzle\Service\Client +{ + public static function factory($config = array()) + { + $default = array(); + $required = array('base_url', 'username', 'api_key'); + $config = Collection::fromConfig($config, $default, $required); + + $client = new self( + $config->get('base_url'), + $config->get('username'), + $config->get('api_key') + ); + $client->setConfig($config); + + $client->setDescription(ServiceDescription::factory(__DIR__ . DIRECTORY_SEPARATOR . 'client.json')); + + return $client; + } +``` + +### Convert XML Service Descriptions to JSON + +**Before** + +```xml + + + + + + Get a list of groups + + + Uses a search query to get a list of groups + + + + Create a group + + + + + Delete a group by ID + + + + + + + Update a group + + + + + + +``` + +**After** + +```json +{ + "name": "Zendesk REST API v2", + "apiVersion": "2012-12-31", + "description":"Provides access to Zendesk views, groups, tickets, ticket fields, and users", + "operations": { + "list_groups": { + "httpMethod":"GET", + "uri": "groups.json", + "summary": "Get a list of groups" + }, + "search_groups":{ + "httpMethod":"GET", + "uri": "search.json?query=\"{query} type:group\"", + "summary": "Uses a search query to get a list of groups", + "parameters":{ + "query":{ + "location": "uri", + "description":"Zendesk Search Query", + "type": "string", + "required": true + } + } + }, + "create_group": { + "httpMethod":"POST", + "uri": "groups.json", + "summary": "Create a group", + "parameters":{ + "data": { + "type": "array", + "location": "body", + "description":"Group JSON", + "filters": "json_encode", + "required": true + }, + "Content-Type":{ + "type": "string", + "location":"header", + "static": "application/json" + } + } + }, + "delete_group": { + "httpMethod":"DELETE", + "uri": "groups/{id}.json", + "summary": "Delete a group", + "parameters":{ + "id":{ + "location": "uri", + "description":"Group to delete by ID", + "type": "integer", + "required": true + } + } + }, + "get_group": { + "httpMethod":"GET", + "uri": "groups/{id}.json", + "summary": "Get a ticket", + "parameters":{ + "id":{ + "location": "uri", + "description":"Group to get by ID", + "type": "integer", + "required": true + } + } + }, + "update_group": { + "httpMethod":"PUT", + "uri": "groups/{id}.json", + "summary": "Update a group", + "parameters":{ + "id": { + "location": "uri", + "description":"Group to update by ID", + "type": "integer", + "required": true + }, + "data": { + "type": "array", + "location": "body", + "description":"Group JSON", + "filters": "json_encode", + "required": true + }, + "Content-Type":{ + "type": "string", + "location":"header", + "static": "application/json" + } + } + } +} +``` + +### Guzzle\Service\Description\ServiceDescription + +Commands are now called Operations + +**Before** + +```php +use Guzzle\Service\Description\ServiceDescription; + +$sd = new ServiceDescription(); +$sd->getCommands(); // @returns ApiCommandInterface[] +$sd->hasCommand($name); +$sd->getCommand($name); // @returns ApiCommandInterface|null +$sd->addCommand($command); // @param ApiCommandInterface $command +``` + +**After** + +```php +use Guzzle\Service\Description\ServiceDescription; + +$sd = new ServiceDescription(); +$sd->getOperations(); // @returns OperationInterface[] +$sd->hasOperation($name); +$sd->getOperation($name); // @returns OperationInterface|null +$sd->addOperation($operation); // @param OperationInterface $operation +``` + +### Guzzle\Common\Inflection\Inflector + +Namespace is now `Guzzle\Inflection\Inflector` + +### Guzzle\Http\Plugin + +Namespace is now `Guzzle\Plugin`. Many other changes occur within this namespace and are detailed in their own sections below. + +### Guzzle\Http\Plugin\LogPlugin and Guzzle\Common\Log + +Now `Guzzle\Plugin\Log\LogPlugin` and `Guzzle\Log` respectively. + +**Before** + +```php +use Guzzle\Common\Log\ClosureLogAdapter; +use Guzzle\Http\Plugin\LogPlugin; + +/** @var \Guzzle\Http\Client */ +$client; + +// $verbosity is an integer indicating desired message verbosity level +$client->addSubscriber(new LogPlugin(new ClosureLogAdapter(function($m) { echo $m; }, $verbosity = LogPlugin::LOG_VERBOSE); +``` + +**After** + +```php +use Guzzle\Log\ClosureLogAdapter; +use Guzzle\Log\MessageFormatter; +use Guzzle\Plugin\Log\LogPlugin; + +/** @var \Guzzle\Http\Client */ +$client; + +// $format is a string indicating desired message format -- @see MessageFormatter +$client->addSubscriber(new LogPlugin(new ClosureLogAdapter(function($m) { echo $m; }, $format = MessageFormatter::DEBUG_FORMAT); +``` + +### Guzzle\Http\Plugin\CurlAuthPlugin + +Now `Guzzle\Plugin\CurlAuth\CurlAuthPlugin`. + +### Guzzle\Http\Plugin\ExponentialBackoffPlugin + +Now `Guzzle\Plugin\Backoff\BackoffPlugin`, and other changes. + +**Before** + +```php +use Guzzle\Http\Plugin\ExponentialBackoffPlugin; + +$backoffPlugin = new ExponentialBackoffPlugin($maxRetries, array_merge( + ExponentialBackoffPlugin::getDefaultFailureCodes(), array(429) + )); + +$client->addSubscriber($backoffPlugin); +``` + +**After** + +```php +use Guzzle\Plugin\Backoff\BackoffPlugin; +use Guzzle\Plugin\Backoff\HttpBackoffStrategy; + +// Use convenient factory method instead -- see implementation for ideas of what +// you can do with chaining backoff strategies +$backoffPlugin = BackoffPlugin::getExponentialBackoff($maxRetries, array_merge( + HttpBackoffStrategy::getDefaultFailureCodes(), array(429) + )); +$client->addSubscriber($backoffPlugin); +``` + +### Known Issues + +#### [BUG] Accept-Encoding header behavior changed unintentionally. + +(See #217) (Fixed in 09daeb8c666fb44499a0646d655a8ae36456575e) + +In version 2.8 setting the `Accept-Encoding` header would set the CURLOPT_ENCODING option, which permitted cURL to +properly handle gzip/deflate compressed responses from the server. In versions affected by this bug this does not happen. +See issue #217 for a workaround, or use a version containing the fix. diff --git a/core/vendor/guzzlehttp/guzzle/composer.json b/core/vendor/guzzlehttp/guzzle/composer.json new file mode 100644 index 00000000000..3f7b96f3f3c --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/composer.json @@ -0,0 +1,40 @@ +{ + "name": "guzzlehttp/guzzle", + "type": "library", + "description": "Guzzle is a PHP HTTP client library and framework for building RESTful web service clients", + "keywords": ["framework", "http", "rest", "web service", "curl", "client", "HTTP client"], + "homepage": "http://guzzlephp.org/", + "license": "MIT", + + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + + "require": { + "php": ">=5.4.0", + "guzzlehttp/streams": "1.*" + }, + + "autoload": { + "psr-4": { + "GuzzleHttp\\": "src/" + }, + "files": ["src/functions.php"] + }, + + "require-dev": { + "ext-curl": "*", + "psr/log": "~1", + "phpunit/phpunit": "4.*" + }, + + "extra": { + "branch-alias": { + "dev-master": "4.0.x-dev" + } + } +} diff --git a/core/vendor/guzzlehttp/guzzle/docs/Makefile b/core/vendor/guzzlehttp/guzzle/docs/Makefile new file mode 100644 index 00000000000..d92e03f95ea --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/docs/Makefile @@ -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 ' where 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." diff --git a/core/vendor/guzzlehttp/guzzle/docs/_static/guzzle-icon.png b/core/vendor/guzzlehttp/guzzle/docs/_static/guzzle-icon.png new file mode 100644 index 00000000000..f1017f7e602 Binary files /dev/null and b/core/vendor/guzzlehttp/guzzle/docs/_static/guzzle-icon.png differ diff --git a/core/vendor/guzzlehttp/guzzle/docs/_static/logo.png b/core/vendor/guzzlehttp/guzzle/docs/_static/logo.png new file mode 100644 index 00000000000..ecc40ac7604 Binary files /dev/null and b/core/vendor/guzzlehttp/guzzle/docs/_static/logo.png differ diff --git a/core/vendor/guzzlehttp/guzzle/docs/_templates/nav_links.html b/core/vendor/guzzlehttp/guzzle/docs/_templates/nav_links.html new file mode 100644 index 00000000000..7950a0f8e9d --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/docs/_templates/nav_links.html @@ -0,0 +1,3 @@ +
  • GitHub
  • +
  • Forum
  • +
  • IRC
  • diff --git a/core/vendor/guzzlehttp/guzzle/docs/adapters.rst b/core/vendor/guzzlehttp/guzzle/docs/adapters.rst new file mode 100644 index 00000000000..27ad668fcb7 --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/docs/adapters.rst @@ -0,0 +1,222 @@ +======== +Adapters +======== + +Guzzle uses *adapters* to send HTTP requests. Adapters emit the lifecycle +events of requests, transfer HTTP requests, and normalize error handling. + +Default Adapter +=============== + +Guzzle will use the best possible adapter based on your environment. + +If cURL is present, Guzzle will use the following adapters by default: + +- ``GuzzleHttp\Adapter\Curl\MultiAdapter`` is used to transfer requests in + parallel. +- If ``allow_url_fopen`` is enabled, then a + ``GuzzleHttp\Adapter\StreamingProxyAdapter`` is added so that streaming + requests are sent using the PHP stream wrapper. If this setting is disabled, + then streaming requests are sent through a cURL adapter. +- If using PHP 5.5 or greater, then a a ``GuzzleHttp\Adapter\Curl\CurlAdapter`` + is used to send serial requests. Otherwise, the + ``GuzzleHttp\Adapter\Curl\MultiAdapter`` is used for serial and parallel + requests. + +If cURL is not installed, then Guzzle will use a +``GuzzleHttp\Adapter\StreamingAdapter`` to send requests through PHP's +HTTP stream wrapper. ``allow_url_fopen`` must be enabled if cURL is not +installed on your system. + +Creating an Adapter +=================== + +Creating a custom HTTP adapter allows you to completely customize the way an +HTTP request is sent over the wire. In some cases, you might need to use a +different mechanism for transferring HTTP requests other than cURL or PHP's +stream wrapper. For example, you might need to use a socket because the version +of cURL on your system has an old bug, maybe you'd like to implement future +response objects, or you want to create a thread pool and send parallel +requests using pthreads. + +The first thing you need to know about implementing custom adapters are the +responsibilities of an adapter. + +Adapter Responsibilities +------------------------ + +Adapters use a ``GuzzleHttp\Adapter\TransactionInterface`` which acts as a +mediator between ``GuzzleHttp\Message\RequestInterface`` and +``GuzzleHttp\Message\ResponseInterface`` objects. The main goal of an adapter +is to set a response on the provided transaction object. + +1. The adapter MUST return a ``GuzzleHttp\Message\ResponseInterface`` object in + a successful condition. + +2. When preparing requests, adapters MUST properly handle as many of the + following request configuration options as possible: + + - :ref:`cert-option` + - :ref:`connect_timeout-option` + - :ref:`debug-option` + - :ref:`expect-option` + - :ref:`proxy-option` + - :ref:`save_to-option` + - :ref:`ssl_key-option` + - :ref:`stream-option` + - :ref:`timeout-option` + - :ref:`verify-option` + +3. Adapters SHOULD not follow redirects. In the normal case, redirects are + followed by ``GuzzleHttp\Subscriber\Redirect``. Redirects SHOULD be + implemented using Guzzle event subscribers, not by an adapter. + +4. The adapter MUST emit a ``before`` event with a + ``GuzzleHttp\Event\BeforeEvent`` object before sending a request. If the + event is intercepted and a response is associated with a transaction during + the ``before`` event, then the adapter MUST not send the request over the + wire, but rather return the response. + +5. When all of the headers of a response have been received, the adapter MUST + emit a ``headers`` event with a ``GuzzleHttp\Event\HeadersEvent``. This + event MUST be emitted before any data is written to the body of the response + object. It is important to keep in mind that event listeners MAY mutate a + response during the emission of this event. + +6. The adapter MUST emit a ``complete`` event with a + ``GuzzleHttp\Event\CompleteEvent`` when a request has completed sending. + Adapters MUST emit the complete event for all valid HTTP responses, + including responses that resulted in a non 2xx level response. + +7. The adapter MUST emit an ``error`` event with a + ``GuzzleHttp\Event\ErrorEvent``when an error occurs during the transfer. + This includes when preparing a request for transfer, during the ``before`` + event, during the ``headers`` event, during the ``complete`` event, when + a networking error occurs, and so on. + +8. After emitting the ``error`` event, the adapter MUST check if the + error event was intercepted and a response was associated with the + transaction. If the propagation of the ``error`` event was not stopped, then + the adapter MUST throw the exception. If the propagation was stopped, then + the adapter MUST NOT throw the exception. + +Parallel Adapters +----------------- + +Parallel adapters are used when using a client's ``sendAll()`` method. Parallel +adapters are expected to send one or more transactions in parallel. Parallel +adapters accept an ``\Iterator`` that yields +``GuzzleHttp\Adapter\TransactionInterface`` object. In addition to the +iterator, the adapter is also provided an integer representing the number of +transactions to execute in parallel. + +Parallel adapters are similar to adapters (described earlier), except for the +following: + +1. RequestExceptions are never thrown from a parallel adapter. Error handling + for parallel transfers is handled through event listeners that use ``error`` + events. + +2. Parallel adapters are not expected to return responses. Because parallel + adapters can, in theory, send an infinite number of requests, developers + must use event listeners to receive the ``complete`` event and handle + responses accordingly. + +Emitting Lifecycle Events +------------------------- + +Request lifecycle events MUST be emitted by adapters and parallel adapters. +These lifecycle events are used by event listeners to modify requests, modify +responses, perform validation, and anything else required by an application. + +Emitting request lifecycle events in an adapter is much simpler if you use the +static helper method of ``GuzzleHttp\Event\RequestEvents``. These methods are +used by the built-in in curl and stream wrapper adapters of Guzzle, so you +should use them too. + +Example Adapter +=============== + +Here's a really simple example of creating a custom HTTP adapter. For +simplicity, this example uses a magic ``send_request()`` function. + +.. code-block:: php + + messageFactory = $messageFactory; + } + + public function send(TransactionInterface $transaction) + { + RequestEvents::emitBefore($transaction); + + // Check if the transaction was intercepted + if (!$transaction->getResponse()) { + // It wasn't intercepted, so send the request + $this->getResponse($transaction); + } + + // Adapters always return a response in the successful case. + return $transaction->getResponse(); + } + + private function getResponse(TransactionInterface $transaction) + { + $request = $transaction->getRequest(); + + $response = send_request( + $request->getMethod(), + $request->getUrl(), + $request->getHeaders(), + $request->getBody() + ); + + if ($response) { + $this->processResponse($response, $transaction); + } else { + // Emit the error event which allows listeners to intercept + // the error with a valid response. If it is not intercepted, + // a RequestException is thrown. + RequestEvents::emitError($transaction, $e); + } + } + + private function processResponse( + array $response, + TransactionInterface $transaction + ) { + // Process the response, create a Guzzle Response object, and + // associate the response with the transaction. + $responseObject = $this->messageFactory->createResponse( + $response['status_code'], + $response['headers'] + ); + + $transaction->setResponse($responseObject); + + // Emit the headers event before downloading the body + RequestEvents::emitHeaders($transaction); + + if ($response['body']) { + // Assuming the response body is a stream or something, + // associate it with the response object. + $responseObject->setBody(Stream::factory($response['body'])); + } + + // Emit the complete event + RequestEvents::emitComplete($transaction); + } + } diff --git a/core/vendor/guzzlehttp/guzzle/docs/clients.rst b/core/vendor/guzzlehttp/guzzle/docs/clients.rst new file mode 100644 index 00000000000..d1943d1de27 --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/docs/clients.rst @@ -0,0 +1,1081 @@ +======= +Clients +======= + +Clients are used to create requests, create transactions, send requests +through an HTTP adapter, and return a response. You can add default request +options to a client that are applied to every request (e.g., default headers, +default query string parameters, etc), and you can add event listeners and +subscribers to every request created by a client. + +Creating a client +================= + +The constructor of a client accepts an associative array of configuration +options. + +base_url + Configures a base URL for the client so that requests created + using a relative URL are combined with the ``base_url`` of the client + according to section `5.2 of RFC 3986 `_. + + .. code-block:: php + + // Create a client with a base URL + $client = new GuzzleHttp\Client(['base_url' => 'https://github.com']); + // Send a request to https://github.com/notifications + $response = $client->get('/notifications'); + + `Absolute URLs `_ sent + through a client will not use the base URL of the client. + +adapter + Configures the HTTP adapter (``GuzzleHttp\Adapter\AdapterInterface``) used + to transfer the HTTP requests of a client. Guzzle will, by default, utilize + a stacked adapter that chooses the best adapter to use based on the provided + request options and based on the extensions available in the environment. If + cURL is installed, it will be used as the default adapter. However, if a + request has the ``stream`` request option, the PHP stream wrapper adapter + will be used (assuming ``allow_url_fopen`` is enabled in your PHP + environment). + +parallel_adapter + Just like the ``adapter`` option, you can choose to specify an adapter + that is used to send requests in parallel + (``GuzzleHttp\Adapter\ParallelAdapterInterface``). Guzzle will by default + use cURL to send requests in parallel, but if cURL is not available it will + use the PHP stream wrapper and simply send requests serially. + +message_factory + Specifies the factory used to create HTTP requests and responses + (``GuzzleHttp\Message\MessageFactoryInterface``). + +defaults + Associative array of :ref:`request-options` that are applied to every + request created by the client. This allows you to specify things like + default headers (e.g., User-Agent), default query string parameters, SSL + configurations, and any other supported request options. + +Here's an example of creating a client with various options, including using +a mock adapter that just returns the result of a callable function and a +base URL that is a URI template with parameters. + +.. code-block:: php + + use GuzzleHttp\Client; + + $client = new Client([ + 'base_url' => ['https://api.twitter.com/{version}', ['version' => 'v1.1']], + 'defaults' => [ + 'headers' => ['Foo' => 'Bar'], + 'query' => ['testing' => '123'], + 'auth' => ['username', 'password'], + 'proxy' => 'tcp://localhost:80' + ] + ]); + +Sending Requests +================ + +Requests can be created using various methods of a client. You can create +**and** send requests using one of the following methods: + +- ``GuzzleHttp\Client::get``: Sends a GET request. +- ``GuzzleHttp\Client::head``: Sends a HEAD request +- ``GuzzleHttp\Client::post``: Sends a POST request +- ``GuzzleHttp\Client::put``: Sends a PUT request +- ``GuzzleHttp\Client::delete``: Sends a DELETE request +- ``GuzzleHttp\Client::options``: Sends an OPTIONS request + +Each of the above methods accepts a URL as the first argument and an optional +associative array of :ref:`request-options` as the second argument. + +.. code-block:: php + + $client = new GuzzleHttp\Client(); + + $client->put('http://httpbin.org', [ + 'headers' => ['X-Foo' => 'Bar'], + 'body' => 'this is the body!', + 'save_to' => '/path/to/local/file', + 'allow_redirects' => false, + 'timeout' => 5 + ]); + +Error Handling +-------------- + +When a recoverable error is encountered while calling the ``send()`` method of +a client, a ``GuzzleHttp\Exception\RequestException`` is thrown. + +.. code-block:: php + + use GuzzleHttp\Client; + use GuzzleHttp\Exception\RequestException; + + $client = new Client(); + + try { + $client->get('http://httpbin.org'); + } catch (RequestException $e) { + echo $e->getRequest() . "\n"; + if ($e->hasResponse()) { + echo $e->getResponse() . "\n"; + } + } + +``GuzzleHttp\Exception\RequestException`` always contains a +``GuzzleHttp\Message\RequestInterface`` object that can be accessed using the +exception's ``getRequest()`` method. + +A response might be present in the exception. In the event of a networking +error, no response will be received. You can check if a ``RequestException`` +has a response using the ``hasResponse()`` method. If the exception has a +response, then you can access the associated +``GuzzleHttp\Message\ResponseInterface`` using the ``getResponse()`` method of +the exception. + +HTTP Errors +~~~~~~~~~~~ + +If the ``exceptions`` request option is not set to ``false``, then exceptions +are thrown for HTTP protocol errors as well: +``GuzzleHttp\Exception\ClientErrorResponseException`` for 4xx level HTTP +responses and ``GuzzleHttp\Exception\ServerException`` for 5xx level responses, +both of which extend from ``GuzzleHttp\Exception\BadResponseException``. + +Creating Requests +----------------- + +You can create a request without sending it. This is useful for building up +requests over time or sending requests in parallel. + +.. code-block:: php + + $request = $client->createRequest('GET', 'http://httpbin.org', [ + 'headers' => ['X-Foo' => 'Bar'] + ]); + + // Modify the request as needed + $request->setHeader('Baz', 'bar'); + +After creating a request, you can send it with the client's ``send()`` method. + +.. code-block:: php + + $response = $client->send($request); + +Sending Requests in Parallel +============================ + +You can send requests in parallel using a client object's ``sendAll()`` method. +The ``sendAll()`` method accepts an array or ``\Iterator`` that contains +``GuzzleHttp\Message\RequestInterface`` objects. In addition to providing the +requests to send, you can also specify an associative array of options that +will affect the transfer. + +.. code-block:: php + + $requests = [ + $client->createRequest('GET', 'http://httpbin.org'), + $client->createRequest('DELETE', 'http://httpbin.org/delete'), + $client->createRequest('PUT', 'http://httpbin.org/put', ['body' => 'test']) + ]; + + $client->sendAll($requests); + +The ``sendAll()`` method accepts the following associative array of options: + +- **parallel**: Integer representing the maximum number of requests that are + allowed to be sent in parallel. +- **before**: Callable or array representing the event listeners to add to + each request's :ref:`before_event` event. +- **complete**: Callable or array representing the event listeners to add to + each request's :ref:`complete_event` event. +- **error**: Callable or array representing the event listeners to add to + each request's :ref:`error_event` event. + +The "before", "complete", and "error" event options accept a callable or an +array of associative arrays where each associative array contains a "fn" key +with a callable value, an optional "priority" key representing the event +priority (with a default value is 0), and an optional "once" key that can be +set to true so that the event listener will be removed from the request after +it is first triggered. + +.. code-block:: php + + use GuzzleHttp\Event\CompleteEvent; + + // Add a single event listener using a callable. + $client->sendAll($requests, [ + 'complete' => function (CompleteEvent $event) { + echo 'Completed request to ' . $event->getRequest()->getUrl() . "\n"; + echo 'Response: ' . $event->getResponse()->getBody() . "\n\n"; + } + ]); + + // The above is equivalent to the following, but the following structure + // allows you to add multiple event listeners to the same event name. + $client->sendAll($requests, [ + 'complete' => [ + [ + 'fn' => function (CompleteEvent $event) { /* ... */ }, + 'priority' => 0, // Optional + 'once' => false // Optional + ] + ] + ]); + +Asynchronous Response Handling +------------------------------ + +When sending requests in parallel, the request/response/error lifecycle must be +handled asynchronously. This means that you give the ``sendAll()`` method +multiple requests and handle the response or errors that is associated with the +request using event callbacks. + +.. code-block:: php + + use GuzzleHttp\Event\ErrorEvent; + + $client->sendAll($requests, [ + 'complete' => function (CompleteEvent $event) { + echo 'Completed request to ' . $event->getRequest()->getUrl() . "\n"; + echo 'Response: ' . $event->getResponse()->getBody() . "\n\n"; + // Do something with the completion of the request... + }, + 'error' => function (ErrorEvent $event) { + echo 'Request failed: ' . $event->getRequest()->getUrl() . "\n" + echo $event->getException(); + // Do something to handle the error... + } + ]); + +The ``GuzzleHttp\Event\ErrorEvent`` event object is emitted when an error +occurs during a transfer. With this event, you have access to the request that +was sent, the response that was received (if one was received), access to +transfer statistics, and the ability to intercept the exception with a +different ``GuzzleHttp\Message\ResponseInterface`` object. See :doc:`events` +for more information. + +Handling Errors After Transferring +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +It sometimes might be easier to handle all of the errors that occurred during a +transfer after all of the requests have been sent. Here we are adding each +failed request to an array that we can use to process errors later. + +.. code-block:: php + + use GuzzleHttp\Event\ErrorEvent; + + $errors = []; + $client->sendAll($requests, [ + 'error' => function (ErrorEvent $event) use (&$errors) { + $errors[] = $event; + } + ]); + + foreach ($errors as $error) { + // Handle the error... + } + +Throwing Errors Immediately +~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +It sometimes is useful to throw exceptions immediately when the occur. The +following exmaple shows how to use an event listener to throw exceptions +immeditaley and prevent subsequent requests from being sent. + +.. code-block:: php + + use GuzzleHttp\Event\ErrorEvent; + + $client->sendAll($requests, [ + 'error' => function (ErrorEvent $event) use (&$errors) { + throw $event->getException(); + } + ]); + +.. _request-options: + +Batching Requests +----------------- + +Sometimes you just want to send a few requests in parallel and then process +the results all at once after they've sent. Guzzle provides a convenience +function ``GuzzleHttp\batch()`` that makes this very simple: + +.. code-block:: php + + $client = new GuzzleHttp\Client(); + + $requests = [ + $client->createRequest('GET', 'http://httpbin.org/get'), + $client->createRequest('HEAD', 'http://httpbin.org/get'), + $client->createRequest('PUT', 'http://httpbin.org/put'), + ]; + + $results = GuzzleHttp\batch($client, $requests); + + // Results is an SplObjectStorage object where each request is a key + foreach ($results as $request) { + echo $request->getUrl() . "\n"; + // Get the result (either a ResponseInterface or RequestException) + $result = $results[$request]; + if ($result instanceof ResponseInterface) { + // Interact with the response directly + echo $result->getStatusCode(); + } else { + // Get the exception message + echo $result->getMessage(); + } + } + +``GuzzleHttp\batch()`` accepts an optional associative array of options in the +third argument that allows you to specify the 'before', 'complete' and 'error' +events as well as specify the maximum number of request to send in parallel +using the 'parallel' option key. This options array is the exact same format as +the options array exposed in ``GuzzleHttp\ClientInterface::sendAll()``. + +Request Options +=============== + +You can customize requests created by a client using **request options**. +Request options control various aspects of a request including, headers, +query string parameters, timeout settings, the body of a request, and much +more. + +All of the following examples use the following client: + +.. code-block:: php + + $client = new GuzzleHttp\Client(['base_url' => 'http://httpbin.org']); + +headers +------- + +:Summary: Associative array of headers to add to the request. Each key is the + name of a header, and each value is a string or array of strings + representing the header field values. +:Types: array +:Defaults: None + +.. code-block:: php + + // Set various headers on a request + $client->get('/get', [ + 'headers' => [ + 'User-Agent' => 'testing/1.0', + 'Accept' => 'application/json', + 'X-Foo' => ['Bar', 'Baz'] + ] + ]); + +body +---- + +:Summary: The ``body`` option is used to control the body of an entity + enclosing request (e.g., PUT, POST, PATCH). +:Types: + - string + - ``fopen()`` resource + - ``GuzzleHttp\Stream\StreamInterface`` + - ``GuzzleHttp\Post\PostBodyInterface`` +:Default: None + +This setting can be set to any of the following types: + +- string + + .. code-block:: php + + // You can send requests that use a string as the message body. + $client->put('/put', ['body' => 'foo']); + +- resource returned from ``fopen()`` + + .. code-block:: php + + // You can send requests that use a stream resource as the body. + $resource = fopen('http://httpbin.org', 'r'); + $client->put('/put', ['body' => $resource]); + +- Array + + Use an array to send POST style requests that use a + ``GuzzleHttp\Post\PostBodyInterface`` object as the body. + + .. code-block:: php + + // You can send requests that use a POST body containing fields & files. + $client->post('/post', [ + 'body' => [ + 'field' => 'abc', + 'other_field' => '123', + 'file_name' => fopen('/path/to/file', 'r') + ] + ]); + +- ``GuzzleHttp\Stream\StreamInterface`` + + .. code-block:: php + + // You can send requests that use a Guzzle stream object as the body + $stream = GuzzleHttp\Stream\Stream::factory('contents...'); + $client->post('/post', ['body' => $stream]); + +query +----- + +:Summary: Associative array of query string values to add to the request. +:Types: + - array + - ``GuzzleHttp\Query`` +:Default: None + +.. code-block:: php + + // Send a GET request to /get?foo=bar + $client->get('/get', ['query' => ['foo' => 'bar']); + +Query strings specified in the ``query`` option are combined with any query +string values that are parsed from the URL. + +.. code-block:: php + + // Send a GET request to /get?abc=123&foo=bar + $client->get('/get?abc=123', ['query' => ['foo' => 'bar']); + +auth +---- + +:Summary: 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. +:Types: + - array + - string + - null +:Default: None + +The built-in authentication types are as follows: + +basic + Use `basic HTTP authentication `_ in + the ``Authorization`` header (the default setting used if none is + specified). + + .. code-block:: php + + $client->get('/get', ['auth' => ['username', 'password']]); + +digest + Use `digest authentication `_ (must be + supported by the HTTP adapter). + + .. code-block:: php + + $client->get('/get', ['auth' => ['username', 'password', 'digest']]); + + *This is currently only supported when using the cURL adapter, but creating + a replacement that can be used with any HTTP adapter is planned.* + +.. important:: + + The authentication type (whether it's provided as a string or as the third + option in an array) is always converted to a lowercase string. Take this + into account when implementing custom authentication types and when + implementing custom message factories. + +Custom Authentication Schemes +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +You can also provide a string representing a custom authentication type name. +When using a custom authentication type string, you will need to implement +the authentication method in an event listener that checks the ``auth`` request +option of a request before it is sent. Authentication listeners that require +a request is not modified after they are signed should have a very low priority +to ensure that they are fired last or near last in the event chain. + +.. code-block:: php + + use GuzzleHttp\Event\BeforeEvent; + use GuzzleHttp\Event\RequestEvents; + + /** + * Custom authentication listener that handles the "foo" auth type. + * + * Listens to the "before" event of a request and only modifies the request + * when the "auth" config setting of the request is "foo". + */ + class FooAuth implements GuzzleHttp\Common\SubscriberInterface + { + private $password; + + public function __construct($password) + { + $this->password = $password; + } + + public function getEvents() + { + return ['before' => ['sign', RequestEvents::SIGN_REQUEST]]; + } + + public function sign(BeforeEvent $e) + { + if ($e->getRequest()->getConfig()['auth'] == 'foo') { + $e->getRequest()->setHeader('X-Foo', 'Foo ' . $this->password); + } + } + } + + $client->getEmitter->attach(new FooAuth('password')); + $client->get('/', ['auth' => 'foo']); + +Adapter Specific Authentication Schemes +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +If you need to use authentication methods provided by cURL (e.g., NTLM, GSS, +etc...), then you need to specify a curl adapter option in the ``options`` +request option array. See :ref:`config-option` for more information. + +.. _cookies-option: + +cookies +------- + +:Summary: Specifies whether or not cookies are used in a request or what cookie + jar to use or what cookies to send. +:Types: + - bool + - array + - ``GuzzleHttp\Cookie\CookieJarInterface`` +:Default: None + +Set to ``true`` to use a shared cookie session associated with the client. + +.. code-block:: php + + // Enable cookies using the shared cookie jar of the client. + $client->get('/get', ['cookies' => true]); + +Pass an associative array containing cookies to send in the request and start a +new cookie session. + +.. code-block:: php + + // Enable cookies and send specific cookies + $client->get('/get', ['cookies' => ['foo' => 'bar']]); + +Set to a ``GuzzleHttp\Cookie\CookieJarInterface`` object to use an existing +cookie jar. + +.. code-block:: php + + $jar = new GuzzleHttp\Cookie\CookieJar(); + $client->get('/get', ['cookies' => $jar]); + +.. _allow_redirects-option: + +allow_redirects +--------------- + +:Summary: Describes the redirect behavior of a request +:Types: + - bool + - array +:Default: ``['max' => 5, 'strict' => false, 'referer' => true]`` + +Set to ``false`` to disable redirects. + +.. code-block:: php + + $res = $client->get('/redirect/3', ['allow_redirects' => false]); + echo $res->getStatusCode(); + // 302 + +Set to ``true`` (the default setting) to enable normal redirects with a maximum +number of 5 redirects. + +.. code-block:: php + + $res = $client->get('/redirect/3'); + echo $res->getStatusCode(); + // 200 + +Pass an associative array containing the 'max' key to specify the maximum +number of redirects, 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), and optionally provide a 'referer' key to +specify whether or not the "Referer" header should be added when redirecting. + +.. code-block:: php + + $res = $client->get('/redirect/3', [ + 'allow_redirects' => [ + 'max' => 10, + 'strict' => true, + 'referer' => true + ] + ]); + echo $res->getStatusCode(); + // 200 + +.. _save_to-option: + +save_to +------- + +:Summary: Specify where the body of a response will be saved. +:Types: + - string + - ``fopen()`` resource + - ``GuzzleHttp\Stream\StreamInterface`` +:Default: PHP temp stream + +Pass a string to specify the path to a file that will store the contents of the +response body: + +.. code-block:: php + + $client->get('/stream/20', ['save_to' => '/path/to/file']); + +Pass a resource returned from ``fopen()`` to write the response to a PHP stream: + +.. code-block:: php + + $resource = fopen('/path/to/file', 'w'); + $client->get('/stream/20', ['save_to' => $resource]); + +Pass a ``GuzzleHttp\Stream\StreamInterface`` object to stream the response body +to an open Guzzle stream: + +.. code-block:: php + + $resource = fopen('/path/to/file', 'w'); + $stream = GuzzleHttp\Stream\Stream::factory($resource); + $client->get('/stream/20', ['save_to' => $stream]); + +.. _events-option: + +events +------ + +:Summary: Associative array mapping event names to a callable. or an + associative array containing the 'fn' key that maps to a callable, an + optional 'priority' key used to specify the event priority, and an optional + 'once' key used to specify if the event should remove itself the first time + it is triggered. +:Types: array +:Default: None + +.. code-block:: php + + use GuzzleHttp\Event\BeforeEvent; + use GuzzleHttp\Event\HeadersEvent; + use GuzzleHttp\Event\CompleteEvent; + use GuzzleHttp\Event\ErrorEvent; + + $client->get('/', [ + 'events' => [ + 'before' => function (BeforeEvent $e) { echo 'Before'; }, + 'headers' => function (HeadersEvent $e) { echo 'Headers'; }, + 'complete' => function (CompleteEvent $e) { echo 'Complete'; }, + 'error' => function (ErrorEvent $e) { echo 'Error'; }, + ] + ]); + +Here's an example of using the associative array format for control over the +priority and whether or not an event should be triggered more than once. + +.. code-block:: php + + $client->get('/', [ + 'events' => [ + 'before' => [ + 'fn' => function (BeforeEvent $e) { echo 'Before'; }, + 'priority' => 100, + 'once' => true + ] + ] + ]); + +.. _subscribers-option: + +subscribers +----------- + +:Summary: Array of event subscribers to add to the request. Each value in the + array must be an instance of ``GuzzleHttp\Event\SubscriberInterface``. +:Types: array +:Default: None + +.. code-block:: php + + use GuzzleHttp\Subscriber\History; + use GuzzleHttp\Subscriber\Mock; + use GuzzleHttp\Message\Response; + + $history = new History(); + $mock = new Mock([new Response(200)]); + $client->get('/', ['subscribers' => [$history, $mock]]); + + echo $history; + // Outputs the request and response history + +.. _exceptions-option: + +exceptions +---------- + +:Summary: Set to ``false`` to disable throwing exceptions on an HTTP protocol + errors (i.e., 4xx and 5xx responses). Exceptions are thrown by default when + HTTP protocol errors are encountered. +:Types: bool +:Default: ``true`` + +.. code-block:: php + + $client->get('/status/500'); + // Throws a GuzzleHttp\Exception\ServerException + + $res = $client->get('/status/500', ['exceptions' => false]); + echo $res->getStatusCode(); + // 500 + +.. _timeout-option: + +timeout +------- + +:Summary: Float describing the timeout of the request in seconds. Use ``0`` + to wait indefinitely (the default behavior). +:Types: float +:Default: ``0`` + +.. code-block:: php + + // Timeout if a server does not return a response in 3.14 seconds. + $client->get('/delay/5', ['timeout' => 3.14]); + // PHP Fatal error: Uncaught exception 'GuzzleHttp\Exception\RequestException' + +.. _connect_timeout-option: + +connect_timeout +--------------- + +:Summary: Float describing the number of seconds to wait while trying to connect + to a server. Use ``0`` to wait indefinitely (the default behavior). +:Types: float +:Default: ``0`` + +.. code-block:: php + + // Timeout if the client fails to connect to the server in 3.14 seconds. + $client->get('/delay/5', ['connect_timeout' => 3.14]); + +.. note:: + + This setting must be supported by the HTTP adapter used to send a request. + ``connect_timeout`` is currently only supported by the built-in cURL + adapter. + +.. _verify-option: + +verify +------ + +:Summary: Describes the SSL certificate verification behavior of a request. + Set to ``true`` to enable SSL certificate verification (the default). Set + to ``false`` to disable certificate verification (this is insecure!). Set + to a string to provide the path to a CA bundle to enable verification using + a custom certificate. +:Types: + - bool + - string +:Default: ``true`` + +.. code-block:: php + + // Use a custom SSL certificate + $client->get('/', ['verify' => '/path/to/cert.pem']); + + // Disable validation + $client->get('/', ['verify' => false]); + +.. _cert-option: + +cert +---- + +:Summary: Set to a string to specify the path to a file containing a PEM + formatted client side certificate. If a password is required, then set to + an array containing the path to the PEM file in the first array element + followed by the password required for the certificate in the second array + element. +:Types: + - string + - array +:Default: None + +.. code-block:: php + + $client->get('/', ['cert' => ['/path/server.pem', 'password']]); + +.. _ssl_key-option: + +ssl_key +------- + +:Summary: 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. +:Types: + - string + - array +:Default: None + +.. note:: + + ``ssl_key`` is implemented by HTTP adapters. This is currently only + supported by the cURL adapter, but might be supported by other third-part + adapters. + +.. _proxy-option: + +proxy +----- + +:Summary: Pass a string to specify an HTTP proxy, or an array to specify + different proxies for different protocols. +:Types: + - string + - array +:Default: None + +Pass a string to specify a proxy for all protocols. + +.. code-block:: php + + $client->get('/', ['proxy' => 'tcp://localhost:8124']); + +Pass an associative array to specify HTTP proxies for specific URI schemes +(i.e., "http", "https"). + +.. code-block:: php + + $client->get('/', [ + 'proxy' => [ + 'http' => 'tcp://localhost:8124', // Use this proxy with "http" + 'https' => 'tcp://localhost:9124' // Use this proxy with "https" + ] + ]); + +.. note:: + + You can provide proxy URLs that contain a scheme, username, and password. + For example, ``"http://username:password@192.168.16.1:10"``. + +.. _debug-option: + +debug +----- + +:Summary: Set to ``true`` or set to a PHP stream returned by ``fopen()`` to + enable debug output with the adapter used to send a request. For example, + when using cURL to transfer requests, cURL's verbose of ``CURLOPT_VERBOSE`` + will be emitted. When using the PHP stream wrapper, stream wrapper + notifications will be emitted. If set to true, the output is written to + PHP's STDOUT. If a PHP stream is provided, output is written to the stream. +:Types: + - bool + - ``fopen()`` resource +:Default: None + +.. code-block:: php + + $client->get('/get', ['debug' => true]); + +Running the above example would output something like the following: + +:: + + * About to connect() to httpbin.org port 80 (#0) + * Trying 107.21.213.98... * Connected to httpbin.org (107.21.213.98) port 80 (#0) + > GET /get HTTP/1.1 + Host: httpbin.org + User-Agent: Guzzle/4.0 curl/7.21.4 PHP/5.5.7 + + < HTTP/1.1 200 OK + < Access-Control-Allow-Origin: * + < Content-Type: application/json + < Date: Sun, 16 Feb 2014 06:50:09 GMT + < Server: gunicorn/0.17.4 + < Content-Length: 335 + < Connection: keep-alive + < + * Connection #0 to host httpbin.org left intact + +.. _stream-option: + +stream +------ + +:Summary: Set to ``true`` to stream a response rather than download it all + up-front. +:Types: bool +:Default: ``false`` + +.. code-block:: php + + $response = $client->get('/stream/20', ['stream' => true]); + // Read bytes off of the stream until the end of the stream is reached + $body = $response->getBody(); + while (!$body->eof()) { + echo $body->read(1024); + } + +.. note:: + + Streaming response support must be implemented by the HTTP adapter used by + a client. This option might not be supported by every HTTP adapter, but the + interface of the response object remains the same regardless of whether or + not it is supported by the adapter. + +.. _expect-option: + +expect +------ + +:Summary: Controls the behavior of the "Expect: 100-Continue" header. +:Types: + - bool + - integer +:Default: ``1048576`` + +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. + +.. note:: + + This option only takes effect when using HTTP/1.1. The HTTP/1.0 and + HTTP/2.0 protocols do not support the "Expect: 100-Continue" header. + Support for handling the "Expect: 100-Continue" workflow must be + implemented by Guzzle HTTP adapters used by a client. + +.. _version-option: + +version +------- + +:Summary: Protocol version to use with the request. +:Types: string, float +:Default: ``1.1`` + +.. code-block:: php + + // Force HTTP/1.0 + $request = $client->createRequest('GET', '/get', ['version' => 1.0]); + echo $request->getProtocolVersion(); + // 1.0 + +.. _config-option: + +config +------ + +:Summary: Associative array of config options that are forwarded to a request's + configuration collection. These values are used as configuration options + that can be consumed by plugins and adapters. +:Types: array +:Default: None + +.. code-block:: php + + $request = $client->createRequest('GET', '/get', ['config' => ['foo' => 'bar']]); + echo $request->getConfig('foo'); + // 'bar' + +Some HTTP adapters allow you to specify custom adapter-specific settings. For +example, you can pass custom cURL options to requests by passing an associative +array in the ``config`` request option under the ``curl`` key. + +.. code-block:: php + + // Use custom cURL options with the request. This example uses NTLM auth + // to authenticate with a server. + $client->get('/', [ + 'config' => [ + 'curl' => [ + CURLOPT_HTTPAUTH => CURLAUTH_NTLM, + CURLOPT_USERPWD => 'username:password' + ] + ] + ]); + +Event Subscribers +================= + +Requests emit lifecycle events when they are transferred. A client object has a +``GuzzleHttp\Common\EventEmitter`` object that can be used to add event +*listeners* and event *subscribers* to all requests created by the client. + +.. important:: + + **Every** event listener or subscriber added to a client will be added to + every request created by the client. + +.. code-block:: php + + use GuzzleHttp\Client; + use GuzzleHttp\Event\BeforeEvent; + + $client = new Client(); + + // Add a listener that will echo out requests before they are sent + $client->getEmitter()->on('before', function (BeforeEvent $e) { + echo 'About to send request: ' . $e->getRequest(); + }); + + $client->get('http://httpbin.org/get'); + // Outputs the request as a string because of the event + +See :doc:`events` for more information on the event system used in Guzzle. + +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 ``GuzzleHttp\Adapter\Curl\MultiAdapter`` + will use when selecting 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. +``HTTPS_PROXY`` + Defines the proxy to use when sending requests using the "https": protocol. + +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 diff --git a/core/vendor/guzzlehttp/guzzle/docs/conf.py b/core/vendor/guzzlehttp/guzzle/docs/conf.py new file mode 100644 index 00000000000..c787faca402 --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/docs/conf.py @@ -0,0 +1,93 @@ +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' + +# -- General configuration ----------------------------------------------------- + +extensions = [] +templates_path = ['_templates'] +source_suffix = '.rst' +master_doc = 'index' + +project = u'Guzzle' +copyright = u'2012, Michael Dowling' +version = '3.0.0' +release = '3.0.0' + +exclude_patterns = ['_build'] + +# -- Options for HTML output --------------------------------------------------- + +# The name for this set of Sphinx documents. If None, it defaults to +# " v documentation". +html_title = "Guzzle documentation" +html_short_title = "Guzzle" + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + +# Custom sidebar templates, maps document names to template names. +html_sidebars = { + '**': ['localtoc.html', 'searchbox.html'] +} + +# Output file base name for HTML help builder. +htmlhelp_basename = 'Guzzledoc' + +# -- Guzzle Sphinx theme setup ------------------------------------------------ + +sys.path.insert(0, '/Users/dowling/projects/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' + +# Guzzle theme options (see theme.conf for more information) +html_theme_options = { + "project_nav_name": "Guzzle", + "github_user": "guzzle", + "github_repo": "guzzle", + "disqus_comments_shortname": "guzzle", + "google_analytics_account": "UA-22752917-1" +} + +# -- Options for LaTeX output -------------------------------------------------- + +latex_elements = {} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, author, documentclass [howto/manual]). +latex_documents = [ + ('index', 'Guzzle.tex', u'Guzzle Documentation', + u'Michael Dowling', 'manual'), +] + +# -- Options for manual page output -------------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + ('index', 'guzzle', u'Guzzle Documentation', + [u'Michael Dowling'], 1) +] + +# If true, show URL addresses after external links. +#man_show_urls = False + +# -- Options for Texinfo output ------------------------------------------------ + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + ('index', 'Guzzle', u'Guzzle Documentation', + u'Michael Dowling', 'Guzzle', 'One line description of project.', + 'Miscellaneous'), +] diff --git a/core/vendor/guzzlehttp/guzzle/docs/events.rst b/core/vendor/guzzlehttp/guzzle/docs/events.rst new file mode 100644 index 00000000000..77800087e21 --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/docs/events.rst @@ -0,0 +1,479 @@ +============ +Event System +============ + +Guzzle uses an event emitter to allow you to easily extend the behavior of a +request, change the response associated with a request, and implement custom +error handling. All events in Guzzle are managed and emitted by an +**event emitter**. + +Event Emitters +============== + +Clients, requests, and any other class that implements the +``GuzzleHttp\Common\HasEmitterInterface`` interface have a +``GuzzleHttp\Common\EventEmitter`` object. You can add event *listeners* and +event *subscribers* to an event *emitter*. + +emitter + An object that implements ``GuzzleHttp\Common\EventEmitterInterface``. This + object emits named events to event listeners. You may register event + listeners on subscribers on an emitter. + +event listeners + Callable functions that are registered on an event emitter for specific + events. Event listeners are registered on an emitter with a *priority* + setting. If no priority is provided, ``0`` is used by default. + +event subscribers + Classes that tell an event emitter what methods to listen to and what + functions on the class to invoke when the event is triggered. Event + subscribers subscribe event listeners to an event emitter. They should be + used when creating more complex event based logic in applications (i.e., + cookie handling is implemented using an event subscriber because it's + easier to share a subscriber than an anonymous function and because + handling cookies is a complex process). + +priority + Describes the order in which event listeners are invoked when an event is + emitted. The higher a priority value, the earlier the event listener will + be invoked (a higher priority means the listener is more important). If + no priority is provided, the priority is assumed to be ``0``. + + When specifying an event priority, you can pass ``"first"`` or ``"last"`` to + dynamically specify the priority based on the current event priorities + associated with the given event name in the emitter. Use ``"first"`` to set + the priority to the current highest priority plus one. Use ``"last"`` to + set the priority to the current lowest event priority minus one. It is + important to remember that these dynamic priorities are calculated only at + the point of insertion into the emitter and they are not rearranged after + subsequent listeners are added to an emitter. + +propagation + Describes whether or not other event listeners are triggered. Event + emitters will trigger every event listener registered to a specific event + in priority order until all of the listeners have been triggered **or** + until the propagation of an event is stopped. + +Getting an EventEmitter +----------------------- + +You can get the event emitter of ``GuzzleHttp\Common\HasEmitterInterface`` +object using the the ``getEmitter()`` method. Here's an example of getting a +client object's event emitter. + +.. code-block:: php + + $client = new GuzzleHttp\Client(); + $emitter = $client->getEmitter(); + +.. note:: + + You'll notice that the event emitter used in Guzzle is very similar to the + `Symfony2 EventDispatcher component `_. + This is because the Guzzle event system is based on the Symfony2 event + system with several changes. Guzzle uses its own event emitter to improve + performance, isolate Guzzle from changes to the Symfony, and provide a few + improvements that make it easier to use for an HTTP client (e.g., the + addition of the ``once()`` method). + +Adding Event Listeners +---------------------- + +After you have the emitter, you can register event listeners that listen to +specific events using the ``on()`` method. When registering an event listener, +you must tell the emitter what event to listen to (e.g., "before", "after", +"headers", "complete", "error", etc...), what callable to invoke when the +event is triggered, and optionally provide a priority. + +.. code-block:: php + + use GuzzleHttp\Event\BeforeEvent; + + $emitter->on('before', function (BeforeEvent $event) { + echo $event->getRequest(); + }); + +When a listener is triggered, it is passed an event that implements the +``GuzzleHttp\Common\EventInterface`` interface, the name of the event, and the +event emitter itself. The above example could more verbosely be written as +follows: + +.. code-block:: php + + use GuzzleHttp\Event\BeforeEvent; + + $emitter->on('before', function ( + BeforeEvent $event, + $name, + EmitterInterface $emitter + ) { + echo $event->getRequest(); + }); + +You can add an event listener that automatically removes itself after it is +triggered using the ``once()`` method of an event emitter. + +.. code-block:: php + + $client = new GuzzleHttp\Client(); + $client->getEmitter()->once('before', function () { + echo 'This will only happen once... per request!'; + }); + +Event Propagation +----------------- + +Event listeners can prevent other event listeners from being triggered by +stopping an event's propagation. + +Stopping event propagation can be useful, for example, if an event listener has +changed the state of the subject to such an extent that allowing subsequent +event listeners to be triggered could place the subject in an inconsistent +state. This technique is used in Guzzle extensively when intercepting error +events with responses. + +You can stop the propagation of an event using the ``stopPropagation()`` method +of a ``GuzzleHttp\Common\EventInterface`` object: + +.. code-block:: php + + use GuzzleHttp\Event\ErrorEvent; + + $emitter->on('error', function (ErrorEvent $event) { + $event->stopPropagation(); + }); + +After stopping the propagation of an event, any subsequent event listeners that +have not yet been trigger will not be triggered. You can check to see if the +propagation of an event was stopped using the ``isPropagationStopped()`` method +of the event. + +.. code-block:: php + + $client = new GuzzleHttp\Client(); + $emitter = $client->getEmitter(); + // Note: assume that the $errorEvent was created + if ($emitter->emit('error', $errorEvent)->isPropagationStopped()) { + echo 'It was stopped!'; + } + +.. hint:: + + When emitting events, the event that was emitted is returned from the + emitter. This allows you to easily chain calls as shown in the above + example. + +Event Subscribers +----------------- + +Event subscribers are classes that implement the +``GuzzleHttp\Common\EventSubscriberInterface`` object. They are used to register +one or more event listeners to methods of the class. Event subscribers tell +event emitters exactly which events to listen to and what method to invoke on +the class when the event is triggered by called the ``getEvents()`` method of +a subscriber. + +The following example registers event listeners to the ``before`` and +``complete`` event of a request. When the ``before`` event is emitted, the +``onBefore`` instance method of the subscriber is invoked. When the +``complete`` event is emitted, the ``onComplete`` event of the subscriber is +invoked. Each array value in the ``getEvents()`` return value MUST +contain the name of the method to invoke and can optionally contain the +priority of the listener (as shown in the ``before`` listener in the example). + +.. code-block:: php + + use GuzzleHttp\Event\EventEmitterInterface; + use GuzzleHttp\Event\SubscriberInterface; + use GuzzleHttp\Event\BeforeEvent; + use GuzzleHttp\Event\CompleteEvent; + + class SimpleSubscriber implements SubscriberInterface + { + public function getEvents() + { + return [ + 'before' => ['onBefore', 100], // Provide name and optional priority + 'complete' => ['onComplete'] + ]; + } + + public function onBefore(BeforeEvent $event, $name, EmitterInterface $emitter) + { + echo 'Before!'; + } + + public function onComplete(CompleteEvent $event, $name, EmitterInterface $emitter) + { + echo 'Complete!'; + } + } + +.. note:: + + You can specify event priorities using integers or ``"first"`` and + ``"last"`` to dynamically determine the priority. + +Event Priorities +================ + +When adding event listeners or subscribers, you can provide an optional event +priority. This priority is used to determine how early or late a listener is +triggered. Specifying the correct priority is an important aspect of ensuring +a listener behaves as expected. For example, if you wanted to ensure that +cookies associated with a redirect were added to a cookie jar, you'd need to +make sure that the listener that collects the cookies is triggered before the +listener that performs the redirect. + +In order to help make the process of determining the correct event priority of +a listener easier, Guzzle provides several pre-determined named event +priorities. These priorities are exposed as constants on the +``GuzzleHttp\Event\RequestEvents`` object. + +last + Use ``"last"`` as an event priority to set the priority to the current + lowest event priority minus one. + +first + Use ``"first"`` as an event priority to set the priority to the current + highest priority plus one. + +``GuzzleHttp\Event\RequestEvents::EARLY`` + Used when you want a listener to be triggered as early as possible in the + event chain. + +``GuzzleHttp\Event\RequestEvents::LATE`` + Used when you want a listener to be to be triggered as late as possible in + the event chain. + +``GuzzleHttp\Event\RequestEvents::PREPARE_REQUEST`` + Used when you want a listener to be trigger while a request is being + prepared during the ``before`` event. This event priority is used by the + ``GuzzleHttp\Subscriber\Prepare`` event subscriber which is responsible for + guessing a Content-Type, Content-Length, and Expect header of a request. + You should subscribe after this event is triggered if you want to ensure + that this subscriber has already been triggered. + +``GuzzleHttp\Event\RequestEvents::SIGN_REQUEST`` + Used when you want a listener to be triggered when a request is about to be + signed. Any listener triggered at this point should expect that the request + object will no longer be mutated. If you are implementing a custom + signature subscriber, then you should use this event priority to sign + requests. + +``GuzzleHttp\Event\RequestEvents::VERIFY_RESPONSE`` + Used when you want a listener to be triggered when a response is being + validated during the ``complete`` event. The + ``GuzzleHttp\Subscriber\HttpError`` event subscriber uses this event + priority to check if an exception should be thrown due to a 4xx or 5xx + level response status code. If you are doing any kind of verification of a + response during the complete event, it should happen at this priority. + +``GuzzleHttp\Event\RequestEvents::REDIRECT_RESPONSE`` + Used when you want a listener to be triggered when a response is being + redirected during the ``complete`` event. The + ``GuzzleHttp\Subscriber\Redirect`` event subscriber uses this event + priority when performing redirects. + +You can use the above event priorities as a guideline for determining the +priority of you event listeners. You can use these constants and add to or +subtract from them to ensure that a listener happens before or after the named +priority. + +.. note:: + + "first" and "last" priorities are not adjusted after they added to an + emitter. For example, if you add a listener with a priority of "first", + you can still add subsequent listeners with a higher priority which would + be triggered before the listener added with a priority of "first". + +Working With Request Events +=========================== + +Requests emit lifecycle events when they are transferred. + +.. important:: + + Request lifecycle events may be triggered multiple times due to redirects, + retries, or reusing a request multiple times. Use the ``once()`` method + of an event emitter if you only want the event to be triggered once. You + can also remove an event listener from an emitter by using the emitter the + is provided to the listener. + +.. _before_event: + +before +------ + +The ``before`` event is emitted before a request is sent. The event emitted is +a ``GuzzleHttp\Event\BeforeEvent``. + +.. code-block:: php + + use GuzzleHttp\Client; + use GuzzleHttp\Common\EmitterInterface; + use GuzzleHttp\Event\BeforeEvent; + + $client = new Client(['base_url' => 'http://httpbin.org']); + $request = $client->createRequest('GET', '/'); + $request->getEmitter()->on( + 'before', + function (BeforeEvent $e, $name, EmitterInterface $emitter) { + echo $name . "\n"; + // "before" + echo $e->getRequest()->getMethod() . "\n"; + // "GET" / "POST" / "PUT" / etc... + echo get_class($e->getClient()); + // "GuzzleHttp\Client" + } + ); + +You can intercept a request with a response before the request is sent over the +wire. The ``intercept()`` method of the ``BeforeEvent`` accepts a +``GuzzleHttp\Message\ResponseInterface``. Intercepting the event will prevent +the request from being sent over the wire and stops the propagation of the +``before`` event, preventing subsequent event listeners from being invoked. + +.. code-block:: php + + use GuzzleHttp\Client; + use GuzzleHttp\Event\BeforeEvent; + use GuzzleHttp\Message\Response; + + $client = new Client(['base_url' => 'http://httpbin.org']); + $request = $client->createRequest('GET', '/status/500'); + $request->getEmitter()->on('before', function (BeforeEvent $e) { + $response = new Response(200); + $e->intercept($response); + }); + + $response = $client->send($request); + echo $response->getStatusCode(); + // 200 + +.. attention:: + + Any exception encountered while executing the ``before`` event will trigger + the ``error`` event of a request. + +.. _headers_event: + +headers +------- + +The ``headers`` event is emitted after the headers of a response have been +received before any of the response body has been downloaded. The event +emitted is a ``GuzzleHttp\Event\HeadersEvent``. + +This event can be useful if you need to conditionally wrap the response body +of a request in a special decorator or if you only want to conditionally +download a response body based on response headers. + +This event cannot be intercepted. + +.. code-block:: php + + use GuzzleHttp\Client; + use GuzzleHttp\Event\HeadersEvent; + + $client = new Client(['base_url' => 'http://httpbin.org']); + $request = $client->createRequest('GET', '/stream/100'); + $request->getEmitter()->on('headers', function (HeadersEvent $e) { + echo $e->getResponse(); + // Prints the response headers + + // Wrap the response body in a custom decorator if the response has a body + if ($e->getResponse()->getHeader('Content-Length') || + $e->getResponse()->getHeader('Content-Encoding') + ) { + $customBody = new MyCustomStreamDecorator($e->getResponse()->getBody()); + $e->getResponse()->setBody($customBody); + } + }); + +.. note:: + + A response may or may not yet have a body associated with it. If a request + used a ``save_to`` request option, then the response will have a body. + Otherwise, the response will have no body but you are free to associate one + with the response. As an example, this is done in the + `progress subscriber `_. + +.. _complete_event: + +complete +-------- + +The ``complete`` event is emitted after a transaction completes and an entire +response has been received. The event is a ``GuzzleHttp\Event\CompleteEvent``. + +You can intercept the ``complete`` event with a different response if needed +using the ``intercept()`` method of the event. This can be useful, for example, +for changing the response for caching. + +.. code-block:: php + + use GuzzleHttp\Client; + use GuzzleHttp\Event\CompleteEvent; + use GuzzleHttp\Message\Response; + + $client = new Client(['base_url' => 'http://httpbin.org']); + $request = $client->createRequest('GET', '/status/302'); + $cachedResponse = new Response(200); + + $request->getEmitter()->on( + 'complete', + function (CompleteEvent $e) use ($cachedResponse) { + if ($e->getResponse()->getStatusCode() == 302) { + // Intercept the original transaction with the new response + $e->intercept($cachedResponse); + } + } + ); + + $response = $client->send($request); + echo $response->getStatusCode(); + // 200 + +.. attention:: + + Any ``GuzzleHttp\Exception\RequestException`` encountered while executing + the ``complete`` event will trigger the ``error`` event of a request. + +.. _error_event: + +error +----- + +The ``error`` event is emitted when a request fails (whether it's from a +networking error or an HTTP protocol error). The event emitted is a +``GuzzleHttp\Event\ErrorEvent``. + +This event is useful for retrying failed requests. Here's an example of +retrying failed basic auth requests by re-sending the original request with +a username and password. + +.. code-block:: php + + use GuzzleHttp\Client; + use GuzzleHttp\Event\ErrorEvent; + + $client = new Client(['base_url' => 'http://httpbin.org']); + $request = $client->createRequest('GET', '/basic-auth/foo/bar'); + $request->getEmitter()->on('error', function (ErrorEvent $e) { + if ($e->getResponse()->getStatusCode() == 401) { + // Add authentication stuff as needed and retry the request + $e->getRequest()->setHeader('Authorization', 'Basic ' . base64_encode('foo:bar')); + // Get the client of the event and retry the request + $newResponse = $e->getClient()->send($e->getRequest()); + // Intercept the original transaction with the new response + $e->intercept($newResponse); + } + }); + +.. attention:: + + If an ``error`` event is intercepted with a response, then the ``complete`` + event of a request is triggered. If the ``complete`` event fails, then the + ``error`` event is triggered once again. diff --git a/core/vendor/guzzlehttp/guzzle/docs/faq.rst b/core/vendor/guzzlehttp/guzzle/docs/faq.rst new file mode 100644 index 00000000000..8ad7c460a28 --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/docs/faq.rst @@ -0,0 +1,111 @@ +=== +FAQ +=== + +Is it possible to use Guzzle 3 and 4 in the same project? +========================================================= + +Yes, because Guzzle 3 and 4 use different Packagist packages and different +namespaced. You simply need to add ``guzzle/guzzle`` (Guzzle 3) and +``guzzlehttp/guzzle`` (Guzzle 4+) to your project's composer.json file. + +.. code-block:: javascript + + { + "require": { + "guzzle/guzzle": 3.*, + "guzzlehttp/guzzle": 4.* + } + } + +You might need to use Guzzle 3 and Guzzle 4 in the same project due to a +requirement of a legacy application or a dependency that has not yet migrated +to Guzzle 4.0. + +How do I migrate from Guzzle 3 to 4? +==================================== + +See https://github.com/guzzle/guzzle/blob/master/UPGRADING.md#3x-to-40. + +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 + +[`source `_] + +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->put('/', [], 'the body', [ + 'expect' => false + ]); + + // Disable the expect header on all client requests + $client->setDefaultOption('expect', false) + +How can I add custom cURL options? +================================== + +cURL offer a huge number of `customizable options `_. +While Guzzle normalizes many of these options across different adapters, 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 the +**config** request option. + +For example, let's say you need to customize the outgoing network interface +used with a client. + +.. code-block:: php + + $client->get('/', [ + 'config' => [ + 'curl' => [ + CURLOPT_INTERFACE => 'xxx.xxx.xxx.xxx' + ] + ] + ]); + +How can I add custom stream context options? +============================================ + +You can pass custom `stream context options `_ +using the **stream_context** key of the **config** 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->get('/', [ + 'stream' => true, + 'config' => [ + 'stream_context' => [ + 'ssl' => [ + 'allow_self_signed' => true + ], + 'socket' => [ + 'bindto' => 'xxx.xxx.xxx.xxx' + ] + ] + ] + ]); diff --git a/core/vendor/guzzlehttp/guzzle/docs/http-messages.rst b/core/vendor/guzzlehttp/guzzle/docs/http-messages.rst new file mode 100644 index 00000000000..1ccf3949033 --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/docs/http-messages.rst @@ -0,0 +1,480 @@ +============================= +Request and Response Messages +============================= + +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. + +Headers +======= + +Both request and response messages contain HTTP headers. + +Complex Headers +--------------- + +Some headers contain additional key value pair information. For example, Link +headers contain a link and several key value pairs: + +:: + + ; 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\Message\Request; + + $request = new Request('GET', '/', [ + 'Link' => '; rel="front"; type="image/jpeg"' + ]); + + $parsed = Request::parseHeader($request, 'Link'); + echo json_encode($parsed, JSON_PRETTY_PRINT); + +:: + + [ + { + "0": "", + "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. + +See :ref:`headers` for information on how the headers of a request and response +can be accessed and modified. + +Body +==== + +Both request and response messages can contain a body. + +You can check to see if a request or response has a body using the +``getBody()`` method: + +.. code-block:: php + + $response = GuzzleHttp\get('http://httpbin.org/get'); + if ($response->getBody()) { + echo $response->getBody(); + // JSON string: { ... } + } + +The body used in request and response objects is a +``GuzzleHttp\Stream\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 a 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). + +You can change the body used in a request or response using the ``setBody()`` +method: + +.. code-block:: php + + use GuzzleHttp\Stream\Stream; + $request = $client->createRequest('PUT', 'http://httpbin.org/put'); + $request->setBody(Stream::factory('foo')); + +The easiest way to create a body for a request is using the static +``GuzzleHttp\Stream\Stream::factory()`` method. This method accepts various +inputs like strings, resources returned from ``fopen()``, and other +``GuzzleHttp\Stream\StreamInterface`` objects. + +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; + $request = $client->createRequest('PUT', 'http://httpbin.org/put', ['body' => 'testing...']); + + echo $request->getBody()->read(4); + // test + echo $request->getBody()->read(4); + // ing. + echo $request->getBody()->read(1024); + // .. + var_export($request->eof()); + // true + +You can find out more about Guzzle stream objects in :doc:`streams`. + +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. + +Clients are used to create request messages. More precisely, clients use +a ``GuzzleHttp\Message\MessageFactoryInterface`` to create request messages. +You create requests with a client using the ``createRequest()`` method. + +.. code-block:: php + + // Create a request but don't sent it immediately + $request = $client->createRequest('GET', 'http://httpbin.org/get'); + +Request Methods +--------------- + +When creating a request, you are expected to provide the HTTP method you wish +to perform. You can specfiy any method you'd like, including a custom method +that might not be part of RFC 2616 (like "MOVE"). + +.. code-block:: php + + // Create a request using a completely custom HTTP method + $request = $client->createRequest('MOVE', 'http://httpbin.org/move', ['exceptions' => false]); + + echo $request->getMethod(); + // MOVE + + $response = $client->send($request); + echo $response->getStatusCode(); + // 405 + +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 **/])`` + +.. code-block:: php + + $response = $client->patch('http://httpbin.org/patch', ['body' => 'content']); + +Request URI +----------- + +The resource you are requesting with an HTTP request is identified by the +path of the request, the query string, and the "Host" header of the request. + +When creating a request, you can provide the entire resource URI as a URL. + +.. code-block:: php + + $response = $client->get('http://httbin.org/get?q=foo'); + +Using the above code, you will send a request that uses ``httpbin.org`` as +the Host header, sends the request over port 80, uses ``/get`` as the path, +and sends ``?q=foo`` as the query string. All of this is parsed automatically +from the provided URI. + +Sometimes you don't know what the entire request will be when it is created. +In these cases, you can modify the request as needed before sending it using +the ``createRequest()`` method of the client and methods on the request that +allow you to change it. + +.. code-block:: php + + $request = $client->createRequest('GET', 'http://httbin.org'); + +You can change the path of the request using ``setPath()``: + +.. code-block:: php + + $request->setPath('/get'); + echo $request->getPath(); + // /get + echo $request->getUrl(); + // http://httpbin.com/get + +Scheme +~~~~~~ + +The `scheme `_ of a request +specifies the protocol to use when sending the request. When using Guzzle, the +scheme can be set to "http" or "https". + +You can change the scheme of the request using the ``setScheme()`` method: + +.. code-block:: php + + $request = $client->createRequest('GET', 'http://httbin.org'); + $request->setScheme('https'); + echo $request->getScheme(); + // https + echo $request->getUrl(); + // https://httpbin.com/get + +Port +~~~~ + +No port is necessary when using the "http" or "https" schemes, but you can +override the port using ``setPort()``. If you need to modify the port used with +the specified scheme from the default setting, then you must use the +``setPort()`` method. + +.. code-block:: php + + $request = $client->createRequest('GET', 'http://httbin.org'); + $request->setPort(8080); + echo $request->getPort(); + // 8080 + echo $request->getUrl(); + // https://httpbin.com:8080/get + + // Set the port back to the default value for the scheme + $request->setPort(443); + echo $request->getUrl(); + // https://httpbin.com/get + +Query string +~~~~~~~~~~~~ + +You can get the query string of the request using the ``getQuery()`` method. +This method returns a ``GuzzleHttp\Query`` object. A Query object can be +accessed like a PHP array, iterated in a foreach statement like a PHP array, +and cast to a string. + +.. code-block:: php + + $request = $client->createRequest('GET', 'http://httbin.org'); + $query = $request->getQuery(); + $query['foo'] = 'bar'; + $query['baz'] = 'bam'; + $query['bam'] = ['test' => 'abc']; + + echo $request->getQuery(); + // foo=bar&baz=bam&bam%5Btest%5D=abc + + echo $request->getQuery()['foo']; + // bar + echo $request->getQuery()->get('foo'); + // bar + echo $request->getQuery()->get('foo'); + // bar + + var_export($request->getQuery()['bam']); + // array('test' => 'abc') + + foreach ($query as $key => $value) { + var_export($value); + } + + echo $request->getUrl(); + // https://httpbin.com/get?foo=bar&baz=bam&bam%5Btest%5D=abc + +Query Aggregators +^^^^^^^^^^^^^^^^^ + +Query objects can store scalar values or arrays of values. When an array of +values is added to a query object, the query object uses a query aggregator to +convert the complex structure into a string. Query objects will use +`PHP style query strings `_ when complex +query string parameters are converted to a string. You can customize how +complex query string parameters are aggregated using the ``setAggregator()`` +method of a query string object. + +.. code-block:: php + + $query->setAggregator($query::duplicateAggregator()); + +In the above example, we've changed the query object to use the +"duplicateAggregator". This aggregator will allow duplicate entries to appear +in a query string rather than appending "[n]" to each value. So if you had a +query string with ``['a' => ['b', 'c']]``, the duplicate aggregator would +convert this to "a=b&a=c" while the default aggregator would convert this to +"a[0]=b&a[1]=c" (with urlencoded brackets). + +The ``setAggregator()`` method accepts a ``callable`` which is used to convert +a deeply nested array of query string variables into a flattened array of key +value pairs. The callable accepts an array of query data and returns a +flattened array of key value pairs where each value is an array of strings. +You can use the ``GuzzleHttp\Query::walkQuery()`` static function to easily +create custom query aggregators. + +Host +~~~~ + +You can change the host header of the request in a predictable way using the +``setHost()`` method of a request: + +.. code-block:: php + + $request->setHost('www.google.com'); + echo $request->getHost(); + // www.google.com + echo $request->getUrl(); + // https://www.google.com/get?foo=bar&baz=bam + +.. note:: + + The Host header can also be changed by modifying the Host header of a + request directly, but modifying the Host header directly could result in + sending a request to a different Host than what is specified in the Host + header (sometimes this is actually the desired behavior). + +Resource +~~~~~~~~ + +You can use the ``getResource()`` method of a request to return the path and +query string of a request in a single string. + +.. code-block:: php + + $request = $client->createRequest('GET', 'http://httpbin.org/get?baz=bar'); + echo $request->getResource(); + // /get?baz=bar + +Request Config +-------------- + +Request messages contain a configuration collection that can be used by +event listeners and HTTP adapters to modify how a request behaves or is +transferred over the wire. For example, many of the request options that are +specified when creating a request are actually set as config options that are +only acted upon by adapters and listeners when the request is sent. + +You can get access to the request's config object using the ``getConfig()`` +method of a request. + +.. code-block:: php + + $request = $client->createRequest('GET', '/'); + $config = $request->getConfig(); + +The config object is a ``GuzzleHttp\Common\Collection`` object that acts like +an associative array. You can grab values from the collection using array like +access. You can also modify and remove values using array like access. + +.. code-block:: php + + $config['foo'] = 'bar'; + echo $config['foo']; + // bar + + var_export(isset($config['foo'])); + // true + + unset($config['foo']); + var_export(isset($config['foo'])); + // false + + var_export($config['foo']); + // NULL + +HTTP adapters and event listeners can expose additional customization options +through request config settings. For example, in order to specify custom cURL +options to the cURL adapter, you need to specify an associative array in the +``curl`` ``config`` request option. + +.. code-block:: php + + $client->get('/', [ + 'config' => [ + 'curl' => [ + CURLOPT_HTTPAUTH => CURLAUTH_NTLM, + CURLOPT_USERPWD => 'username:password' + ] + ] + ]); + +Consult the HTTP adapters and event listeners you are using to see if they +allow customization through request configuration options. + +Event Emitter +------------- + +Request objects implement ``GuzzleHttp\Common\HasEmitterInterface``, so they +have a method called ``getEmitter()`` that can be used to get an event emitter +used by the request. Any listener or subscriber attached to a request will only +be triggered for the lifecycle events of a specific request. Conversely, adding +an event listener or subscriber to a client will listen to all lifecycle events +of all requests created by the client. + +See :doc:`events` for more information. + +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 + + $response = GuzzleHttp\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 + + if ($body = $response->getBody()) { + echo $body; + // Cast to a string: { ... } + $body->seek(0); + // Rewind the body + $body->read(1024); + // Read bytes of the body + } + +When working with JSON responses, you can use the ``json()`` method of a +response: + +.. code-block:: php + + $json = $response->json(); + +.. note:: + + Guzzle uses the ``json_decode()`` method of PHP and uses arrays rather than + ``stdClass`` objects for objects. + +You can use the ``xml()`` method when working with XML data. + +.. code-block:: php + + $xml = $response->xml(); + +.. note:: + + Guzzle uses the ``SimpleXMLElement`` objects when converting response + bodies to XML. + +Effective URL +------------- + +The URL that was ultimately accessed that returned a response can be accessed +using the ``getEffectiveUrl()`` method of a response. This method will return +the URL of a reqeust or the URL of the last redirected URL if any redirects +occurred while transferring a request. + +.. code-block:: php + + $response = GuzzleHttp\get('http://httpbin.org/get'); + echo $response->getEffectiveUrl(); + // http://httpbin.org/get + + $response = GuzzleHttp\get('http://httpbin.org/redirect-to?url=http://www.google.com'); + echo $response->getEffectiveUrl(); + // http://www.google.com diff --git a/core/vendor/guzzlehttp/guzzle/docs/index.rst b/core/vendor/guzzlehttp/guzzle/docs/index.rst new file mode 100644 index 00000000000..c06e0bf3f31 --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/docs/index.rst @@ -0,0 +1,94 @@ +.. title:: Guzzle | PHP HTTP client and framework for consuming RESTful web services + +====== +Guzzle +====== + +Guzzle is a PHP HTTP client that makes it easy to work with HTTP/1.1 and takes +the pain out of consuming web services. + +- Pluggable HTTP adapters that can send requests serially or in parallel +- Doesn't require cURL, but uses cURL by default +- Streams data for both uploads and downloads +- Provides event hooks & plugins for cookies, caching, logging, OAuth, mocks, etc... +- Keep-Alive & connection pooling +- SSL Verification +- Automatic decompression of response bodies +- Streaming multipart file uploads +- Connection timeouts + +.. code-block:: php + + $client = new GuzzleHttp\Client(); + $response = $client->get('http://guzzlephp.org'); + $res = $client->get('https://api.github.com/user', ['auth' => ['user', 'pass']]); + echo $res->statusCode(); + // 200 + echo $res->getHeader('content-type'); + // 'application/json; charset=utf8' + echo $res->getBody(); + // {"type":"User"...' + var_export($res->json()); + // Outputs the JSON decoded data + +User guide +---------- + +.. toctree:: + :maxdepth: 2 + + overview + quickstart + clients + http-messages + events + streams + adapters + testing + faq + +HTTP Components +--------------- + +There are a number of optional libraries you can use along with Guzzle's HTTP +layer to add capabilities to the client. + +`Log Subscriber `_ + Logs HTTP requests and responses sent over the wire using customizable + log message templates. + +`OAuth Subscriber `_ + Signs requests using OAuth 1.0. + +`Progress Subscriber `_ + Emits progress events when uploading and downloading data. + +`Cache Subscriber `_ + Implements a private transparent proxy cache that caches HTTP responses. + +`Retry Subscriber `_ + Retries failed requests using customizable retry strategies (e.g., retry + based on response status code, cURL error codes, etc...) + +`Message Integrity Subscriber `_ + Verifies the message integrity of HTTP responses using customizable + validators. This plugin can be used, for example, to verify the Content-MD5 + headers of responses. + +Service Description Commands +---------------------------- + +You can use the **Guzzle Command** library to encapsulate interaction with a +web service using command objects. Building on top of Guzzle's command +abstraction allows you to easily implement things like service description that +can be used to serialize requests and parse responses using a meta-description +of a web service. + +`Guzzle Command `_ + Provides the foundational elements used to build high-level, command based, + web service clients with Guzzle. + +`Guzzle Services `_ + Provides an implementation of the *Guzzle Command* library that uses + Guzzle service descriptions to describe web services, serialize requests, + and parse responses into easy to use model structures. diff --git a/core/vendor/guzzlehttp/guzzle/docs/overview.rst b/core/vendor/guzzlehttp/guzzle/docs/overview.rst new file mode 100644 index 00000000000..35c74d86ce1 --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/docs/overview.rst @@ -0,0 +1,150 @@ +======== +Overview +======== + +Requirements +============ + +#. PHP 5.4.0 +#. To use the PHP stream adapter, ``allow_url_fopen`` must be enabled in your + system's php.ini. +#. To use the cURL adapter, you must have a recent version of cURL >= 7.16.2 + 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 adapter used to send requests. + +.. _installation: + +Installation +============ + +The recommended way to install Guzzle is with `Composer `_. 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:~4 + +Alternatively, you can specify Guzzle as a dependency in your project's +existing composer.json file: + +.. code-block:: js + + { + "require": { + "guzzlehttp/guzzle": "4.*" + } + } + +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 `_. + +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 ``dev-master``. + +.. code-block:: js + + { + "require": { + "guzzlehttp/guzzle": "dev-master" + } + } + +License +======= + +Licensed using the `MIT license `_. + + Copyright (c) 2014 Michael Dowling + + 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 follows PSR-0, PSR-1, and PSR-2. +2. Guzzle is meant to be lean and fast with very few dependencies. +3. Guzzle has a minimum PHP version requirement of PHP 5.4. Pull requests must + not require a PHP version greater than PHP 5.4. +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 vendored PHPUnit +binary: + +.. code-block:: bash + + vendor/bin/phpunit + +.. note:: + + You'll need to install node.js v0.5.0 or newer in order to perform + integration tests on Guzzle's HTTP adapters. + +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 `_. + +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. diff --git a/core/vendor/guzzlehttp/guzzle/docs/quickstart.rst b/core/vendor/guzzlehttp/guzzle/docs/quickstart.rst new file mode 100644 index 00000000000..51c7ba8d2bc --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/docs/quickstart.rst @@ -0,0 +1,454 @@ +========== +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. + +Make a Request +============== + +You can send requests with Guzzle in one of two ways: through the procedural +API or using a ``GuzzleHttp\ClientInterface`` object. Using the procedural API +is an easy way to send a quick HTTP request. Using a Client object provides +much more flexibility in how requests are transferred and allows you to more +easily test the client. + +Procedural API +-------------- + +Here's an example of sending a ``GET`` request using the procedural API. + +.. code-block:: php + + $response = GuzzleHttp\post('http://httpbin.org/post', [ + 'headers' => ['X-Foo' => 'Bar'], + 'body' => ['field_name' => 'value'] + ]); + +You can send all kinds of HTTP requests with the procedural API. Just call +the function that maps to the HTTP method name. + +.. code-block:: php + + $response = GuzzleHttp\head('http://httpbin.org/get'); + $response = GuzzleHttp\post('http://httpbin.org/post'); + $response = GuzzleHttp\put('http://httpbin.org/put'); + $response = GuzzleHttp\delete('http://httpbin.org/delete'); + $response = GuzzleHttp\options('http://httpbin.org/get'); + +Creating a Client +----------------- + +The procedural API is simple but not very testable; it's best left for quick +prototyping. If you want to use Guzzle in a more flexible and testable way, +then you'll need to use a ``GuzzleHttp\ClientInterface`` object. + +.. code-block:: php + + use GuzzleHttp\Client; + + $client = new Client(); + $response = $client->get('https://github.com/timeline.json'); + + // You can use the same methods you saw in the procedural API + $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 with a client and then send the request with the +client when you're ready. + +.. code-block:: php + + $request = $client->createRequest('GET', 'http://www.foo.com'); + $response = $client->send($request); + +Client objects provide a great deal of flexibility in how request are +transferred including default request options, subscribers that are attached +to each request, and a base URL that allows you to send requests with relative +URLs. You can find out all about clients in the :doc:`clients` page of the +documentation. + +Using Responses +=============== + +In the previous examples, we retrieved a ``$response`` variable. This value is +actually a ``GuzzleHttp\Message\ResponseInterface`` object 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 + +Response Body +------------- + +The body of a response can be retrieved and cast to a string. + +.. code-block:: php + + $body = $response->getBody(); + echo $body; + // { "some_json_data" ...} + +You can also read read bytes from body of a response like a stream. + +.. code-block:: php + + $body = $response->getBody(); + + while (!$body->eof()) { + echo $body->read(1024); + } + +JSON Responses +~~~~~~~~~~~~~~ + +You can more easily work with JSON responses using the ``json()`` method of a +response. + +.. code-block:: php + + $response = $client->get('https://github.com/timeline.json'); + $json = $response->json(); + var_dump($json[0]['repository']); + +Guzzle internally uses PHP's ``json_decode()`` function to parse responses. If +Guzzle is unable to parse the JSON response body, then a +``GuzzleHttp\Exception\ParseException`` is thrown. + +XML Responses +~~~~~~~~~~~~~ + +You can use a response's ``xml()`` method to more easily work with responses +that contain XML data. + +.. code-block:: php + + $response = $client->get('https://github.com/mtdowling.atom'); + $xml = $response->xml(); + echo $xml->id; + // tag:github.com,2008:/mtdowling + +Guzzle internally uses a ``SimpleXMLElement`` object to parse responses. If +Guzzle is unable to parse the XML response body, then a +``GuzzleHttp\Exception\ParseException`` is thrown. + +Query String Parameters +======================= + +Sending query string parameters with a request is easy. You can set query +string parameters in the request's URL. + +.. code-block:: php + + $response = $client->get('http://httpbin.org?foo=bar'); + +You can also specify the query string parameters using the ``query`` request +option. + +.. code-block:: php + + $client->get('http://httpbin.org', [ + 'query' => ['foo' => 'bar'] + ]); + +And finally, you can build up the query string of a request as needed by +calling the ``getQuery()`` method of a request and modifying the request's +``GuzzleHttp\Query`` object as needed. + +.. code-block:: php + + $request = $client->createRequest('GET', 'http://httpbin.org'); + $query = $request->getQuery(); + $query->set('foo', 'bar'); + + // You can use the query string object like an array + $query['baz'] = 'bam'; + + // The query object can be cast to a string + echo $query; + // foo=bar&baz=bam + + // Setting a value to false or null will cause the "=" sign to be omitted + $query['empty'] = null; + echo $query; + // foo=bar&baz=bam&empty + + // Use an empty string to include the "=" sign with an empty value + $query['empty'] = ''; + echo $query; + // foo=bar&baz=bam&empty= + +.. _headers: + +Request and Response Headers +---------------------------- + +You can specify request headers when sending or creating requests with a +client. In the following example, we send the ``X-Foo-Header`` with a value of +``value`` by setting the ``headers`` request option. + +.. code-block:: php + + $response = $client->get('http://httpbin.org/get', [ + 'headers' => ['X-Foo-Header' => 'value'] + ]); + +You can view the headers of a response using header specific methods of a +response class. Headers work exactly the same way for request and response +object. + +You can retrieve a header from a request or response using the ``getHeader()`` +method of the object. This method is case-insensitive and by default will +return a string containing the header field value. + +.. code-block:: php + + $response = $client->get('http://www.yahoo.com'); + $length = $response->getHeader('Content-Length'); + +Header fields that contain multiple values can be retrieved as a string or as +an array. Retrieving the field values as a string will naively concatenate all +of the header values together with a comma. Because not all header fields +should be represented this way (e.g., ``Set-Cookie``), you can pass an optional +flag to the ``getHeader()`` method to retrieve the header values as an array. + +.. code-block:: php + + $values = $response->getHeader('Set-Cookie', true); + foreach ($values as $value) { + echo $value; + } + +You can test if a request or response has a specific header using the +``hasHeader()`` method. This method accepts a case-insensitive string and +returns true if the header is present or false if it is not. + +You can retrieve all of the headers of a message using the ``getHeaders()`` +method of a request or response. The return value is an associative array where +the keys represent the header name as it will be sent over the wire, and each +value is an array of strings associated with the header. + +.. code-block:: php + + $headers = $response->getHeaders(); + foreach ($message->getHeaders() as $name => $values) { + echo $name . ": " . implode(", ", $values); + } + +Modifying headers +----------------- + +The headers of a message can be modified using the ``setHeader()``, +``addHeader()``, ``setHeaders()``, and ``removeHeader()`` methods of a request +or response object. + +.. code-block:: php + + $request = $client->createRequest('GET', 'http://httpbin.org/get'); + + // Set a single value for a header + $request->setHeader('User-Agent', 'Testing!'); + + // Set multiple values for a header in one call + $request->setHeader('X-Foo', ['Baz', 'Bar']); + + // Add a header to the message + $request->addHeader('X-Foo', 'Bam'); + + echo $request->getHeader('X-Foo'); + // Baz, Bar, Bam + + // Remove a specific header using a case-insensitive name + $request->removeHeader('x-foo'); + echo $request->getHeader('X-Foo'); + // Echoes an empty string: '' + +POST Requests +============= + +You can send POST requests that contain a raw POST body by passing a +string, resource returned from ``fopen``, or a +``GuzzleHttp\Stream\StreamInterface`` object to the ``body`` request option. + +.. code-block:: php + + $r = $client->post('http://httpbin.org/post', ['body' => 'raw data']); + +Sending POST Fields +------------------- + +Sending ``application/x-www-form-urlencoded`` POST requests requires that you +specify the body of a POST request as an array. + +.. code-block:: php + + $response = $client->post('http://httpbin.org/post', [ + 'body' => [ + 'field_name' => 'abc', + 'other_field' => '123' + ] + ]); + +You can also build up POST requests before sending them. + +.. code-block:: php + + $request = $client->createRequest('POST', 'http://httpbin.org/post'); + $postBody = $request->getBody(); + + // $postBody is an instance of GuzzleHttp\Post\PostBodyInterface + $postBody->setField('foo', 'bar'); + echo $postBody->getField('foo'); + // 'bar' + + echo json_encode($postBody->getFields()); + // {"foo": "bar"} + + // Send the POST request + $response = $client->send($request); + +Sending POST Files +------------------ + +Sending ``multipart/form-data`` POST requests (POST requests that contain +files) is the same as sending ``application/x-www-form-urlencoded``, except +some of the array values of the POST fields map to PHP ``fopen`` resources, or +``GuzzleHttp\Stream\StreamInterface``, or +``GuzzleHttp\Post\PostFileInterface`` objects. + +.. code-block:: php + + use GuzzleHttp\Post\PostFile; + + $response = $client->post('http://httpbin.org/post', [ + 'body' => [ + 'field_name' => 'abc', + 'file_filed' => fopen('/path/to/file', 'r'), + 'other_file' => new PostFile('other_file', 'this is the content') + ] + ]); + +Just like when sending POST fields, you can also build up POST requests with +files before sending them. + +.. code-block:: php + + use GuzzleHttp\Post\PostFile; + + $request = $client->createRequest('POST', 'http://httpbin.org/post'); + $postBody = $request->getBody(); + $postBody->setField('foo', 'bar'); + $postBody->addFile(new PostFile('test', fopen('/path/to/file', 'r'))); + $response = $client->send($request); + +Cookies +======= + +Guzzle can maintain a cookie session for you if instructed using the +``cookies`` request option. + +- Set to ``true`` to use a shared cookie session associated with the client. +- Pass an associative array containing cookies to send in the request and start + a new cookie session. +- Set to a ``GuzzleHttp\Subscriber\CookieJar\CookieJarInterface`` object to uss + an existing cookie jar. + +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->get('http://github.com'); + echo $response->getStatusCode(); + // 200 + echo $response->getEffectiveUrl(); + // 'https://github.com/' + +The following example shows that redirects can be disabled. + +.. code-block:: php + + $response = $client->get('http://github.com', ['allow_redirects' => false]); + echo $response->getStatusCode(); + // 301 + echo $response->getEffectiveUrl(); + // 'http://github.com/' + +Exceptions +========== + +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 + (non-parallel) requests. + + .. code-block:: php + + use GuzzleHttp\Exception\RequestException; + + try { + $client->get('https://github.com/_abc_123_404'); + } catch (RequestException $e) { + echo $e->getRequest(); + if ($e->hasResponse()) { + echo $e->getResponse(); + } + } + +- A ``GuzzleHttp\Exception\ClientErrorResponseException`` is thrown for 400 + level errors if the ``exceptions`` request option is not set to true. This + exception extends from ``GuzzleHttp\Exception\BadResponseException`` and + ``GuzzleHttp\Exception\BadResponseException`` extends from + ``GuzzleHttp\Exception\RequestException``. + + .. code-block:: php + + use GuzzleHttp\Exception\ClientErrorResponseException; + + try { + $client->get('https://github.com/_abc_123_404'); + } catch (ClientErrorResponseException $e) { + echo $e->getRequest(); + echo $e->getResponse(); + } + +- A ``GuzzleHttp\Exception\ServerErrorResponse`` is thrown for 500 level + errors if the ``exceptions`` request option is not 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 extends from + ``GuzzleHttp\Exception\RequestException``. +- A ``GuzzleHttp\Exception\AdapterException`` is thrown when an error occurs + in an HTTP adapter during a parallel request. This exception is only thrown + when using the ``sendAll()`` method of a client. + +All of the above exceptions extend from +``GuzzleHttp\Exception\TransferException``. diff --git a/core/vendor/guzzlehttp/guzzle/docs/requirements.txt b/core/vendor/guzzlehttp/guzzle/docs/requirements.txt new file mode 100644 index 00000000000..fe7a4eab465 --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/docs/requirements.txt @@ -0,0 +1,2 @@ +Sphinx>=1.2b1 +guzzle_sphinx_theme>=0.6.0 diff --git a/core/vendor/guzzlehttp/guzzle/docs/streams.rst b/core/vendor/guzzlehttp/guzzle/docs/streams.rst new file mode 100644 index 00000000000..c743e2c4bb4 --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/docs/streams.rst @@ -0,0 +1,227 @@ +======= +Streams +======= + +Guzzle uses 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. + +Guzzle's 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). + +Creating Streams +================ + +The best way to create a stream is using the +``GuzzleHttp\Stream\create()`` function. This function accepts strings, +resources returned from ``fopen()``, an object that implements +``__toString()``, and an object that implements +``GuzzleHttp\Stream\StreamInterface``. + +.. code-block:: php + + use GuzzleHttp\Stream; + + $stream = Stream\create('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 + +.. note:: + + You can use this ``create()`` function or use the static ``factory()`` + method of the ``GuzzleHttp\Stream\Stream`` class via + ``GuzzleHttp\Stream\Stream::factory()``. This static factory method has the + same method signature as the ``create()`` function. Actually, the static + factory method is just a convenience method for the ``create()`` function. + +Metadata Streams +================ + +Guzzle streams that implement ``GuzzleHttp\Stream\MetadataStreamInterface`` +expose stream metadata through the ``getMetadata()`` method. This method +provides the data you would retrieve when calling PHP's +`stream_get_meta_data() function `_. + +.. code-block:: php + + use GuzzleHttp\Stream; + + $resource = fopen('/path/to/file', 'r'); + $stream = Stream\create($resource); + echo $stream->getMetadata('uri'); + // /path/to/file + var_export($stream->isReadable()); + // true + var_export($stream->isWritable()); + // false + var_export($stream->isSeekable()); + // true + +.. note:: + + Streams created using ``GuzzleHttp\Stream\create()`` and + ``GuzzleHttp\Stream\Stream::factory()`` all implement + ``GuzzleHttp\Stream\MetadataStreamInterface``. + +Stream Decorators +================= + +With the small and focused interface, add custom functionality to streams is +very simple with stream decorators. Guzzle provides several built-in decorators +that provide additional stream functionality. + +CachingStream +------------- + +The CachingStream is used to allow seeking over previously read bytes on +non-seekable streams. This can be useful when transferring a non-seekable +entity body fails due to needing to rewind the stream (for example, resulting +from a redirect). Data that is read from the remote stream will be buffered in +a PHP temp stream so that previously read bytes are cached first in memory, +then on disk. + +.. code-block:: php + + use GuzzleHttp\Stream; + use GuzzleHttp\Stream\CachingStream; + + $original = Stream\create(fopen('http://www.google.com', 'r')); + $stream = new CachingStream($original); + + $stream->read(1024); + echo $stream->tell(); + // 1024 + + $stream->seek(0); + echo $stream->tell(); + // 0 + +LimitStream +----------- + +LimitStream can be used to read a subset or slice of an existing stream object. +This can be useful for breaking a large file into smaller pieces to be sent in +chunks (e.g. Amazon S3's multipart upload API). + +.. code-block:: php + + use GuzzleHttp\Stream; + use GuzzleHttp\Stream\LimitStream; + + $original = Stream\create(fopen('/tmp/test.txt', 'r+')); + echo $original->getSize(); + // >>> 1048576 + + // Limit the size of the body to 1024 bytes and start reading from byte 2048 + $stream = new LimitStream($original, 1024, 2048); + echo $stream->getSize(); + // >>> 1024 + echo $stream->tell(); + // >>> 0 + +NoSeekStream +------------ + +NoSeekStream wraps a stream and does not allow seeking. + +.. code-block:: php + + use GuzzleHttp\Stream; + use GuzzleHttp\Stream\LimitStream; + + $original = Stream\create('foo'); + $noSeek = new NoSeekStream($original); + + echo $noSeek->read(3); + // foo + var_export($noSeek->isSeekable()); + // false + $noSeek->seek(0); + var_export($noSeek->read(3)); + // NULL + +Creating Custom Decorators +-------------------------- + +Creating a stream decorator is very easy thanks to the +``GuzzleHttp\Stream\StreamDecoratorTrait``. This trait provides methods that +implement ``GuzzleHttp\Stream\StreamInterface`` by proxying to an underlying +stream. Just ``use`` the ``StreamDecoratorTrait`` and implement your custom +methods. + +For example, let's say we wanted to call a specific function each time the last +byte is read from a stream. This could be implemented by overriding the +``read()`` method. + +.. code-block:: php + + use GuzzleHttp\Stream\StreamDecoratorTrait; + + class EofCallbackStream implements StreamInterface, MetadataStreamInterface + { + use StreamDecoratorTrait; + + private $callback; + + public function __construct(StreamInterface $stream, callable $callback) + { + $this->stream = $stream; + $this->callback = $callback; + } + + public function read($length) + { + $result = $this->stream->read($length); + + // Invoke the callback when EOF is hit. + if ($this->eof()) { + call_user_func($this->callback); + } + + return $result; + } + } + +This decorator could be added to any existing stream and used like so: + +.. code-block:: php + + use GuzzleHttp\Stream; + + $original = Stream\create('foo'); + $eofStream = new EofCallbackStream($original, function () { + echo 'EOF!'; + }); + + $eofStream->read(2); + $eofStream->read(1); + // echoes "EOF!" + $eofStream->seek(0); + $eofStream->read(3); + // echoes "EOF!" diff --git a/core/vendor/guzzlehttp/guzzle/docs/testing.rst b/core/vendor/guzzlehttp/guzzle/docs/testing.rst new file mode 100644 index 00000000000..d67bd615c01 --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/docs/testing.rst @@ -0,0 +1,236 @@ +====================== +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 subscriber +* Mock adapter +* Node.js web server for integration testing + +Mock Subscriber +=============== + +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 subscriber that can be attached to clients or requests +that allows you to queue up a list of responses to use rather than hitting a +remote API. + +.. code-block:: php + + use GuzzleHttp\Client; + use GuzzleHttp\Subscriber\Mock; + use GuzzleHttp\Message\Response; + + $client = new Client(); + + // Create a mock subscriber and queue two responses. + $mock = new Mock([ + new Response(200, ['X-Foo' => 'Bar']), // Use response object + "HTTP/1.1 202 OKr\nContent-Length: 0\r\n\r\n" // Use a response string + ]); + + // Add the mock subscriber to the client. + $client->getEmitter()->attach($mock); + // The first request is intercepted with the first response. + echo $client->get('/')->getStatus(); + //> 200 + // The second request is intercepted with the second response. + echo $client->get('/')->getStatus(); + //> 202 + +When no more responses are in the queue and a request is sent, an +``OutOfBoundsException`` is thrown. + +History Subscriber +================== + +When using things like the ``Mock`` subscriber, you often need to know if the +requests you expected to send were sent exactly as you intended. While the mock +subscriber responds with mocked responses, the ``GuzzleHttp\Subscriber\History`` +subscriber maintains a history of the requests that were sent by a client. + +.. code-block:: php + + use GuzzleHttp\Client; + use GuzzleHttp\Subscriber\History; + + $client = new Client(); + $history = new History(); + + // Add the history subscriber to the client. + $client->getEmitter()->attach($history); + + $client->get('http://httpbin.org/get'); + $client->head('http://httpbin.org/get'); + + // Count the number of transactions + echo count($history); + //> 2 + // Get the last request + $lastRequest = $history->getLastRequest(); + // Get the last response + $lastRequest = $history->getLastResponse(); + + // Iterate over the transactions that were sent + foreach ($history as $transaction) { + echo $transaction['request']->getMethod(); + //> GET, HEAD + echo $transaction['response']->getStatusCode(); + //> 200, 200 + } + +The history subscriber can also be printed, revealing the requests and +responses that were sent as a string, in order. + +.. code-block:: php + + echo $history; + +:: + + > GET /get HTTP/1.1 + Host: httpbin.org + User-Agent: Guzzle/4.0-dev curl/7.21.4 PHP/5.5.8 + + < HTTP/1.1 200 OK + Access-Control-Allow-Origin: * + Content-Type: application/json + Date: Tue, 25 Mar 2014 03:53:27 GMT + Server: gunicorn/0.17.4 + Content-Length: 270 + Connection: keep-alive + + { + "headers": { + "Connection": "close", + "X-Request-Id": "3d0f7d5c-c937-4394-8248-2b8e03fcccdb", + "User-Agent": "Guzzle/4.0-dev curl/7.21.4 PHP/5.5.8", + "Host": "httpbin.org" + }, + "origin": "76.104.247.1", + "args": {}, + "url": "http://httpbin.org/get" + } + + > HEAD /get HTTP/1.1 + Host: httpbin.org + User-Agent: Guzzle/4.0-dev curl/7.21.4 PHP/5.5.8 + + < HTTP/1.1 200 OK + Access-Control-Allow-Origin: * + Content-length: 270 + Content-Type: application/json + Date: Tue, 25 Mar 2014 03:53:27 GMT + Server: gunicorn/0.17.4 + Connection: keep-alive + +Mock Adapter +============ + +In addition to using the Mock subscriber, you can use the +``GuzzleHttp\Adapter\MockAdapter`` as the adapter of a client to return the +same response over and over or return the result of a callable function. + +.. code-block:: php + + use GuzzleHttp\Client; + use GuzzleHttp\Adapter\MockAdapter; + use GuzzleHttp\Adapter\TransactionInterface; + use GuzzleHttp\Message\Response; + + $mockAdapter = new MockAdapter(function (TransactionInterface $trans) { + // You have access to the request + $request = $trans->getRequest(); + // Return a response + return new Response(200); + }); + + $client = new Client(['adapter' => $mockAdapter]); + +Test Web Server +=============== + +Using mock responses is usually enough when testing a web service client. When +implementing custom :doc:`HTTP adapters `, you'll need to send actual +HTTP requests in order to sufficiently test the adapter. 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 +--------------------- + +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. + +In order to use the web server, you'll need to manually require +``tests/Server.php``. Any operation on the ``Server`` object will ensure that +the server is running and wait until it is able to receive requets before +returning. + +.. code-block:: php + + // Require the test server (using something like this). + require __DIR__ . '/../vendor/guzzlehttp/guzzle/tests/Server.php'; + + use GuzzleHttp\Client; + use GuzzleHttp\Tests\Server; + + // Start the server and queue a response + Server::enqueue("HTTP/1.1 200 OK\r\n\Content-Length: 0r\n\r\n"); + + $client = new Client(['base_url' => Server::$url]); + echo $client->get('/foo')->getStatusCode(); + // 200 + +``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 a string representing an HTTP +response message, a ``GuzzleHttp\Message\ResponseInterface``, or an array of +HTTP message strings / ``GuzzleHttp\Message\ResponseInterface`` objects. + +.. code-block:: php + + // Queue single response + Server::enqueue("HTTP/1.1 200 OK\r\n\Content-Length: 0r\n\r\n"); + + // Clear the queue and queue an array of responses + Server::enqueue([ + "HTTP/1.1 200 OK\r\n\Content-Length: 0r\n\r\n", + "HTTP/1.1 404 Not Found\r\n\Content-Length: 0r\n\r\n" + ]); + +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()``. This method accepts an optional ``$hydrate`` parameter +that specifies if you are retrieving an array of HTTP requests as strings or an +array of ``GuzzleHttp\Message\RequestInterface`` objects. + +.. code-block:: php + + foreach (Server::received() as $response) { + echo $response; + } + +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 diff --git a/core/vendor/guzzlehttp/guzzle/phpunit.xml.dist b/core/vendor/guzzlehttp/guzzle/phpunit.xml.dist new file mode 100644 index 00000000000..d75d0ba878b --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/phpunit.xml.dist @@ -0,0 +1,14 @@ + + + + + tests + + + + + src + + + diff --git a/core/vendor/guzzlehttp/guzzle/src/Adapter/AdapterInterface.php b/core/vendor/guzzlehttp/guzzle/src/Adapter/AdapterInterface.php new file mode 100644 index 00000000000..f3c035e2b46 --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/src/Adapter/AdapterInterface.php @@ -0,0 +1,23 @@ +multi = $multiHandle; + $this->handles = new \SplObjectStorage(); + $this->throwsExceptions = $throwsExceptions; + $this->pending = $pending; + } + + /** + * Find a transaction for a given curl handle + * + * @param resource $handle Curl handle + * + * @return TransactionInterface + * @throws AdapterException if a transaction is not found + */ + public function findTransaction($handle) + { + foreach ($this->handles as $transaction) { + if ($this->handles[$transaction] === $handle) { + return $transaction; + } + } + + throw new AdapterException('No curl handle was found'); + } + + /** + * Returns true if there are any remaining pending transactions + * + * @return bool + */ + public function hasPending() + { + return $this->pending && $this->pending->valid(); + } + + /** + * Pop the next transaction from the transaction queue + * + * @return TransactionInterface|null + */ + public function nextPending() + { + if (!$this->hasPending()) { + return null; + } + + $current = $this->pending->current(); + $this->pending->next(); + + return $current; + } + + /** + * Checks if the batch is to throw exceptions on error + * + * @return bool + */ + public function throwsExceptions() + { + return $this->throwsExceptions; + } + + /** + * Get the curl_multi handle + * + * @return resource + */ + public function getMultiHandle() + { + return $this->multi; + } + + /** + * Add a transaction to the multi handle + * + * @param TransactionInterface $transaction Transaction to add + * @param resource $handle Resource to use with the handle + * + * @throws AdapterException If the handle is already registered + */ + public function addTransaction(TransactionInterface $transaction, $handle) + { + if (isset($this->handles[$transaction])) { + throw new AdapterException('Transaction already registered'); + } + + $code = curl_multi_add_handle($this->multi, $handle); + if ($code != CURLM_OK) { + CurlAdapter::throwMultiError($code); + } + + $this->handles[$transaction] = $handle; + } + + /** + * Remove a transaction and associated handle from the context + * + * @param TransactionInterface $transaction Transaction to remove + * + * @return array Returns the curl_getinfo array + * @throws AdapterException if the transaction is not found + */ + public function removeTransaction(TransactionInterface $transaction) + { + if (!isset($this->handles[$transaction])) { + throw new AdapterException('Transaction not registered'); + } + + $handle = $this->handles[$transaction]; + + $code = curl_multi_remove_handle($this->multi, $handle); + if ($code != CURLM_OK) { + CurlAdapter::throwMultiError($code); + } + + $info = curl_getinfo($handle); + curl_close($handle); + unset($this->handles[$transaction]); + + return $info; + } +} diff --git a/core/vendor/guzzlehttp/guzzle/src/Adapter/Curl/CurlAdapter.php b/core/vendor/guzzlehttp/guzzle/src/Adapter/Curl/CurlAdapter.php new file mode 100644 index 00000000000..0f120353171 --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/src/Adapter/Curl/CurlAdapter.php @@ -0,0 +1,142 @@ +handles = $this->ownedHandles = []; + $this->messageFactory = $messageFactory; + $this->curlFactory = isset($options['handle_factory']) + ? $options['handle_factory'] + : new CurlFactory(); + $this->maxHandles = isset($options['max_handles']) + ? $options['max_handles'] + : 5; + } + + public function __destruct() + { + foreach ($this->handles as $handle) { + if (is_resource($handle)) { + curl_close($handle); + } + } + } + + public function send(TransactionInterface $transaction) + { + RequestEvents::emitBefore($transaction); + if ($response = $transaction->getResponse()) { + return $response; + } + + $factory = $this->curlFactory; + $handle = $factory( + $transaction, + $this->messageFactory, + $this->checkoutEasyHandle() + ); + + curl_exec($handle); + $info = curl_getinfo($handle); + $info['curl_result'] = curl_errno($handle); + + if ($info['curl_result']) { + $this->handleError($transaction, $info, $handle); + } else { + $this->releaseEasyHandle($handle); + RequestEvents::emitComplete($transaction, $info); + } + + return $transaction->getResponse(); + } + + private function handleError( + TransactionInterface $transaction, + $info, + $handle + ) { + $error = curl_error($handle); + $this->releaseEasyHandle($handle); + RequestEvents::emitError( + $transaction, + new AdapterException("cURL error {$info['curl_result']}: {$error}"), + $info + ); + } + + private function checkoutEasyHandle() + { + // Find an unused handle in the cache + if (false !== ($key = array_search(false, $this->ownedHandles, true))) { + $this->ownedHandles[$key] = true; + return $this->handles[$key]; + } + + // Add a new handle + $handle = curl_init(); + $id = (int) $handle; + $this->handles[$id] = $handle; + $this->ownedHandles[$id] = true; + + return $handle; + } + + private function releaseEasyHandle($handle) + { + $id = (int) $handle; + if (count($this->ownedHandles) > $this->maxHandles) { + curl_close($this->handles[$id]); + unset($this->handles[$id], $this->ownedHandles[$id]); + } else { + curl_reset($handle); + $this->ownedHandles[$id] = false; + } + } +} diff --git a/core/vendor/guzzlehttp/guzzle/src/Adapter/Curl/CurlFactory.php b/core/vendor/guzzlehttp/guzzle/src/Adapter/Curl/CurlFactory.php new file mode 100644 index 00000000000..0af3d7566e5 --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/src/Adapter/Curl/CurlFactory.php @@ -0,0 +1,334 @@ +getRequest(); + $mediator = new RequestMediator($transaction, $messageFactory); + $options = $this->getDefaultOptions($request, $mediator); + $this->applyMethod($request, $options); + $this->applyTransferOptions($request, $mediator, $options); + $this->applyHeaders($request, $options); + unset($options['_headers']); + + // Add adapter options from the request's configuration options + if ($config = $request->getConfig()['curl']) { + $options = $this->applyCustomCurlOptions($config, $options); + } + + if (!$handle) { + $handle = curl_init(); + } + + curl_setopt_array($handle, $options); + + return $handle; + } + + protected function getDefaultOptions( + RequestInterface $request, + RequestMediator $mediator + ) { + $url = $request->getUrl(); + + // Strip fragment from URL. See: + // https://github.com/guzzle/guzzle/issues/453 + if (($pos = strpos($url, '#')) !== false) { + $url = substr($url, 0, $pos); + } + + $config = $request->getConfig(); + $options = array( + CURLOPT_URL => $url, + CURLOPT_CONNECTTIMEOUT => $config['connect_timeout'] ?: 150, + CURLOPT_RETURNTRANSFER => false, + CURLOPT_HEADER => false, + CURLOPT_WRITEFUNCTION => array($mediator, 'writeResponseBody'), + CURLOPT_HEADERFUNCTION => array($mediator, 'receiveResponseHeader'), + CURLOPT_READFUNCTION => array($mediator, 'readRequestBody'), + CURLOPT_HTTP_VERSION => $request->getProtocolVersion() === '1.0' + ? CURL_HTTP_VERSION_1_0 : CURL_HTTP_VERSION_1_1, + CURLOPT_SSL_VERIFYPEER => 1, + CURLOPT_SSL_VERIFYHOST => 2, + '_headers' => $request->getHeaders() + ); + + if (defined('CURLOPT_PROTOCOLS')) { + // Allow only HTTP and HTTPS protocols + $options[CURLOPT_PROTOCOLS] = CURLPROTO_HTTP | CURLPROTO_HTTPS; + } + + // Add CURLOPT_ENCODING if Accept-Encoding header is provided + if ($request->hasHeader('Accept-Encoding')) { + $options[CURLOPT_ENCODING] = $request->getHeader('Accept-Encoding'); + // Let cURL set the Accept-Encoding header. Without this change + // curl could add a duplicate value. + $this->removeHeader('Accept-Encoding', $options); + } + + return $options; + } + + private function applyMethod(RequestInterface $request, array &$options) + { + $method = $request->getMethod(); + if ($method == 'GET') { + $options[CURLOPT_HTTPGET] = true; + unset($options[CURLOPT_READFUNCTION]); + } elseif ($method == 'HEAD') { + $options[CURLOPT_NOBODY] = true; + unset($options[CURLOPT_WRITEFUNCTION], $options[CURLOPT_READFUNCTION]); + } else { + $options[CURLOPT_CUSTOMREQUEST] = $method; + if (!$request->getBody()) { + unset($options[CURLOPT_READFUNCTION]); + } else { + $this->applyBody($request, $options); + } + } + } + + private function applyBody(RequestInterface $request, array &$options) + { + if ($request->hasHeader('Content-Length')) { + $size = (int) $request->getHeader('Content-Length'); + } else { + $size = null; + } + + $request->getBody()->seek(0); + + // You can send the body as a string using curl's CURLOPT_POSTFIELDS + if (($size !== null && $size < 32768) || + isset($request->getConfig()['curl']['body_as_string']) + ) { + $options[CURLOPT_POSTFIELDS] = $request->getBody()->getContents(); + // Don't duplicate the Content-Length header + $this->removeHeader('Content-Length', $options); + $this->removeHeader('Transfer-Encoding', $options); + } else { + $options[CURLOPT_UPLOAD] = true; + // Let cURL handle setting the Content-Length header + if ($size !== null) { + $options[CURLOPT_INFILESIZE] = $size; + $this->removeHeader('Content-Length', $options); + } + } + + // If the Expect header is not present, prevent curl from adding it + if (!$request->hasHeader('Expect')) { + $options[CURLOPT_HTTPHEADER][] = 'Expect:'; + } + } + + private function applyHeaders(RequestInterface $request, array &$options) + { + foreach ($options['_headers'] as $name => $values) { + $options[CURLOPT_HTTPHEADER][] = $name . ': ' . implode(', ', $values); + } + + // Remove the Expect header if one was not set + if (!$request->hasHeader('Accept')) { + $options[CURLOPT_HTTPHEADER][] = 'Accept:'; + } + } + + private function applyTransferOptions( + RequestInterface $request, + RequestMediator $mediator, + array &$options + ) { + static $methods; + if (!$methods) { + $methods = array_flip(get_class_methods(__CLASS__)); + } + + foreach ($request->getConfig()->toArray() as $key => $value) { + $method = "add_{$key}"; + if (isset($methods[$method])) { + $this->{$method}($request, $mediator, $options, $value); + } + } + } + + private function add_debug( + RequestInterface $request, + RequestMediator $mediator, + &$options, + $value + ) { + if ($value) { + $options[CURLOPT_STDERR] = is_resource($value) ? $value : STDOUT; + $options[CURLOPT_VERBOSE] = true; + } + } + + private function add_proxy( + RequestInterface $request, + RequestMediator $mediator, + &$options, + $value + ) { + if (!is_array($value)) { + $options[CURLOPT_PROXY] = $value; + } else { + $scheme = $request->getScheme(); + if (isset($value[$scheme])) { + $options[CURLOPT_PROXY] = $value[$scheme]; + } + } + } + + private function add_timeout( + RequestInterface $request, + RequestMediator $mediator, + &$options, + $value + ) { + $options[CURLOPT_TIMEOUT_MS] = $value * 1000; + } + + private function add_connect_timeout( + RequestInterface $request, + RequestMediator $mediator, + &$options, + $value + ) { + $options[CURLOPT_CONNECTTIMEOUT_MS] = $value * 1000; + } + + private function add_verify( + RequestInterface $request, + RequestMediator $mediator, + &$options, + $value + ) { + if ($value === false) { + unset($options[CURLOPT_CAINFO]); + $options[CURLOPT_SSL_VERIFYHOST] = 0; + $options[CURLOPT_SSL_VERIFYPEER] = false; + } elseif ($value === true || is_string($value)) { + $options[CURLOPT_SSL_VERIFYHOST] = 2; + $options[CURLOPT_SSL_VERIFYPEER] = true; + if ($value !== true) { + if (!file_exists($value)) { + throw new AdapterException('SSL certificate authority file' + . " not found: {$value}"); + } + $options[CURLOPT_CAINFO] = $value; + } + } + } + + private function add_cert( + RequestInterface $request, + RequestMediator $mediator, + &$options, + $value + ) { + if (!file_exists($value)) { + throw new AdapterException("SSL certificate not found: {$value}"); + } + + $options[CURLOPT_SSLCERT] = $value; + } + + private function add_ssl_key( + RequestInterface $request, + RequestMediator $mediator, + &$options, + $value + ) { + if (is_array($value)) { + $options[CURLOPT_SSLKEYPASSWD] = $value[1]; + $value = $value[0]; + } + + if (!file_exists($value)) { + throw new AdapterException("SSL private key not found: {$value}"); + } + + $options[CURLOPT_SSLKEY] = $value; + } + + private function add_save_to( + RequestInterface $request, + RequestMediator $mediator, + &$options, + $value + ) { + $mediator->setResponseBody(is_string($value) + ? Stream\create(fopen($value, 'w')) + : Stream\create($value)); + } + + /** + * Takes an array of curl options specified in the 'curl' option of a + * request's configuration array and maps them to CURLOPT_* options. + * + * This method is only called when a request has a 'curl' config setting. + * Array key strings that start with CURL that have a matching constant + * value will be automatically converted to the matching constant. + * + * @param array $config Configuration array of custom curl option + * @param array $options Array of existing curl options + * + * @return array Returns a new array of curl options + */ + private function applyCustomCurlOptions(array $config, array $options) + { + unset($config['body_as_string']); + $curlOptions = []; + + // Map curl constant strings to defined values + foreach ($config as $key => $value) { + if (defined($key) && substr($key, 0, 4) === 'CURL') { + $key = constant($key); + } + $curlOptions[$key] = $value; + } + + return $curlOptions + $options; + } + + /** + * 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; + } + } + } +} diff --git a/core/vendor/guzzlehttp/guzzle/src/Adapter/Curl/MultiAdapter.php b/core/vendor/guzzlehttp/guzzle/src/Adapter/Curl/MultiAdapter.php new file mode 100644 index 00000000000..90ac98992f9 --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/src/Adapter/Curl/MultiAdapter.php @@ -0,0 +1,285 @@ +handles = new \SplObjectStorage(); + $this->messageFactory = $messageFactory; + $this->curlFactory = isset($options['handle_factory']) + ? $options['handle_factory'] + : new CurlFactory(); + + if (isset($options['select_timeout'])) { + $this->selectTimeout = $options['select_timeout']; + } elseif (isset($_SERVER[self::ENV_SELECT_TIMEOUT])) { + $this->selectTimeout = $_SERVER[self::ENV_SELECT_TIMEOUT]; + } else { + $this->selectTimeout = 1; + } + } + + public function __destruct() + { + foreach ($this->multiHandles as $handle) { + if (is_resource($handle)) { + curl_multi_close($handle); + } + } + } + + /** + * Throw an exception for a cURL multi response + * + * @param int $code Curl response code + * @throws AdapterException + */ + public static function throwMultiError($code) + { + $buffer = function_exists('curl_multi_strerror') + ? curl_multi_strerror($code) + : self::ERROR_STR; + + throw new AdapterException(sprintf('cURL error %s: %s', $code, $buffer)); + } + + public function send(TransactionInterface $transaction) + { + $context = new BatchContext($this->checkoutMultiHandle(), true); + $this->addHandle($transaction, $context); + $this->perform($context); + + return $transaction->getResponse(); + } + + public function sendAll(\Iterator $transactions, $parallel) + { + $context = new BatchContext( + $this->checkoutMultiHandle(), + false, + $transactions + ); + + foreach (new \LimitIterator($transactions, 0, $parallel) as $trans) { + $this->addHandle($trans, $context); + } + + $this->perform($context); + } + + private function perform(BatchContext $context) + { + // The first curl_multi_select often times out no matter what, but is + // usually required for fast transfers. + $active = false; + $multi = $context->getMultiHandle(); + + do { + while (($mrc = curl_multi_exec($multi, $active)) == CURLM_CALL_MULTI_PERFORM); + if ($mrc != CURLM_OK && $mrc != CURLM_CALL_MULTI_PERFORM) { + self::throwMultiError($mrc); + } + // Need to check if there are pending transactions before processing + // them so that we don't bail from the loop too early. + $pending = $context->hasPending(); + $this->processMessages($context); + if ($active && curl_multi_select($multi, $this->selectTimeout) === -1) { + // Perform a usleep if a select returns -1. + // See: https://bugs.php.net/bug.php?id=61141 + usleep(250); + } + } while ($active || $pending); + + $this->releaseMultiHandle($multi); + } + + private function processMessages(BatchContext $context) + { + $multi = $context->getMultiHandle(); + + while ($done = curl_multi_info_read($multi)) { + $transaction = $context->findTransaction($done['handle']); + $this->processResponse($transaction, $done, $context); + // Add the next transaction if there are more in the queue + if ($next = $context->nextPending()) { + $this->addHandle($next, $context); + } + } + } + + private function processResponse( + TransactionInterface $transaction, + array $curl, + BatchContext $context + ) { + $info = $context->removeTransaction($transaction); + + try { + if (!$this->isCurlException($transaction, $curl, $context, $info)) { + RequestEvents::emitComplete($transaction, $info); + } + } catch (RequestException $e) { + $this->throwException($e, $context); + } + } + + private function addHandle( + TransactionInterface $transaction, + BatchContext $context + ) { + try { + RequestEvents::emitBefore($transaction); + // Only transfer if the request was not intercepted + if (!$transaction->getResponse()) { + $factory = $this->curlFactory; + $context->addTransaction( + $transaction, + $factory($transaction, $this->messageFactory) + ); + } + } catch (RequestException $e) { + $this->throwException($e, $context); + } + } + + private function isCurlException( + TransactionInterface $transaction, + array $curl, + BatchContext $context, + array $info + ) { + if (CURLM_OK == $curl['result'] || + CURLM_CALL_MULTI_PERFORM == $curl['result'] + ) { + return false; + } + + $request = $transaction->getRequest(); + try { + // Send curl stats along if they are available + $stats = ['curl_result' => $curl['result']] + $info; + RequestEvents::emitError( + $transaction, + new RequestException( + sprintf( + '[curl] (#%s) %s [url] %s', + $curl['result'], + function_exists('curl_strerror') + ? curl_strerror($curl['result']) + : self::ERROR_STR, + $request->getUrl() + ), + $request + ), + $stats + ); + } catch (RequestException $e) { + $this->throwException($e, $context); + } + + return true; + } + + private function throwException(RequestException $e, BatchContext $context) + { + if ($context->throwsExceptions()) { + $this->releaseMultiHandle($context->getMultiHandle()); + throw $e; + } + } + + /** + * Returns a curl_multi handle from the cache or creates a new one + * + * @return resource + */ + private function checkoutMultiHandle() + { + // Find an unused handle in the cache + $key = array_search(false, $this->multiOwned, true); + if (false !== $key) { + $this->multiOwned[$key] = true; + return $this->multiHandles[$key]; + } + + // Add a new handle + $handle = curl_multi_init(); + $id = (int) $handle; + $this->multiHandles[$id] = $handle; + $this->multiOwned[$id] = true; + + return $handle; + } + + /** + * Releases a curl_multi handle back into the cache and removes excess cache + * + * @param resource $handle Curl multi handle to remove + */ + private function releaseMultiHandle($handle) + { + $id = (int) $handle; + + if (count($this->multiHandles) <= 3) { + $this->multiOwned[$id] = false; + } else { + // Prune excessive handles + curl_multi_close($this->multiHandles[$id]); + unset($this->multiHandles[$id], $this->multiOwned[$id]); + } + } +} diff --git a/core/vendor/guzzlehttp/guzzle/src/Adapter/Curl/RequestMediator.php b/core/vendor/guzzlehttp/guzzle/src/Adapter/Curl/RequestMediator.php new file mode 100644 index 00000000000..19cbcfd090c --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/src/Adapter/Curl/RequestMediator.php @@ -0,0 +1,130 @@ +transaction = $transaction; + $this->messageFactory = $messageFactory; + } + + /** + * Set the body that will hold the response body + * + * @param StreamInterface $body Response body + */ + public function setResponseBody(StreamInterface $body = null) + { + $this->body = $body; + } + + /** + * Receive a response header from curl + * + * @param resource $curl Curl handle + * @param string $header Received header + * + * @return int + */ + public function receiveResponseHeader($curl, $header) + { + static $normalize = ["\r", "\n"]; + $length = strlen($header); + $header = str_replace($normalize, '', $header); + + if (strpos($header, 'HTTP/') === 0) { + $startLine = explode(' ', $header, 3); + // Only download the body to a target body when a successful + // response is received. + if ($startLine[1][0] != '2') { + $this->body = null; + } + $this->statusCode = $startLine[1]; + $this->reasonPhrase = isset($startLine[2]) ? $startLine[2] : null; + $this->protocolVersion = substr($startLine[0], -3); + $this->headers = []; + } elseif ($pos = strpos($header, ':')) { + $this->headers[substr($header, 0, $pos)][] = substr($header, $pos + 1); + } elseif ($header == '' && $this->statusCode >= 200) { + $response = $this->messageFactory->createResponse( + $this->statusCode, + $this->headers, + $this->body, + [ + 'protocol_version' => $this->protocolVersion, + 'reason_phrase' => $this->reasonPhrase + ] + ); + $this->headers = $this->body = null; + $this->transaction->setResponse($response); + // Allows events to react before downloading any of the body + RequestEvents::emitHeaders($this->transaction); + } + + return $length; + } + + /** + * Write data to the response body of a request + * + * @param resource $curl + * @param string $write + * + * @return int + */ + public function writeResponseBody($curl, $write) + { + if (!($response = $this->transaction->getResponse())) { + return 0; + } + + // Add a default body on the response if one was not found + if (!($body = $response->getBody())) { + $body = new Stream(fopen('php://temp', 'r+')); + $response->setBody($body); + } + + return $body->write($write); + } + + /** + * Read data from the request body and send it to curl + * + * @param resource $ch Curl handle + * @param resource $fd File descriptor + * @param int $length Amount of data to read + * + * @return string + */ + public function readRequestBody($ch, $fd, $length) + { + return (string) $this->transaction->getRequest()->getBody()->read($length); + } +} diff --git a/core/vendor/guzzlehttp/guzzle/src/Adapter/FakeParallelAdapter.php b/core/vendor/guzzlehttp/guzzle/src/Adapter/FakeParallelAdapter.php new file mode 100644 index 00000000000..302656837f1 --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/src/Adapter/FakeParallelAdapter.php @@ -0,0 +1,34 @@ +adapter = $adapter; + } + + public function sendAll(\Iterator $transactions, $parallel) + { + foreach ($transactions as $transaction) { + try { + $this->adapter->send($transaction); + } catch (RequestException $e) { + // no op for batch transaction + } + } + } +} diff --git a/core/vendor/guzzlehttp/guzzle/src/Adapter/MockAdapter.php b/core/vendor/guzzlehttp/guzzle/src/Adapter/MockAdapter.php new file mode 100644 index 00000000000..3e8020e6984 --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/src/Adapter/MockAdapter.php @@ -0,0 +1,60 @@ +setResponse($response); + } + + /** + * Set the response that will be served by the adapter + * + * @param ResponseInterface|callable $response Response to serve or + * function to invoke that handles a transaction + */ + public function setResponse($response) + { + $this->response = $response; + } + + public function send(TransactionInterface $transaction) + { + RequestEvents::emitBefore($transaction); + if (!$transaction->getResponse()) { + + // Read the request body if it is present + if ($transaction->getRequest()->getBody()) { + $transaction->getRequest()->getBody()->__toString(); + } + + $response = is_callable($this->response) + ? call_user_func($this->response, $transaction) + : $this->response; + if (!$response instanceof ResponseInterface) { + throw new \RuntimeException('Invalid mocked response'); + } + + $transaction->setResponse($response); + RequestEvents::emitHeaders($transaction); + RequestEvents::emitComplete($transaction); + } + + return $transaction->getResponse(); + } +} diff --git a/core/vendor/guzzlehttp/guzzle/src/Adapter/ParallelAdapterInterface.php b/core/vendor/guzzlehttp/guzzle/src/Adapter/ParallelAdapterInterface.php new file mode 100644 index 00000000000..79a25b7e0dc --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/src/Adapter/ParallelAdapterInterface.php @@ -0,0 +1,23 @@ +messageFactory = $messageFactory; + } + + public function send(TransactionInterface $transaction) + { + // HTTP/1.1 streams using the PHP stream wrapper require a + // Connection: close header. Setting here so that it is added before + // emitting the request.before_send event. + $request = $transaction->getRequest(); + if ($request->getProtocolVersion() == '1.1' && + !$request->hasHeader('Connection') + ) { + $transaction->getRequest()->setHeader('Connection', 'close'); + } + + RequestEvents::emitBefore($transaction); + if (!$transaction->getResponse()) { + $this->createResponse($transaction); + RequestEvents::emitComplete($transaction); + } + + return $transaction->getResponse(); + } + + private function createResponse(TransactionInterface $transaction) + { + $request = $transaction->getRequest(); + $stream = $this->createStream($request, $http_response_header); + + if (!$request->getConfig()['stream']) { + $stream = $this->getSaveToBody($request, $stream); + } + + // Track the response headers of the request + $this->createResponseObject($http_response_header, $transaction, $stream); + } + + /** + * Drain the steam into the destination stream + */ + private function getSaveToBody(RequestInterface $request, $stream) + { + if ($saveTo = $request->getConfig()['save_to']) { + // Stream the response into the destination stream + $saveTo = is_string($saveTo) + ? Stream\create(fopen($saveTo, 'r+')) + : Stream\create($saveTo); + } else { + // Stream into the default temp stream + $saveTo = Stream\create(); + } + + while (!feof($stream)) { + $saveTo->write(fread($stream, 8096)); + } + + fclose($stream); + $saveTo->seek(0); + + return $saveTo; + } + + private function createResponseObject( + array $headers, + TransactionInterface $transaction, + $stream + ) { + $parts = explode(' ', array_shift($headers), 3); + $options = ['protocol_version' => substr($parts[0], -3)]; + if (isset($parts[2])) { + $options['reason_phrase'] = $parts[2]; + } + + // Set the size on the stream if it was returned in the response + $responseHeaders = []; + foreach ($headers as $header) { + $headerParts = explode(':', $header, 2); + $responseHeaders[$headerParts[0]] = isset($headerParts[1]) + ? $headerParts[1] + : ''; + } + + $response = $this->messageFactory->createResponse( + $parts[1], + $responseHeaders, + $stream, + $options + ); + + $transaction->setResponse($response); + RequestEvents::emitHeaders($transaction); + + return $response; + } + + /** + * Create a resource and check to ensure it was created successfully + * + * @param callable $callback Callable that returns stream resource + * @param RequestInterface $request Request used when throwing exceptions + * @param array $options Options used when throwing exceptions + * + * @return resource + * @throws RequestException on error + */ + private function createResource(callable $callback, RequestInterface $request, $options) + { + // Turn off error reporting while we try to initiate the request + $level = error_reporting(0); + $resource = call_user_func($callback); + error_reporting($level); + + // If the resource could not be created, then grab the last error and + // throw an exception. + if (!is_resource($resource)) { + $message = 'Error creating resource. [url] ' . $request->getUrl() . ' '; + if (isset($options['http']['proxy'])) { + $message .= "[proxy] {$options['http']['proxy']} "; + } + foreach (error_get_last() as $key => $value) { + $message .= "[{$key}] {$value} "; + } + throw new RequestException(trim($message), $request); + } + + return $resource; + } + + /** + * Create the stream for the request with the context options. + * + * @param RequestInterface $request Request being sent + * @param mixed $http_response_header Populated by stream wrapper + * + * @return resource + */ + private function createStream( + RequestInterface $request, + &$http_response_header + ) { + static $methods; + if (!$methods) { + $methods = array_flip(get_class_methods(__CLASS__)); + } + + $params = []; + $options = $this->getDefaultOptions($request); + foreach ($request->getConfig()->toArray() as $key => $value) { + $method = "add_{$key}"; + if (isset($methods[$method])) { + $this->{$method}($request, $options, $value, $params); + } + } + + $this->applyCustomOptions($request, $options); + $context = $this->createStreamContext($request, $options, $params); + + return $this->createStreamResource( + $request, + $options, + $context, + $http_response_header + ); + } + + private function getDefaultOptions(RequestInterface $request) + { + $headers = ''; + foreach ($request->getHeaders() as $name => $values) { + $headers .= $name . ': ' . implode(', ', $values) . "\r\n"; + } + + return [ + 'http' => [ + 'method' => $request->getMethod(), + 'header' => trim($headers), + 'protocol_version' => $request->getProtocolVersion(), + 'ignore_errors' => true, + 'follow_location' => 0, + 'content' => (string) $request->getBody() + ] + ]; + } + + private function add_proxy(RequestInterface $request, &$options, $value, &$params) + { + if (!is_array($value)) { + $options['http']['proxy'] = $value; + } else { + $scheme = $request->getScheme(); + if (isset($value[$scheme])) { + $options['http']['proxy'] = $value[$scheme]; + } + } + } + + private function add_timeout(RequestInterface $request, &$options, $value, &$params) + { + $options['http']['timeout'] = $value; + } + + private function add_verify(RequestInterface $request, &$options, $value, &$params) + { + if ($value === true || is_string($value)) { + $options['http']['verify_peer'] = true; + if ($value !== true) { + if (!file_exists($value)) { + throw new \RuntimeException("SSL certificate authority file not found: {$value}"); + } + $options['http']['allow_self_signed'] = true; + $options['http']['cafile'] = $value; + } + } elseif ($value === false) { + $options['http']['verify_peer'] = false; + } + } + + private function add_cert(RequestInterface $request, &$options, $value, &$params) + { + if (is_array($value)) { + $options['http']['passphrase'] = $value[1]; + $value = $value[0]; + } + + if (!file_exists($value)) { + throw new \RuntimeException("SSL certificate not found: {$value}"); + } + + $options['http']['local_cert'] = $value; + } + + private function add_debug(RequestInterface $request, &$options, $value, &$params) + { + 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']; + + if (!is_resource($value)) { + $value = fopen('php://output', 'w'); + } + + $params['notification'] = function () use ($request, $value, $map, $args) { + $passed = func_get_args(); + $code = array_shift($passed); + fprintf($value, '<%s> [%s] ', $request->getUrl(), $map[$code]); + foreach (array_filter($passed) as $i => $v) { + fwrite($value, $args[$i] . ': "' . $v . '" '); + } + fwrite($value, "\n"); + }; + } + + private function applyCustomOptions( + RequestInterface $request, + array &$options + ) { + // Overwrite any generated options with custom options + if ($custom = $request->getConfig()['stream_context']) { + if (!is_array($custom)) { + throw new AdapterException('stream_context must be an array'); + } + $options = array_replace_recursive($options, $custom); + } + } + + private function createStreamContext( + RequestInterface $request, + array $options, + array $params + ) { + return $this->createResource(function () use ( + $request, + $options, + $params + ) { + return stream_context_create($options, $params); + }, $request, $options); + } + + private function createStreamResource( + RequestInterface $request, + array $options, + $context, + &$http_response_header + ) { + $url = $request->getUrl(); + // Add automatic gzip decompression + if (strpos($request->getHeader('Accept-Encoding'), 'gzip') !== false) { + $url = 'compress.zlib://' . $url; + } + + return $this->createResource(function () use ( + $url, + &$http_response_header, + $context + ) { + if (false === strpos($url, 'http')) { + trigger_error("URL is invalid: {$url}", E_USER_WARNING); + return null; + } + return fopen($url, 'r', null, $context); + }, $request, $options); + } +} diff --git a/core/vendor/guzzlehttp/guzzle/src/Adapter/StreamingProxyAdapter.php b/core/vendor/guzzlehttp/guzzle/src/Adapter/StreamingProxyAdapter.php new file mode 100644 index 00000000000..128eb1d1e12 --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/src/Adapter/StreamingProxyAdapter.php @@ -0,0 +1,36 @@ +defaultAdapter = $defaultAdapter; + $this->streamingAdapter = $streamingAdapter; + } + + public function send(TransactionInterface $transaction) + { + return $transaction->getRequest()->getConfig()['stream'] + ? $this->streamingAdapter->send($transaction) + : $this->defaultAdapter->send($transaction); + } +} diff --git a/core/vendor/guzzlehttp/guzzle/src/Adapter/Transaction.php b/core/vendor/guzzlehttp/guzzle/src/Adapter/Transaction.php new file mode 100644 index 00000000000..74bb6b44234 --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/src/Adapter/Transaction.php @@ -0,0 +1,49 @@ +client = $client; + $this->request = $request; + } + + public function getRequest() + { + return $this->request; + } + + public function getResponse() + { + return $this->response; + } + + public function setResponse(ResponseInterface $response) + { + $this->response = $response; + } + + public function getClient() + { + return $this->client; + } +} diff --git a/core/vendor/guzzlehttp/guzzle/src/Adapter/TransactionInterface.php b/core/vendor/guzzlehttp/guzzle/src/Adapter/TransactionInterface.php new file mode 100644 index 00000000000..b9bf50cbacc --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/src/Adapter/TransactionInterface.php @@ -0,0 +1,35 @@ +client = $client; + $this->configureEvents($options); + if ($source instanceof \Iterator) { + $this->source = $source; + } elseif (is_array($source)) { + $this->source = new \ArrayIterator($source); + } else { + throw new \InvalidArgumentException('Expected an Iterator or array'); + } + } + + public function current() + { + $request = $this->source->current(); + + if (!$request instanceof RequestInterface) { + throw new \RuntimeException('All must implement RequestInterface'); + } + + if ($this->eventListeners) { + $emitter = $request->getEmitter(); + foreach ($this->eventListeners as $ev) { + if ($ev['once']) { + $emitter->once($ev['name'], $ev['fn'], $ev['priority']); + } else { + $emitter->on($ev['name'], $ev['fn'], $ev['priority']); + } + } + } + + return new Transaction($this->client, $request); + } + + public function next() + { + $this->source->next(); + } + + public function key() + { + return $this->source->key(); + } + + public function valid() + { + return $this->source->valid(); + } + + public function rewind() {} + + private function configureEvents(array $options) + { + static $namedEvents = ['before', 'complete', 'error']; + + foreach ($namedEvents as $event) { + if (isset($options[$event])) { + if (is_callable($options[$event])) { + $this->eventListeners[] = [ + 'name' => $event, + 'fn' => $options[$event], + 'priority' => 0, + 'once' => false + ]; + } else { + $this->addEvent($event, $options[$event]); + } + } + } + } + + private function addEvent($eventName, $event) + { + static $default = ['priority' => 0, 'once' => false]; + + if (!is_array($event)) { + throw new \InvalidArgumentException('Each event listener must be a' + . ' callable or an array of associative arrays where each' + . ' associative array contains a "fn" key.'); + } + + if (isset($event['fn'])) { + $event['name'] = $eventName; + $this->eventListeners[] = $event + $default; + } else { + foreach ($event as $e) { + $this->addEvent($eventName, $e); + } + } + } +} diff --git a/core/vendor/guzzlehttp/guzzle/src/Client.php b/core/vendor/guzzlehttp/guzzle/src/Client.php new file mode 100644 index 00000000000..617a38e9390 --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/src/Client.php @@ -0,0 +1,361 @@ + [ + * 'http://www.foo.com/{version}/', + * ['version' => '123'] + * ], + * 'defaults' => [ + * 'timeout' => 10, + * 'allow_redirects' => false, + * 'proxy' => '192.168.16.1:10' + * ] + * ]); + * + * @param array $config Client configuration settings + * - base_url: Base URL of the client that is merged into relative URLs. + * Can be a string or an array that contains a URI template followed + * by an associative array of expansion variables to inject into the + * URI template. + * - adapter: Adapter used to transfer requests + * - parallel_adapter: Adapter used to transfer requests in parallel + * - message_factory: Factory used to create request and response object + * - defaults: Default request options to apply to each request + */ + public function __construct(array $config = []) + { + $this->configureBaseUrl($config); + $this->configureDefaults($config); + $this->configureAdapter($config); + } + + /** + * Get the default User-Agent string to use with Guzzle + * + * @return string + */ + public static function getDefaultUserAgent() + { + static $defaultAgent = ''; + if (!$defaultAgent) { + $defaultAgent = 'Guzzle/' . self::VERSION; + if (extension_loaded('curl')) { + $defaultAgent .= ' curl/' . curl_version()['version']; + } + $defaultAgent .= ' PHP/' . PHP_VERSION; + } + + return $defaultAgent; + } + + public function __call($name, $arguments) + { + return \GuzzleHttp\deprecation_proxy( + $this, + $name, + $arguments, + ['getEventDispatcher' => 'getEmitter'] + ); + } + + public function getDefaultOption($keyOrPath = null) + { + return $keyOrPath === null + ? $this->defaults + : \GuzzleHttp\get_path($this->defaults, $keyOrPath); + } + + public function setDefaultOption($keyOrPath, $value) + { + \GuzzleHttp\set_path($this->defaults, $keyOrPath, $value); + } + + public function getBaseUrl() + { + return (string) $this->baseUrl; + } + + public function createRequest($method, $url = null, array $options = []) + { + // Merge in default options + $options = array_replace_recursive($this->defaults, $options); + + // Use a clone of the client's emitter + $options['config']['emitter'] = clone $this->getEmitter(); + + $request = $this->messageFactory->createRequest( + $method, + $url ? (string) $this->buildUrl($url) : (string) $this->baseUrl, + $options + ); + + return $request; + } + + public function get($url = null, $options = []) + { + return $this->send($this->createRequest('GET', $url, $options)); + } + + public function head($url = null, array $options = []) + { + return $this->send($this->createRequest('HEAD', $url, $options)); + } + + public function delete($url = null, array $options = []) + { + return $this->send($this->createRequest('DELETE', $url, $options)); + } + + public function put($url = null, array $options = []) + { + return $this->send($this->createRequest('PUT', $url, $options)); + } + + public function patch($url = null, array $options = []) + { + return $this->send($this->createRequest('PATCH', $url, $options)); + } + + public function post($url = null, array $options = []) + { + return $this->send($this->createRequest('POST', $url, $options)); + } + + public function options($url = null, array $options = []) + { + return $this->send($this->createRequest('OPTIONS', $url, $options)); + } + + public function send(RequestInterface $request) + { + $transaction = new Transaction($this, $request); + try { + if ($response = $this->adapter->send($transaction)) { + return $response; + } + throw new \LogicException('No response was associated with the transaction'); + } catch (RequestException $e) { + throw $e; + } catch (\Exception $e) { + // Wrap exceptions in a RequestException to adhere to the interface + throw new RequestException($e->getMessage(), $request, null, $e); + } + } + + public function sendAll($requests, array $options = []) + { + if (!($requests instanceof TransactionIterator)) { + $requests = new TransactionIterator($requests, $this, $options); + } + + $this->parallelAdapter->sendAll( + $requests, + isset($options['parallel']) + ? $options['parallel'] + : self::DEFAULT_CONCURRENCY + ); + } + + /** + * Get an array of default options to apply to the client + * + * @return array + */ + protected function getDefaultOptions() + { + $settings = [ + 'allow_redirects' => true, + 'exceptions' => true, + 'verify' => __DIR__ . '/cacert.pem' + ]; + + // Use the bundled cacert if it is a regular file, or set to true if + // using a phar file (because curL and the stream wrapper can't read + // cacerts from the phar stream wrapper). Favor the ini setting over + // the system's cacert. + if (substr(__FILE__, 0, 7) == 'phar://') { + $settings['verify'] = ini_get('openssl.cafile') ?: true; + } + + // Use the standard Linux HTTP_PROXY and HTTPS_PROXY if set + if (isset($_SERVER['HTTP_PROXY'])) { + $settings['proxy']['http'] = $_SERVER['HTTP_PROXY']; + } + + if (isset($_SERVER['HTTPS_PROXY'])) { + $settings['proxy']['https'] = $_SERVER['HTTPS_PROXY']; + } + + return $settings; + } + + /** + * Expand a URI template and inherit from the base URL if it's relative + * + * @param string|array $url URL or URI template to expand + * + * @return string + */ + private function buildUrl($url) + { + if (!is_array($url)) { + if (strpos($url, '://')) { + return (string) $url; + } + return (string) $this->baseUrl->combine($url); + } elseif (strpos($url[0], '://')) { + return \GuzzleHttp\uri_template($url[0], $url[1]); + } + + return (string) $this->baseUrl->combine( + \GuzzleHttp\uri_template($url[0], $url[1]) + ); + } + + /** + * Get a default parallel adapter to use based on the environment + * + * @return ParallelAdapterInterface|null + * @throws \RuntimeException + */ + private function getDefaultParallelAdapter() + { + return extension_loaded('curl') + ? new CurlAdapter($this->messageFactory) + : new FakeParallelAdapter($this->adapter); + } + + /** + * Create a default adapter to use based on the environment + * @throws \RuntimeException + */ + private function getDefaultAdapter() + { + if (extension_loaded('curl')) { + $this->parallelAdapter = new MultiAdapter($this->messageFactory); + $this->adapter = function_exists('curl_reset') + ? new CurlAdapter($this->messageFactory) + : $this->parallelAdapter; + if (ini_get('allow_url_fopen')) { + $this->adapter = new StreamingProxyAdapter( + $this->adapter, + new StreamAdapter($this->messageFactory) + ); + } + } elseif (ini_get('allow_url_fopen')) { + $this->adapter = new StreamAdapter($this->messageFactory); + } else { + throw new \RuntimeException('Guzzle requires cURL, the ' + . 'allow_url_fopen ini setting, or a custom HTTP adapter.'); + } + } + + private function configureBaseUrl(&$config) + { + if (!isset($config['base_url'])) { + $this->baseUrl = new Url('', ''); + } elseif (is_array($config['base_url'])) { + $this->baseUrl = Url::fromString( + \GuzzleHttp\uri_template( + $config['base_url'][0], + $config['base_url'][1] + ) + ); + $config['base_url'] = (string) $this->baseUrl; + } else { + $this->baseUrl = Url::fromString($config['base_url']); + } + } + + private function configureDefaults($config) + { + if (!isset($config['defaults'])) { + $this->defaults = $this->getDefaultOptions(); + } else { + $this->defaults = array_replace( + $this->getDefaultOptions(), + $config['defaults'] + ); + } + + // Add the default user-agent header + if (!isset($this->defaults['headers'])) { + $this->defaults['headers'] = [ + 'User-Agent' => static::getDefaultUserAgent() + ]; + } elseif (!isset(array_change_key_case($this->defaults['headers'])['user-agent'])) { + // Add the User-Agent header if one was not already set + $this->defaults['headers']['User-Agent'] = static::getDefaultUserAgent(); + } + } + + private function configureAdapter(&$config) + { + if (isset($config['message_factory'])) { + $this->messageFactory = $config['message_factory']; + } else { + $this->messageFactory = new MessageFactory(); + } + if (isset($config['adapter'])) { + $this->adapter = $config['adapter']; + } else { + $this->getDefaultAdapter(); + } + // If no parallel adapter was explicitly provided and one was not + // defaulted when creating the default adapter, then create one now. + if (isset($config['parallel_adapter'])) { + $this->parallelAdapter = $config['parallel_adapter']; + } elseif (!$this->parallelAdapter) { + $this->parallelAdapter = $this->getDefaultParallelAdapter(); + } + } +} diff --git a/core/vendor/guzzlehttp/guzzle/src/ClientInterface.php b/core/vendor/guzzlehttp/guzzle/src/ClientInterface.php new file mode 100644 index 00000000000..60c6a2cecf9 --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/src/ClientInterface.php @@ -0,0 +1,179 @@ +data = $data; + } + + /** + * Create a new collection from an array, validate the keys, and add default + * values where missing + * + * @param array $config Configuration values to apply. + * @param array $defaults Default parameters + * @param array $required Required parameter names + * + * @return self + * @throws \InvalidArgumentException if a parameter is missing + */ + public static function fromConfig( + array $config = [], + array $defaults = [], + array $required = [] + ) { + $data = $config + $defaults; + + if ($missing = array_diff($required, array_keys($data))) { + throw new \InvalidArgumentException( + 'Config is missing the following keys: ' . + implode(', ', $missing)); + } + + return new self($data); + } + + /** + * Removes all key value pairs + * + * @return Collection + */ + public function clear() + { + $this->data = []; + + return $this; + } + + /** + * Get a specific key value. + * + * @param string $key Key to retrieve. + * + * @return mixed|null Value of the key or NULL + */ + public function get($key) + { + return isset($this->data[$key]) ? $this->data[$key] : null; + } + + /** + * Set a key value pair + * + * @param string $key Key to set + * @param mixed $value Value to set + * + * @return Collection Returns a reference to the object + */ + public function set($key, $value) + { + $this->data[$key] = $value; + + return $this; + } + + /** + * Add a value to a key. If a key of the same name has already been added, + * the key value will be converted into an array and the new value will be + * pushed to the end of the array. + * + * @param string $key Key to add + * @param mixed $value Value to add to the key + * + * @return Collection Returns a reference to the object. + */ + public function add($key, $value) + { + if (!array_key_exists($key, $this->data)) { + $this->data[$key] = $value; + } elseif (is_array($this->data[$key])) { + $this->data[$key][] = $value; + } else { + $this->data[$key] = array($this->data[$key], $value); + } + + return $this; + } + + /** + * Remove a specific key value pair + * + * @param string $key A key to remove + * + * @return Collection + */ + public function remove($key) + { + unset($this->data[$key]); + + return $this; + } + + /** + * Get all keys in the collection + * + * @return array + */ + public function getKeys() + { + return array_keys($this->data); + } + + /** + * Returns whether or not the specified key is present. + * + * @param string $key The key for which to check the existence. + * + * @return bool + */ + public function hasKey($key) + { + return array_key_exists($key, $this->data); + } + + /** + * Checks if any keys contains a certain value + * + * @param string $value Value to search for + * + * @return mixed Returns the key if the value was found FALSE if the value + * was not found. + */ + public function hasValue($value) + { + return array_search($value, $this->data, true); + } + + /** + * Replace the data of the object with the value of an array + * + * @param array $data Associative array of data + * + * @return Collection Returns a reference to the object + */ + public function replace(array $data) + { + $this->data = $data; + + return $this; + } + + /** + * Add and merge in a Collection or array of key value pair data. + * + * @param Collection|array $data Associative array of key value pair data + * + * @return Collection Returns a reference to the object. + */ + public function merge($data) + { + foreach ($data as $key => $value) { + $this->add($key, $value); + } + + return $this; + } + + /** + * Over write key value pairs in this collection with all of the data from + * an array or collection. + * + * @param array|\Traversable $data Values to override over this config + * + * @return self + */ + public function overwriteWith($data) + { + if (is_array($data)) { + $this->data = $data + $this->data; + } elseif ($data instanceof Collection) { + $this->data = $data->toArray() + $this->data; + } else { + foreach ($data as $key => $value) { + $this->data[$key] = $value; + } + } + + return $this; + } + + /** + * Returns a Collection containing all the elements of the collection after + * applying the callback function to each one. + * + * The callable should accept three arguments: + * - (string) $key + * - (string) $value + * - (array) $context + * + * The callable must return a the altered or unaltered value. + * + * @param callable $closure Map function to apply + * @param array $context Context to pass to the callable + * + * @return Collection + */ + public function map(callable $closure, array $context = []) + { + $collection = new static(); + foreach ($this as $key => $value) { + $collection[$key] = $closure($key, $value, $context); + } + + return $collection; + } + + /** + * Iterates over each key value pair in the collection passing them to the + * callable. If the callable returns true, the current value from input is + * returned into the result Collection. + * + * The callable must accept two arguments: + * - (string) $key + * - (string) $value + * + * @param callable $closure Evaluation function + * + * @return Collection + */ + public function filter(callable $closure) + { + $collection = new static(); + foreach ($this->data as $key => $value) { + if ($closure($key, $value)) { + $collection[$key] = $value; + } + } + + return $collection; + } +} diff --git a/core/vendor/guzzlehttp/guzzle/src/Cookie/CookieJar.php b/core/vendor/guzzlehttp/guzzle/src/Cookie/CookieJar.php new file mode 100644 index 00000000000..1b526fb9c54 --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/src/Cookie/CookieJar.php @@ -0,0 +1,232 @@ +strictMode = $strictMode; + } + + /** + * Create a new Cookie jar from an associative array and domain. + * + * @param array $cookies Cookies to create the jar from + * @param string $domain Domain to set the cookies to + * + * @return self + */ + public static function fromArray(array $cookies, $domain) + { + $cookieJar = new self(); + foreach ($cookies as $name => $value) { + $cookieJar->setCookie(new SetCookie([ + 'Domain' => $domain, + 'Name' => $name, + 'Value' => $value, + 'Discard' => true + ])); + } + + return $cookieJar; + } + + /** + * Quote the cookie value if it is not already quoted and it contains + * problematic characters. + * + * @param string $value Value that may or may not need to be quoted + * + * @return string + */ + public static function getCookieValue($value) + { + if (substr($value, 0, 1) !== '"' && + substr($value, -1, 1) !== '"' && + strpbrk($value, ';,') + ) { + $value = '"' . $value . '"'; + } + + return $value; + } + + public function clear($domain = null, $path = null, $name = null) + { + if (!$domain) { + $this->cookies = []; + return; + } elseif (!$path) { + $this->cookies = array_filter( + $this->cookies, + function (SetCookie $cookie) use ($path, $domain) { + return !$cookie->matchesDomain($domain); + } + ); + } elseif (!$name) { + $this->cookies = array_filter( + $this->cookies, + function (SetCookie $cookie) use ($path, $domain) { + return !($cookie->matchesPath($path) && + $cookie->matchesDomain($domain)); + } + ); + } else { + $this->cookies = array_filter( + $this->cookies, + function (SetCookie $cookie) use ($path, $domain, $name) { + return !($cookie->getName() == $name && + $cookie->matchesPath($path) && + $cookie->matchesDomain($domain)); + } + ); + } + } + + public function clearSessionCookies() + { + $this->cookies = array_filter( + $this->cookies, + function (SetCookie $cookie) { + return !$cookie->getDiscard() && $cookie->getExpires(); + } + ); + } + + public function setCookie(SetCookie $cookie) + { + // 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', true)) { + foreach ($cookieHeader as $cookie) { + $sc = SetCookie::fromString($cookie); + if (!$sc->getDomain()) { + $sc->setDomain($request->getHost()); + } + $this->setCookie($sc); + } + } + } + + public function addCookieHeader(RequestInterface $request) + { + $values = []; + $scheme = $request->getScheme(); + $host = $request->getHost(); + $path = $request->getPath(); + + foreach ($this->cookies as $cookie) { + if ($cookie->matchesPath($path) && + $cookie->matchesDomain($host) && + !$cookie->isExpired() && + (!$cookie->getSecure() || $scheme == 'https') + ) { + $values[] = $cookie->getName() . '=' + . self::getCookieValue($cookie->getValue()); + } + } + + if ($values) { + $request->setHeader('Cookie', implode(';', $values)); + } + } + + /** + * 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() + ); + } + } +} diff --git a/core/vendor/guzzlehttp/guzzle/src/Cookie/CookieJarInterface.php b/core/vendor/guzzlehttp/guzzle/src/Cookie/CookieJarInterface.php new file mode 100644 index 00000000000..360fbe3c3b7 --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/src/Cookie/CookieJarInterface.php @@ -0,0 +1,76 @@ +filename = $cookieFile; + + 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) { + if ($cookie->getExpires() && !$cookie->getDiscard()) { + $json[] = $cookie->toArray(); + } + } + + if (false === file_put_contents($filename, json_encode($json))) { + // @codeCoverageIgnoreStart + throw new \RuntimeException("Unable to save file {$filename}"); + // @codeCoverageIgnoreEnd + } + } + + /** + * 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) { + // @codeCoverageIgnoreStart + throw new \RuntimeException("Unable to load file {$filename}"); + // @codeCoverageIgnoreEnd + } + + $data = json_decode($json, true); + if (is_array($data)) { + foreach (json_decode($json, true) as $cookie) { + $this->setCookie(new SetCookie($cookie)); + } + } elseif (strlen($data)) { + throw new \RuntimeException("Invalid cookie file: {$filename}"); + } + } +} diff --git a/core/vendor/guzzlehttp/guzzle/src/Cookie/SetCookie.php b/core/vendor/guzzlehttp/guzzle/src/Cookie/SetCookie.php new file mode 100644 index 00000000000..76f6f8d15c9 --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/src/Cookie/SetCookie.php @@ -0,0 +1,410 @@ + null, + 'Value' => null, + 'Domain' => null, + 'Path' => '/', + 'Max-Age' => null, + 'Expires' => null, + 'Secure' => false, + 'Discard' => false, + 'HttpOnly' => false + ]; + + /** @var array Cookie data */ + private $data; + + /** + * Create a new SetCookie object from a string + * + * @param string $cookie Set-Cookie header string + * + * @return self + */ + public static function fromString($cookie) + { + // Create the default return array + $data = self::$defaults; + // Explode the cookie string using a series of semicolons + $pieces = array_filter(array_map('trim', explode(';', $cookie))); + // The name of the cookie (first kvp) must include an equal sign. + if (empty($pieces) || !strpos($pieces[0], '=')) { + return new self($data); + } + + // Add the cookie pieces into the parsed data array + foreach ($pieces as $part) { + + $cookieParts = explode('=', $part, 2); + $key = trim($cookieParts[0]); + $value = isset($cookieParts[1]) + ? trim($cookieParts[1], " \n\r\t\0\x0B\"") + : true; + + // Only check for non-cookies when cookies have been found + if (empty($data['Name'])) { + $data['Name'] = $key; + $data['Value'] = $value; + } else { + foreach (array_keys(self::$defaults) as $search) { + if (!strcasecmp($search, $key)) { + $data[$search] = $value; + continue 2; + } + } + $data[$key] = $value; + } + } + + return new self($data); + } + + /** + * @param array $data Array of cookie data provided by a Cookie parser + */ + public function __construct(array $data = []) + { + $this->data = array_replace(self::$defaults, $data); + // Extract the Expires value and turn it into a UNIX timestamp if needed + if (!$this->getExpires() && $this->getMaxAge()) { + // Calculate the Expires date + $this->setExpires(time() + $this->getMaxAge()); + } elseif ($this->getExpires() && !is_numeric($this->getExpires())) { + $this->setExpires($this->getExpires()); + } + } + + public function __toString() + { + $str = $this->data['Name'] . '=' . $this->data['Value'] . '; '; + foreach ($this->data as $k => $v) { + if ($k != 'Name' && $k != 'Value'&& $v !== null && $v !== false) { + if ($k == 'Expires') { + $str .= 'Expires=' . gmdate('D, d M Y H:i:s \G\M\T', $v) . '; '; + } else { + $str .= ($v === true ? $k : "{$k}={$v}") . '; '; + } + } + } + + return rtrim($str, '; '); + } + + public function toArray() + { + return $this->data; + } + + /** + * Get the cookie name + * + * @return string + */ + public function getName() + { + return $this->data['Name']; + } + + /** + * Set the cookie name + * + * @param string $name Cookie name + * + * @return self + */ + public function setName($name) + { + $this->data['Name'] = $name; + + return $this; + } + + /** + * Get the cookie value + * + * @return string + */ + public function getValue() + { + return $this->data['Value']; + } + + /** + * Set the cookie value + * + * @param string $value Cookie value + * + * @return self + */ + public function setValue($value) + { + $this->data['Value'] = $value; + + return $this; + } + + /** + * Get the domain + * + * @return string|null + */ + public function getDomain() + { + return $this->data['Domain']; + } + + /** + * Set the domain of the cookie + * + * @param string $domain + * + * @return self + */ + public function setDomain($domain) + { + $this->data['Domain'] = $domain; + + return $this; + } + + /** + * 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 + * + * @return self + */ + public function setPath($path) + { + $this->data['Path'] = $path; + + return $this; + } + + /** + * 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 + * + * @return self + */ + public function setMaxAge($maxAge) + { + $this->data['Max-Age'] = $maxAge; + + return $this; + } + + /** + * 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 + * + * @return self + */ + public function setExpires($timestamp) + { + $this->data['Expires'] = is_numeric($timestamp) + ? (int) $timestamp + : strtotime($timestamp); + + return $this; + } + + /** + * Get whether or not this is a secure cookie + * + * @return null|bool + */ + public function getSecure() + { + return $this->data['Secure']; + } + + /** + * Set whether or not the cookie is secure + * + * @param bool $secure Set to true or false if secure + * + * @return self + */ + public function setSecure($secure) + { + $this->data['Secure'] = $secure; + + return $this; + } + + /** + * Get whether or not this is a session cookie + * + * @return null|bool + */ + public function getDiscard() + { + return $this->data['Discard']; + } + + /** + * Set whether or not this is a session cookie + * + * @param bool $discard Set to true or false if this is a session cookie + * + * @return self + */ + public function setDiscard($discard) + { + $this->data['Discard'] = $discard; + + return $this; + } + + /** + * 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 + * + * @return self + */ + public function setHttpOnly($httpOnly) + { + $this->data['HttpOnly'] = $httpOnly; + + return $this; + } + + /** + * Check if the cookie matches a path value + * + * @param string $path Path to check against + * + * @return bool + */ + public function matchesPath($path) + { + return !$this->getPath() || 0 === stripos($path, $this->getPath()); + } + + /** + * Check if the cookie matches a domain value + * + * @param string $domain Domain to check against + * + * @return bool + */ + public function matchesDomain($domain) + { + // Remove the leading '.' as per spec in RFC 6265. + // http://tools.ietf.org/html/rfc6265#section-5.2.3 + $cookieDomain = ltrim($this->getDomain(), '.'); + + // Domain not set or exact match. + if (!$cookieDomain || !strcasecmp($domain, $cookieDomain)) { + return true; + } + + // Matching the subdomain according to RFC 6265. + // http://tools.ietf.org/html/rfc6265#section-5.1.3 + if (filter_var($domain, FILTER_VALIDATE_IP)) { + return false; + } + + return (bool) preg_match('/\.' . preg_quote($cookieDomain) . '$/i', $domain); + } + + /** + * Check if the cookie is expired + * + * @return bool + */ + public function isExpired() + { + return $this->getExpires() && time() > $this->getExpires(); + } + + /** + * Check if the cookie is valid according to RFC 6265 + * + * @return bool|string Returns true if valid or an error message if invalid + */ + public function validate() + { + // Names must not be empty, but can be 0 + $name = $this->getName(); + if (empty($name) && !is_numeric($name)) { + return 'The cookie name must not be empty'; + } + + // Check if any of the invalid characters are present in the cookie name + if (preg_match("/[=,; \t\r\n\013\014]/", $name)) { + return "Cookie name must not cannot invalid characters: =,; \\t\\r\\n\\013\\014"; + } + + // 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; + } +} diff --git a/core/vendor/guzzlehttp/guzzle/src/Event/AbstractEvent.php b/core/vendor/guzzlehttp/guzzle/src/Event/AbstractEvent.php new file mode 100644 index 00000000000..fa1453c8420 --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/src/Event/AbstractEvent.php @@ -0,0 +1,21 @@ +propagationStopped; + } + + public function stopPropagation() + { + $this->propagationStopped = true; + } +} diff --git a/core/vendor/guzzlehttp/guzzle/src/Event/AbstractRequestEvent.php b/core/vendor/guzzlehttp/guzzle/src/Event/AbstractRequestEvent.php new file mode 100644 index 00000000000..d188248ac6f --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/src/Event/AbstractRequestEvent.php @@ -0,0 +1,49 @@ +transaction = $transaction; + } + + /** + * Get the client associated with the event + * + * @return ClientInterface + */ + public function getClient() + { + return $this->transaction->getClient(); + } + + /** + * Get the request object + * + * @return RequestInterface + */ + public function getRequest() + { + return $this->transaction->getRequest(); + } + + /** + * @return TransactionInterface + */ + protected function getTransaction() + { + return $this->transaction; + } +} diff --git a/core/vendor/guzzlehttp/guzzle/src/Event/AbstractTransferEvent.php b/core/vendor/guzzlehttp/guzzle/src/Event/AbstractTransferEvent.php new file mode 100644 index 00000000000..f6b8f38d723 --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/src/Event/AbstractTransferEvent.php @@ -0,0 +1,83 @@ +transferInfo = $transferInfo; + } + + /** + * Get all transfer information as an associative array if no $name + * argument is supplied, or gets a specific transfer statistic if + * a $name attribute is supplied (e.g., 'total_time'). + * + * @param string $name Name of the transfer stat to retrieve + * + * @return mixed|null|array + */ + public function getTransferInfo($name = null) + { + if (!$name) { + return $this->transferInfo; + } + + return isset($this->transferInfo[$name]) + ? $this->transferInfo[$name] + : null; + } + + /** + * Get the response + * + * @return ResponseInterface|null + */ + abstract public function getResponse(); + + /** + * Intercept the request and associate a response + * + * @param ResponseInterface $response Response to set + */ + abstract public function intercept(ResponseInterface $response); +} diff --git a/core/vendor/guzzlehttp/guzzle/src/Event/BeforeEvent.php b/core/vendor/guzzlehttp/guzzle/src/Event/BeforeEvent.php new file mode 100644 index 00000000000..34a7811d6dc --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/src/Event/BeforeEvent.php @@ -0,0 +1,26 @@ +getTransaction()->setResponse($response); + $this->stopPropagation(); + RequestEvents::emitComplete($this->getTransaction()); + } +} diff --git a/core/vendor/guzzlehttp/guzzle/src/Event/CompleteEvent.php b/core/vendor/guzzlehttp/guzzle/src/Event/CompleteEvent.php new file mode 100644 index 00000000000..344576001ae --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/src/Event/CompleteEvent.php @@ -0,0 +1,35 @@ +stopPropagation(); + $this->getTransaction()->setResponse($response); + } + + /** + * Get the response of the request + * + * @return ResponseInterface + */ + public function getResponse() + { + return $this->getTransaction()->getResponse(); + } +} diff --git a/core/vendor/guzzlehttp/guzzle/src/Event/Emitter.php b/core/vendor/guzzlehttp/guzzle/src/Event/Emitter.php new file mode 100644 index 00000000000..49172bcb50b --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/src/Event/Emitter.php @@ -0,0 +1,147 @@ + + * + * For the full copyright and license information, please view the LICENSE + * file that was distributed with this source code. + * + * @link https://github.com/symfony/symfony/tree/master/src/Symfony/Component/EventDispatcher + */ +class Emitter implements EmitterInterface +{ + /** @var array */ + private $listeners = []; + + /** @var array */ + private $sorted = []; + + public function on($eventName, callable $listener, $priority = 0) + { + if ($priority === 'first') { + $priority = isset($this->listeners[$eventName]) + ? max(array_keys($this->listeners[$eventName])) + 1 + : 1; + } elseif ($priority === 'last') { + $priority = isset($this->listeners[$eventName]) + ? min(array_keys($this->listeners[$eventName])) - 1 + : -1; + } + + $this->listeners[$eventName][$priority][] = $listener; + unset($this->sorted[$eventName]); + } + + public function once($eventName, callable $listener, $priority = 0) + { + $onceListener = function ( + EventInterface $event, + $eventName + ) use (&$onceListener, $eventName, $listener, $priority) { + $this->removeListener($eventName, $onceListener); + $listener($event, $eventName, $this); + }; + + $this->on($eventName, $onceListener, $priority); + } + + public function removeListener($eventName, callable $listener) + { + if (!isset($this->listeners[$eventName])) { + return; + } + + foreach ($this->listeners[$eventName] as $priority => $listeners) { + if (false !== ($key = array_search($listener, $listeners, true))) { + unset( + $this->listeners[$eventName][$priority][$key], + $this->sorted[$eventName] + ); + } + } + } + + public function listeners($eventName = null) + { + // Return all events in a sorted priority order + if ($eventName === null) { + foreach (array_keys($this->listeners) as $eventName) { + if (!isset($this->sorted[$eventName])) { + $this->listeners($eventName); + } + } + return $this->sorted; + } + + // Return the listeners for a specific event, sorted in priority order + if (!isset($this->sorted[$eventName])) { + if (!isset($this->listeners[$eventName])) { + return []; + } else { + krsort($this->listeners[$eventName]); + $this->sorted[$eventName] = call_user_func_array( + 'array_merge', + $this->listeners[$eventName] + ); + } + } + + return $this->sorted[$eventName]; + } + + public function emit($eventName, EventInterface $event) + { + if (isset($this->listeners[$eventName])) { + foreach ($this->listeners($eventName) as $listener) { + $listener($event, $eventName); + if ($event->isPropagationStopped()) { + break; + } + } + } + + return $event; + } + + public function attach(SubscriberInterface $subscriber) + { + foreach ($subscriber->getEvents() as $eventName => $listener) { + $this->on( + $eventName, + array($subscriber, $listener[0]), + isset($listener[1]) ? $listener[1] : 0 + ); + } + } + + public function detach(SubscriberInterface $subscriber) + { + foreach ($subscriber->getEvents() as $eventName => $listener) { + $this->removeListener($eventName, array($subscriber, $listener[0])); + } + } + + public function __call($name, $arguments) + { + return \GuzzleHttp\deprecation_proxy( + $this, + $name, + $arguments, + [ + 'addSubscriber' => 'attach', + 'removeSubscriber' => 'detach', + 'addListener' => 'on', + 'dispatch' => 'emit' + ] + ); + } +} diff --git a/core/vendor/guzzlehttp/guzzle/src/Event/EmitterInterface.php b/core/vendor/guzzlehttp/guzzle/src/Event/EmitterInterface.php new file mode 100644 index 00000000000..0181e7fe713 --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/src/Event/EmitterInterface.php @@ -0,0 +1,88 @@ +exception = $e; + } + + /** + * Intercept the exception and inject a response + * + * @param ResponseInterface $response Response to set + */ + public function intercept(ResponseInterface $response) + { + $this->stopPropagation(); + $this->getTransaction()->setResponse($response); + RequestEvents::emitComplete($this->getTransaction()); + } + + /** + * Get the exception that was encountered + * + * @return RequestException + */ + public function getException() + { + return $this->exception; + } + + /** + * Get the response the was received (if any) + * + * @return ResponseInterface|null + */ + public function getResponse() + { + return $this->getException()->getResponse(); + } +} diff --git a/core/vendor/guzzlehttp/guzzle/src/Event/EventInterface.php b/core/vendor/guzzlehttp/guzzle/src/Event/EventInterface.php new file mode 100644 index 00000000000..bf58f8b5146 --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/src/Event/EventInterface.php @@ -0,0 +1,24 @@ +emitter) { + $this->emitter = new Emitter(); + } + + return $this->emitter; + } +} diff --git a/core/vendor/guzzlehttp/guzzle/src/Event/HeadersEvent.php b/core/vendor/guzzlehttp/guzzle/src/Event/HeadersEvent.php new file mode 100644 index 00000000000..81274ff84a6 --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/src/Event/HeadersEvent.php @@ -0,0 +1,39 @@ +getResponse()) { + throw new \RuntimeException('A response must be present'); + } + } + + /** + * Get the response the was received + * + * @return ResponseInterface + */ + public function getResponse() + { + return $this->getTransaction()->getResponse(); + } +} diff --git a/core/vendor/guzzlehttp/guzzle/src/Event/RequestEvents.php b/core/vendor/guzzlehttp/guzzle/src/Event/RequestEvents.php new file mode 100644 index 00000000000..252c0af9b43 --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/src/Event/RequestEvents.php @@ -0,0 +1,130 @@ +getRequest(); + try { + $request->getEmitter()->emit( + 'before', + new BeforeEvent($transaction) + ); + } catch (RequestException $e) { + // When a RequestException has been emitted through emitError, the + // exception is marked as "emitted". This means that the exception + // had a chance to be rescued but was not. In this case, this method + // must not emit the error again, but rather throw the exception. + // This prevents RequestExceptions encountered during the before + // event from being emitted to listeners twice. + if ($e->emittedError()) { + throw $e; + } + self::emitError($transaction, $e); + } catch (\Exception $e) { + self::emitError($transaction, $e); + } + } + + /** + * Emits the complete event for a request and emits an error + * event if an error is encountered during the after send. + * + * @param TransactionInterface $transaction Transaction to emit for + * @param array $stats Transfer stats + * + * @throws RequestException + */ + public static function emitComplete( + TransactionInterface $transaction, + array $stats = [] + ) { + $request = $transaction->getRequest(); + $transaction->getResponse()->setEffectiveUrl($request->getUrl()); + try { + $request->getEmitter()->emit( + 'complete', + new CompleteEvent($transaction, $stats) + ); + } catch (RequestException $e) { + self::emitError($transaction, $e, $stats); + } + } + + /** + * Emits the headers event for a request. + * + * @param TransactionInterface $transaction Transaction to emit for + */ + public static function emitHeaders(TransactionInterface $transaction) + { + $transaction->getRequest()->getEmitter()->emit( + 'headers', + new HeadersEvent($transaction) + ); + } + + /** + * Emits an error event for a request and accounts for the propagation + * of an error event being stopped to prevent the exception from being + * thrown. + * + * @param TransactionInterface $transaction + * @param \Exception $e + * @param array $stats + * + * @throws \GuzzleHttp\Exception\RequestException + */ + public static function emitError( + TransactionInterface $transaction, + \Exception $e, + array $stats = [] + ) { + $request = $transaction->getRequest(); + + // Convert non-request exception to a wrapped exception + if (!($e instanceof RequestException)) { + $e = new RequestException($e->getMessage(), $request, null, $e); + } + + // Mark the exception as having been emitted for an error event. This + // works in tandem with the emitBefore method to prevent the error + // event from being triggered twice for the same exception. + $e->emittedError(true); + + // Dispatch an event and allow interception + if (!$request->getEmitter()->emit( + 'error', + new ErrorEvent($transaction, $e, $stats) + )->isPropagationStopped()) { + throw $e; + } + } +} diff --git a/core/vendor/guzzlehttp/guzzle/src/Event/SubscriberInterface.php b/core/vendor/guzzlehttp/guzzle/src/Event/SubscriberInterface.php new file mode 100644 index 00000000000..22c7311900f --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/src/Event/SubscriberInterface.php @@ -0,0 +1,31 @@ + ['methodName']] + * - ['eventName' => ['methodName', $priority]] + * + * @return array + */ + public function getEvents(); +} diff --git a/core/vendor/guzzlehttp/guzzle/src/Exception/AdapterException.php b/core/vendor/guzzlehttp/guzzle/src/Exception/AdapterException.php new file mode 100644 index 00000000000..55334c464c2 --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/src/Exception/AdapterException.php @@ -0,0 +1,5 @@ +response = $response; + } + /** + * Get the associated response + * + * @return ResponseInterface|null + */ + public function getResponse() + { + return $this->response; + } +} diff --git a/core/vendor/guzzlehttp/guzzle/src/Exception/RequestException.php b/core/vendor/guzzlehttp/guzzle/src/Exception/RequestException.php new file mode 100644 index 00000000000..2c3e426ff80 --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/src/Exception/RequestException.php @@ -0,0 +1,123 @@ +request = $request; + $this->response = $response; + } + + /** + * 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 + * + * @return self + */ + public static function create( + RequestInterface $request, + ResponseInterface $response = null, + \Exception $previous = null + ) { + if (!$response) { + return new self('Error completing request', $request, null, $previous); + } + + $level = $response->getStatusCode()[0]; + if ($level == '4') { + $label = 'Client error response'; + $className = __NAMESPACE__ . '\\ClientException'; + } elseif ($level == '5') { + $label = 'Server error response'; + $className = __NAMESPACE__ . '\\ServerException'; + } else { + $label = 'Unsuccessful response'; + $className = __CLASS__; + } + + $message = $label . ' [url] ' . $request->getUrl() + . ' [status code] ' . $response->getStatusCode() + . ' [reason phrase] ' . $response->getReasonPhrase(); + + return new $className($message, $request, $response, $previous); + } + + /** + * 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; + } + + /** + * Check or set if the exception was emitted in an error event. + * + * This value is used in the RequestEvents::emitBefore() method to check + * to see if an exception has already been emitted in an error event. + * + * @param bool|null Set to true to set the exception as having emitted an + * error. Leave null to retrieve the current setting. + * + * @return null|bool + * @throws \InvalidArgumentException if you attempt to set the value to false + */ + public function emittedError($value = null) + { + if ($value === null) { + return $this->emittedErrorEvent; + } elseif ($value === true) { + return $this->emittedErrorEvent = true; + } else { + throw new \InvalidArgumentException('You cannot set the emitted ' + . 'error value to false.'); + } + } +} diff --git a/core/vendor/guzzlehttp/guzzle/src/Exception/ServerException.php b/core/vendor/guzzlehttp/guzzle/src/Exception/ServerException.php new file mode 100644 index 00000000000..d67ed27e342 --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/src/Exception/ServerException.php @@ -0,0 +1,8 @@ +data); + } + + public function offsetGet($offset) + { + return isset($this->data[$offset]) ? $this->data[$offset] : null; + } + + public function offsetSet($offset, $value) + { + $this->data[$offset] = $value; + } + + public function offsetExists($offset) + { + return isset($this->data[$offset]); + } + + public function offsetUnset($offset) + { + unset($this->data[$offset]); + } + + public function toArray() + { + return $this->data; + } + + public function count() + { + return count($this->data); + } + + /** + * Get a value from the collection using a path syntax to retrieve nested + * data. + * + * @param string $path Path to traverse and retrieve a value from + * + * @return mixed|null + */ + public function getPath($path) + { + return \GuzzleHttp\get_path($this->data, $path); + } + + /** + * Set a value into a nested array key. Keys will be created as needed to + * set the value. + * + * @param string $path Path to set + * @param mixed $value Value to set at the key + * + * @throws \RuntimeException when trying to setPath using a nested path + * that travels through a scalar value + */ + public function setPath($path, $value) + { + \GuzzleHttp\set_path($this->data, $path, $value); + } +} diff --git a/core/vendor/guzzlehttp/guzzle/src/Message/AbstractMessage.php b/core/vendor/guzzlehttp/guzzle/src/Message/AbstractMessage.php new file mode 100644 index 00000000000..6037a70e6a2 --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/src/Message/AbstractMessage.php @@ -0,0 +1,237 @@ +getStartLine(); + foreach ($this->getHeaders() as $name => $values) { + $result .= "\r\n{$name}: " . implode(', ', $values); + } + + return $result . "\r\n\r\n" . $this->body; + } + + public function getProtocolVersion() + { + return $this->protocolVersion; + } + + public function getBody() + { + return $this->body; + } + + public function setBody(StreamInterface $body = null) + { + if ($body === null) { + // Setting a null body will remove the body of the request + $this->removeHeader('Content-Length') + ->removeHeader('Transfer-Encoding'); + } + + $this->body = $body; + + return $this; + } + + public function addHeader($header, $value) + { + static $valid = ['string' => true, 'integer' => true, + 'double' => true, 'array' => true]; + + $type = gettype($value); + if (!isset($valid[$type])) { + throw new \InvalidArgumentException('Invalid header value'); + } + + if ($type == 'array') { + $current = array_merge($this->getHeader($header, true), $value); + } else { + $current = $this->getHeader($header, true); + $current[] = $value; + } + + return $this->setHeader($header, $current); + } + + public function addHeaders(array $headers) + { + foreach ($headers as $name => $header) { + $this->addHeader($name, $header); + } + } + + public function getHeader($header, $asArray = false) + { + $name = strtolower($header); + + if (!isset($this->headers[$name])) { + return $asArray ? [] : ''; + } + + return $asArray + ? $this->headers[$name] + : implode(', ', $this->headers[$name]); + } + + public function getHeaders() + { + $headers = []; + foreach ($this->headers as $name => $values) { + $headers[$this->headerNames[$name]] = $values; + } + + return $headers; + } + + public function setHeader($header, $value) + { + $header = trim($header); + $name = strtolower($header); + $this->headerNames[$name] = $header; + + switch (gettype($value)) { + case 'string': + $this->headers[$name] = [trim($value)]; + break; + case 'integer': + case 'double': + $this->headers[$name] = [(string) $value]; + break; + case 'array': + foreach ($value as &$v) { + $v = trim($v); + } + $this->headers[$name] = $value; + break; + default: + throw new \InvalidArgumentException('Invalid header value ' + . 'provided: ' . var_export($value, true)); + } + + return $this; + } + + public function setHeaders(array $headers) + { + $this->headers = $this->headerNames = []; + foreach ($headers as $key => $value) { + $this->setHeader($key, $value); + } + + return $this; + } + + public function hasHeader($header) + { + return isset($this->headers[strtolower($header)]); + } + + public function removeHeader($header) + { + $name = strtolower($header); + unset($this->headers[$name], $this->headerNames[$name]); + + return $this; + } + + /** + * Parse an array of header values containing ";" separated data into an + * array of associative arrays representing the header key value pair + * data of the header. When a parameter does not contain a value, but just + * contains a key, this function will inject a key with a '' string value. + * + * @param MessageInterface $message That contains the header + * @param string $header Header to retrieve from the message + * + * @return array Returns the parsed header values. + */ + public static function parseHeader(MessageInterface $message, $header) + { + static $trimmed = "\"' \n\t\r"; + $params = $matches = []; + + foreach (self::normalizeHeader($message, $header) as $val) { + $part = []; + foreach (preg_split('/;(?=([^"]*"[^"]*")*[^"]*$)/', $val) as $kvp) { + if (preg_match_all('/<[^>]+>|[^=]+/', $kvp, $matches)) { + $m = $matches[0]; + if (isset($m[1])) { + $part[trim($m[0], $trimmed)] = trim($m[1], $trimmed); + } else { + $part[] = trim($m[0], $trimmed); + } + } + } + if ($part) { + $params[] = $part; + } + } + + return $params; + } + + /** + * Converts an array of header values that may contain comma separated + * headers into an array of headers with no comma separated values. + * + * @param MessageInterface $message That contains the header + * @param string $header Header to retrieve from the message + * + * @return array Returns the normalized header field values. + */ + public static function normalizeHeader(MessageInterface $message, $header) + { + $h = $message->getHeader($header, true); + for ($i = 0, $total = count($h); $i < $total; $i++) { + if (strpos($h[$i], ',') === false) { + continue; + } + foreach (preg_split('/,(?=([^"]*"[^"]*")*[^"]*$)/', $h[$i]) as $v) { + $h[] = trim($v); + } + unset($h[$i]); + } + + return $h; + } + + /** + * Returns the start line of a message. + * + * @return string + */ + abstract protected function getStartLine(); + + /** + * Accepts and modifies the options provided to the message in the + * constructor. + * + * Can be overridden in subclasses as necessary. + * + * @param array $options Options array passed by reference. + */ + protected function handleOptions(array &$options) + { + if (isset($options['protocol_version'])) { + $this->protocolVersion = $options['protocol_version']; + } + } +} diff --git a/core/vendor/guzzlehttp/guzzle/src/Message/MessageFactory.php b/core/vendor/guzzlehttp/guzzle/src/Message/MessageFactory.php new file mode 100644 index 00000000000..9305fe69728 --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/src/Message/MessageFactory.php @@ -0,0 +1,335 @@ +errorPlugin = new HttpError(); + $this->redirectPlugin = new Redirect(); + } + + public function createResponse( + $statusCode, + array $headers = [], + $body = null, + array $options = [] + ) { + if (null !== $body) { + $body = Stream\create($body); + } + + return new Response($statusCode, $headers, $body, $options); + } + + public function createRequest($method, $url, array $options = []) + { + // Handle the request protocol version option that needs to be + // specified in the request constructor. + if (isset($options['version'])) { + $options['config']['protocol_version'] = $options['version']; + unset($options['version']); + } + + $request = new Request($method, $url, [], null, + isset($options['config']) ? $options['config'] : []); + + unset($options['config']); + + // Use a POST body by default + if ($method == 'POST' && !isset($options['body'])) { + $options['body'] = []; + } + + if ($options) { + $this->applyOptions($request, $options); + } + + return $request; + } + + /** + * Create a request or response object from an HTTP message string + * + * @param string $message Message to parse + * + * @return RequestInterface|ResponseInterface + * @throws \InvalidArgumentException if unable to parse a message + */ + public function fromMessage($message) + { + static $parser; + if (!$parser) { + $parser = new MessageParser(); + } + + // Parse a response + if (strtoupper(substr($message, 0, 4)) == 'HTTP') { + $data = $parser->parseResponse($message); + return $this->createResponse( + $data['code'], + $data['headers'], + $data['body'] === '' ? null : $data['body'], + $data + ); + } + + // Parse a request + if (!($data = ($parser->parseRequest($message)))) { + throw new \InvalidArgumentException('Unable to parse request'); + } + + return $this->createRequest( + $data['method'], + Url::buildUrl($data['request_url']), + [ + 'headers' => $data['headers'], + 'body' => $data['body'] === '' ? null : $data['body'], + 'config' => [ + 'protocol_version' => $data['protocol_version'] + ] + ] + ); + } + + /** + * Apply POST fields and files to a request to attempt to give an accurate + * representation. + * + * @param RequestInterface $request Request to update + * @param array $body Body to apply + */ + protected function addPostData(RequestInterface $request, array $body) + { + $post = new PostBody(); + foreach ($body as $key => $value) { + if (is_string($value) || is_array($value)) { + $post->setField($key, $value); + } elseif ($value instanceof PostFileInterface) { + $post->addFile($value); + } else { + $post->addFile(new PostFile($key, $value)); + } + } + + $request->setBody($post); + $post->applyRequestHeaders($request); + } + + protected function applyOptions( + RequestInterface $request, + array $options = [] + ) { + // Values specified in the config map are passed to request options + static $configMap = ['connect_timeout' => 1, 'timeout' => 1, + 'verify' => 1, 'ssl_key' => 1, 'cert' => 1, 'proxy' => 1, + 'debug' => 1, 'save_to' => 1, 'stream' => 1, 'expect' => 1]; + static $methods; + if (!$methods) { + $methods = array_flip(get_class_methods(__CLASS__)); + } + + // Iterate over each key value pair and attempt to apply a config using + // double dispatch. + $config = $request->getConfig(); + foreach ($options as $key => $value) { + $method = "add_{$key}"; + if (isset($methods[$method])) { + $this->{$method}($request, $value); + } elseif (isset($configMap[$key])) { + $config[$key] = $value; + } else { + throw new \InvalidArgumentException("No method is configured " + . "to handle the {$key} config key"); + } + } + } + + private function add_body(RequestInterface $request, $value) + { + if ($value !== null) { + if (is_array($value)) { + $this->addPostData($request, $value); + } else { + $request->setBody(Stream\create($value)); + } + } + } + + private function add_allow_redirects(RequestInterface $request, $value) + { + static $defaultRedirect = [ + 'max' => 5, + 'strict' => false, + 'referer' => false + ]; + + if ($value === false) { + return; + } + + if ($value === true) { + $value = $defaultRedirect; + } elseif (!isset($value['max'])) { + throw new \InvalidArgumentException('allow_redirects must be ' + . 'true, false, or an array that contains the \'max\' key'); + } else { + // Merge the default settings with the provided settings + $value += $defaultRedirect; + } + + $request->getConfig()['redirect'] = $value; + $request->getEmitter()->attach($this->redirectPlugin); + } + + private function add_exceptions(RequestInterface $request, $value) + { + if ($value === true) { + $request->getEmitter()->attach($this->errorPlugin); + } + } + + private function add_auth(RequestInterface $request, $value) + { + if (!$value) { + return; + } elseif (is_array($value)) { + $authType = isset($value[2]) ? strtolower($value[2]) : 'basic'; + } else { + $authType = strtolower($value); + } + + $request->getConfig()->set('auth', $value); + + if ($authType == 'basic') { + $request->setHeader( + 'Authorization', + 'Basic ' . base64_encode("$value[0]:$value[1]") + ); + } elseif ($authType == 'digest') { + // Currently only implemented by the cURL adapter. + // @todo: Need an event listener solution that does not rely on cURL + $config = $request->getConfig(); + $config->setPath('curl/' . CURLOPT_HTTPAUTH, CURLAUTH_DIGEST); + $config->setPath('curl/' . CURLOPT_USERPWD, "$value[0]:$value[1]"); + } + } + + private function add_query(RequestInterface $request, $value) + { + if ($value instanceof Query) { + $original = $request->getQuery(); + // Do not overwrite existing query string variables by overwriting + // the object with the query string data passed in the URL + $request->setQuery($value->overwriteWith($original->toArray())); + } elseif (is_array($value)) { + // Do not overwrite existing query string variables + $query = $request->getQuery(); + foreach ($value as $k => $v) { + if (!isset($query[$k])) { + $query[$k] = $v; + } + } + } else { + throw new \InvalidArgumentException('query value must be an array ' + . 'or Query object'); + } + } + + private function add_headers(RequestInterface $request, $value) + { + if (!is_array($value)) { + throw new \InvalidArgumentException('header value must be an array'); + } + + // Do not overwrite existing headers + foreach ($value as $k => $v) { + if (!$request->hasHeader($k)) { + $request->setHeader($k, $v); + } + } + } + + private function add_cookies(RequestInterface $request, $value) + { + if ($value === true) { + static $cookie = null; + if (!$cookie) { + $cookie = new Cookie(); + } + $request->getEmitter()->attach($cookie); + } elseif (is_array($value)) { + $request->getEmitter()->attach( + new Cookie(CookieJar::fromArray($value, $request->getHost())) + ); + } elseif ($value instanceof CookieJarInterface) { + $request->getEmitter()->attach(new Cookie($value)); + } elseif ($value !== false) { + throw new \InvalidArgumentException('cookies must be an array, ' + . 'true, or a CookieJarInterface object'); + } + } + + private function add_events(RequestInterface $request, $value) + { + if (!is_array($value)) { + throw new \InvalidArgumentException('events value must be an array'); + } + + $emitter = $request->getEmitter(); + foreach ($value as $name => $method) { + if (is_callable($method)) { + $emitter->on($name, $method); + } elseif (!is_array($method) || !isset($method['fn'])) { + throw new \InvalidArgumentException('Each event must be a ' + . 'callable or associative array containing a "fn" key'); + } elseif (isset($method['once']) && $method['once'] === true) { + $emitter->once( + $name, + $method['fn'], + isset($method['priority']) ? $method['priority'] : 0 + ); + } else { + $emitter->on( + $name, + $method['fn'], + isset($method['priority']) ? $method['priority'] : 0 + ); + } + } + } + + private function add_subscribers(RequestInterface $request, $value) + { + if (!is_array($value)) { + throw new \InvalidArgumentException('subscribers must be an array'); + } + + $emitter = $request->getEmitter(); + foreach ($value as $subscribers) { + $emitter->attach($subscribers); + } + } +} diff --git a/core/vendor/guzzlehttp/guzzle/src/Message/MessageFactoryInterface.php b/core/vendor/guzzlehttp/guzzle/src/Message/MessageFactoryInterface.php new file mode 100644 index 00000000000..d8de3d6f54c --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/src/Message/MessageFactoryInterface.php @@ -0,0 +1,70 @@ +getHeaders() as $name => $values) { + * echo $name . ": " . implode(", ", $values); + * } + * + * @return array Returns an associative array of the message's headers. + */ + public function getHeaders(); + + /** + * Retrieve a header by the given case-insensitive name. + * + * By default, this method returns all of the header values of the given + * case-insensitive header name as a string concatenated together using + * a comma. Because some header should not be concatenated together using a + * comma, this method provides a Boolean argument that can be used to + * retrieve the associated header values as an array of strings. + * + * @param string $header Case-insensitive header name. + * @param bool $asArray Set to true to retrieve the header value as an + * array of strings. + * + * @return array|string + */ + public function getHeader($header, $asArray = false); + + /** + * Checks if a header exists by the given case-insensitive name. + * + * @param string $header Case-insensitive header name. + * + * @return bool Returns true if any header names match the given header + * name using a case-insensitive string comparison. Returns false if + * no matching header name is found in the message. + */ + public function hasHeader($header); + + /** + * Remove a specific header by case-insensitive name. + * + * @param string $header Case-insensitive header name. + * + * @return self + */ + public function removeHeader($header); + + /** + * Appends a header value to any existing values associated with the + * given header name. + * + * @param string $header Header name to add + * @param string $value Value of the header + * + * @return self + */ + public function addHeader($header, $value); + + /** + * Merges in an associative array of headers. + * + * Each array key MUST be a string representing the case-insensitive name + * of a header. Each value MUST be either a string or an array of strings. + * For each value, the value is appended to any existing header of the same + * name, or, if a header does not already exist by the given name, then the + * header is added. + * + * @param array $headers Associative array of headers to add to the message + * + * @return self + */ + public function addHeaders(array $headers); + + /** + * Sets a header, replacing any existing values of any headers with the + * same case-insensitive name. + * + * The header values MUST be a string or an array of strings. + * + * @param string $header Header name + * @param string|array $value Header value(s) + * + * @return self Returns the message. + */ + public function setHeader($header, $value); + + /** + * Sets headers, replacing any headers that have already been set on the + * message. + * + * The array keys MUST be a string. The array values must be either a + * string or an array of strings. + * + * @param array $headers Headers to set. + * + * @return self Returns the message. + */ + public function setHeaders(array $headers); +} diff --git a/core/vendor/guzzlehttp/guzzle/src/Message/MessageParser.php b/core/vendor/guzzlehttp/guzzle/src/Message/MessageParser.php new file mode 100644 index 00000000000..2c49c9ecc19 --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/src/Message/MessageParser.php @@ -0,0 +1,171 @@ +parseMessage($message))) { + return false; + } + + // Parse the protocol and protocol version + if (isset($parts['start_line'][2])) { + $startParts = explode('/', $parts['start_line'][2]); + $protocol = strtoupper($startParts[0]); + $version = isset($startParts[1]) ? $startParts[1] : '1.1'; + } else { + $protocol = 'HTTP'; + $version = '1.1'; + } + + $parsed = [ + 'method' => strtoupper($parts['start_line'][0]), + 'protocol' => $protocol, + 'protocol_version' => $version, + 'headers' => $parts['headers'], + 'body' => $parts['body'] + ]; + + $parsed['request_url'] = $this->getUrlPartsFromMessage($parts['start_line'][1], $parsed); + + return $parsed; + } + + /** + * Parse an HTTP response message into an associative array of parts. + * + * @param string $message HTTP response to parse + * + * @return array|bool Returns false if the message is invalid + */ + public function parseResponse($message) + { + if (!($parts = $this->parseMessage($message))) { + return false; + } + + list($protocol, $version) = explode('/', trim($parts['start_line'][0])); + + return [ + 'protocol' => $protocol, + 'protocol_version' => $version, + 'code' => $parts['start_line'][1], + 'reason_phrase' => isset($parts['start_line'][2]) ? $parts['start_line'][2] : '', + 'headers' => $parts['headers'], + 'body' => $parts['body'] + ]; + } + + /** + * Parse a message into parts + * + * @param string $message Message to parse + * + * @return array|bool + */ + private function parseMessage($message) + { + if (!$message) { + return false; + } + + $startLine = null; + $headers = []; + $body = ''; + + // Iterate over each line in the message, accounting for line endings + $lines = preg_split('/(\\r?\\n)/', $message, -1, PREG_SPLIT_DELIM_CAPTURE); + for ($i = 0, $totalLines = count($lines); $i < $totalLines; $i += 2) { + + $line = $lines[$i]; + + // If two line breaks were encountered, then this is the end of body + if (empty($line)) { + if ($i < $totalLines - 1) { + $body = implode('', array_slice($lines, $i + 2)); + } + break; + } + + // Parse message headers + if (!$startLine) { + $startLine = explode(' ', $line, 3); + } elseif (strpos($line, ':')) { + $parts = explode(':', $line, 2); + $key = trim($parts[0]); + $value = isset($parts[1]) ? trim($parts[1]) : ''; + if (!isset($headers[$key])) { + $headers[$key] = $value; + } elseif (!is_array($headers[$key])) { + $headers[$key] = [$headers[$key], $value]; + } else { + $headers[$key][] = $value; + } + } + } + + return [ + 'start_line' => $startLine, + 'headers' => $headers, + 'body' => $body + ]; + } + + /** + * Create URL parts from HTTP message parts + * + * @param string $requestUrl Associated URL + * @param array $parts HTTP message parts + * + * @return array + */ + private function getUrlPartsFromMessage($requestUrl, array $parts) + { + // Parse the URL information from the message + $urlParts = ['path' => $requestUrl, 'scheme' => 'http']; + + // Check for the Host header + if (isset($parts['headers']['Host'])) { + $urlParts['host'] = $parts['headers']['Host']; + } elseif (isset($parts['headers']['host'])) { + $urlParts['host'] = $parts['headers']['host']; + } else { + $urlParts['host'] = null; + } + + if (false === strpos($urlParts['host'], ':')) { + $urlParts['port'] = ''; + } else { + $hostParts = explode(':', $urlParts['host']); + $urlParts['host'] = trim($hostParts[0]); + $urlParts['port'] = (int) trim($hostParts[1]); + if ($urlParts['port'] == 443) { + $urlParts['scheme'] = 'https'; + } + } + + // Check if a query is present + $path = $urlParts['path']; + $qpos = strpos($path, '?'); + if ($qpos) { + $urlParts['query'] = substr($path, $qpos + 1); + $urlParts['path'] = substr($path, 0, $qpos); + } else { + $urlParts['query'] = ''; + } + + return $urlParts; + } +} diff --git a/core/vendor/guzzlehttp/guzzle/src/Message/Request.php b/core/vendor/guzzlehttp/guzzle/src/Message/Request.php new file mode 100644 index 00000000000..aa37034c92d --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/src/Message/Request.php @@ -0,0 +1,203 @@ +setUrl($url); + $this->method = strtoupper($method); + $this->handleOptions($options); + $this->transferOptions = new Collection($options); + $this->addPrepareEvent(); + + if ($body !== null) { + $this->setBody($body); + } + + if ($headers) { + foreach ($headers as $key => $value) { + $this->setHeader($key, $value); + } + } + } + + public function __clone() + { + if ($this->emitter) { + $this->emitter = clone $this->emitter; + } + $this->transferOptions = clone $this->transferOptions; + $this->url = clone $this->url; + } + + public function setUrl($url) + { + $this->url = $url instanceof Url ? $url : Url::fromString($url); + $this->updateHostHeaderFromUrl(); + + return $this; + } + + public function getUrl() + { + return (string) $this->url; + } + + public function setQuery($query) + { + $this->url->setQuery($query); + + return $this; + } + + public function getQuery() + { + return $this->url->getQuery(); + } + + public function setMethod($method) + { + $this->method = strtoupper($method); + + return $this; + } + + public function getMethod() + { + return $this->method; + } + + public function getScheme() + { + return $this->url->getScheme(); + } + + public function setScheme($scheme) + { + $this->url->setScheme($scheme); + + return $this; + } + + public function getHost() + { + return $this->url->getHost(); + } + + public function setHost($host) + { + $this->url->setHost($host); + $this->updateHostHeaderFromUrl(); + + return $this; + } + + public function getPath() + { + return '/' . ltrim($this->url->getPath(), '/'); + } + + public function setPath($path) + { + $this->url->setPath($path); + + return $this; + } + + public function getResource() + { + $resource = $this->getPath(); + if ($query = (string) $this->url->getQuery()) { + $resource .= '?' . $query; + } + + return $resource; + } + + public function getConfig() + { + return $this->transferOptions; + } + + protected function handleOptions(array &$options) + { + parent::handleOptions($options); + // Use a custom emitter if one is specified, and remove it from + // options that are exposed through getConfig() + if (isset($options['emitter'])) { + $this->emitter = $options['emitter']; + unset($options['emitter']); + } + } + + protected function getStartLine() + { + return trim($this->method . ' ' . $this->getResource()) + . ' HTTP/' . $this->getProtocolVersion(); + } + + /** + * Adds a subscriber that ensures a request's body is prepared before + * sending. + */ + private function addPrepareEvent() + { + static $subscriber; + if (!$subscriber) { + $subscriber = new Prepare(); + } + + $this->getEmitter()->attach($subscriber); + } + + private function updateHostHeaderFromUrl() + { + $port = $this->url->getPort(); + $scheme = $this->url->getScheme(); + if ($host = $this->url->getHost()) { + if (($port == 80 && $scheme == 'http') || + ($port == 443 && $scheme == 'https') + ) { + $this->setHeader('Host', $this->url->getHost()); + } else { + $this->setHeader('Host', $this->url->getHost() . ':' . $port); + } + } + } +} diff --git a/core/vendor/guzzlehttp/guzzle/src/Message/RequestInterface.php b/core/vendor/guzzlehttp/guzzle/src/Message/RequestInterface.php new file mode 100644 index 00000000000..255632296ca --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/src/Message/RequestInterface.php @@ -0,0 +1,144 @@ + 'Continue', + 101 => 'Switching Protocols', + 102 => 'Processing', + 200 => 'OK', + 201 => 'Created', + 202 => 'Accepted', + 203 => 'Non-Authoritative Information', + 204 => 'No Content', + 205 => 'Reset Content', + 206 => 'Partial Content', + 207 => 'Multi-Status', + 208 => 'Already Reported', + 226 => 'IM Used', + 300 => 'Multiple Choices', + 301 => 'Moved Permanently', + 302 => 'Found', + 303 => 'See Other', + 304 => 'Not Modified', + 305 => 'Use Proxy', + 307 => 'Temporary Redirect', + 308 => 'Permanent Redirect', + 400 => 'Bad Request', + 401 => 'Unauthorized', + 402 => 'Payment Required', + 403 => 'Forbidden', + 404 => 'Not Found', + 405 => 'Method Not Allowed', + 406 => 'Not Acceptable', + 407 => 'Proxy Authentication Required', + 408 => 'Request Timeout', + 409 => 'Conflict', + 410 => 'Gone', + 411 => 'Length Required', + 412 => 'Precondition Failed', + 413 => 'Request Entity Too Large', + 414 => 'Request-URI Too Long', + 415 => 'Unsupported Media Type', + 416 => 'Requested Range Not Satisfiable', + 417 => 'Expectation Failed', + 422 => 'Unprocessable Entity', + 423 => 'Locked', + 424 => 'Failed Dependency', + 425 => 'Reserved for WebDAV advanced collections expired proposal', + 426 => 'Upgrade required', + 428 => 'Precondition Required', + 429 => 'Too Many Requests', + 431 => 'Request Header Fields Too Large', + 500 => 'Internal Server Error', + 501 => 'Not Implemented', + 502 => 'Bad Gateway', + 503 => 'Service Unavailable', + 504 => 'Gateway Timeout', + 505 => 'HTTP Version Not Supported', + 506 => 'Variant Also Negotiates (Experimental)', + 507 => 'Insufficient Storage', + 508 => 'Loop Detected', + 510 => 'Not Extended', + 511 => 'Network Authentication Required', + ); + + /** @var string The reason phrase of the response (human readable code) */ + private $reasonPhrase; + + /** @var string The status code of the response */ + private $statusCode; + + /** @var string The effective URL that returned this response */ + private $effectiveUrl; + + /** + * @param string $statusCode The response status code (e.g. 200) + * @param array $headers The response headers + * @param StreamInterface $body The body of the response + * @param array $options Response message options + * - reason_phrase: Set a custom reason phrase + * - protocol_version: Set a custom protocol version + */ + public function __construct( + $statusCode, + array $headers = [], + StreamInterface $body = null, + array $options = [] + ) { + $this->statusCode = (string) $statusCode; + $this->handleOptions($options); + + // Assume a reason phrase if one was not applied as an option + if (!$this->reasonPhrase && + isset(self::$statusTexts[$this->statusCode]) + ) { + $this->reasonPhrase = self::$statusTexts[$this->statusCode]; + } + + if ($headers) { + $this->setHeaders($headers); + } + + if ($body) { + $this->setBody($body); + } + } + + public function getStatusCode() + { + return $this->statusCode; + } + + public function getReasonPhrase() + { + return $this->reasonPhrase; + } + + public function json(array $config = []) + { + $data = json_decode( + (string) $this->getBody(), + isset($config['object']) ? !$config['object'] : true, + 512, + isset($config['big_int_strings']) ? JSON_BIGINT_AS_STRING : 0 + ); + + if (JSON_ERROR_NONE !== json_last_error()) { + throw new ParseException( + 'Unable to parse response body into JSON: ' . json_last_error(), + $this + ); + } + + return $data; + } + + public function xml(array $config = []) + { + $disableEntities = libxml_disable_entity_loader(true); + $internalErrors = libxml_use_internal_errors(true); + + try { + // Allow XML to be retrieved even if there is no response body + $xml = new \SimpleXMLElement( + (string) $this->getBody() ?: '', + LIBXML_NONET, + isset($config['ns']) ? $config['ns'] : '', + isset($config['ns_is_prefix']) ? $config['ns_is_prefix'] : false + ); + libxml_disable_entity_loader($disableEntities); + libxml_use_internal_errors($internalErrors); + } catch (\Exception $e) { + libxml_disable_entity_loader($disableEntities); + libxml_use_internal_errors($internalErrors); + throw new ParseException( + 'Unable to parse response body into XML: ' . $e->getMessage(), + $this + ); + } + + return $xml; + } + + public function getEffectiveUrl() + { + return $this->effectiveUrl; + } + + public function setEffectiveUrl($url) + { + $this->effectiveUrl = $url; + + return $this; + } + + /** + * Accepts and modifies the options provided to the response in the + * constructor. + * + * @param array $options Options array passed by reference. + */ + protected function handleOptions(array &$options = []) + { + parent::handleOptions($options); + if (isset($options['reason_phrase'])) { + $this->reasonPhrase = $options['reason_phrase']; + } + } + + protected function getStartLine() + { + return 'HTTP/' . $this->getProtocolVersion() + . " {$this->statusCode} {$this->reasonPhrase}"; + } +} diff --git a/core/vendor/guzzlehttp/guzzle/src/Message/ResponseInterface.php b/core/vendor/guzzlehttp/guzzle/src/Message/ResponseInterface.php new file mode 100644 index 00000000000..8db7215cd5b --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/src/Message/ResponseInterface.php @@ -0,0 +1,86 @@ +mimetypes[$extension]) ? $this->mimetypes[$extension] : null; + $extension = strtolower($extension); + + return isset($this->mimetypes[$extension]) + ? $this->mimetypes[$extension] + : null; } /** diff --git a/core/vendor/guzzlehttp/guzzle/src/Post/MultipartBody.php b/core/vendor/guzzlehttp/guzzle/src/Post/MultipartBody.php new file mode 100644 index 00000000000..08c137d2873 --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/src/Post/MultipartBody.php @@ -0,0 +1,293 @@ +boundary = $boundary ?: uniqid(); + $this->fields = $fields; + $this->files = $files; + $this->meta['mode'] = 'r'; + + // Ensure each file is a PostFileInterface + foreach ($this->files as $file) { + if (!$file instanceof PostFileInterface) { + throw new \InvalidArgumentException('All POST fields must ' + . 'implement PostFieldInterface'); + } + } + } + + public function __toString() + { + $this->seek(0); + + return $this->getContents(); + } + + public function getContents($maxLength = -1) + { + $buffer = ''; + + while (!$this->eof()) { + if ($maxLength === -1) { + $read = 1048576; + } else { + $len = strlen($buffer); + if ($len == $maxLength) { + break; + } + $read = min(1048576, $maxLength - $len); + } + $buffer .= $this->read($read); + } + + return $buffer; + } + + /** + * Get the boundary + * + * @return string + */ + public function getBoundary() + { + return $this->boundary; + } + + public function close() + { + $this->detach(); + } + + public function detach() + { + $this->fields = $this->files = []; + } + + /** + * The stream has reached an EOF when all of the fields and files have been + * read. + * {@inheritdoc} + */ + public function eof() + { + return $this->currentField == count($this->fields) && + $this->currentFile == count($this->files); + } + + public function tell() + { + return $this->pos; + } + + public function isReadable() + { + return true; + } + + public function isWritable() + { + return false; + } + + /** + * The steam is seekable by default, but all attached files must be + * seekable too. + * {@inheritdoc} + */ + public function isSeekable() + { + foreach ($this->files as $file) { + if (!$file->getContent()->isSeekable()) { + return false; + } + } + + return true; + } + + public function getSize() + { + if ($this->size === null) { + foreach ($this->files as $file) { + // We must be able to ascertain the size of each attached file + if (null === ($size = $file->getContent()->getSize())) { + return null; + } + $this->size += strlen($this->getFileHeaders($file)) + $size; + } + foreach (array_keys($this->fields) as $key) { + $this->size += strlen($this->getFieldString($key)); + } + $this->size += strlen("\r\n--{$this->boundary}--"); + } + + return $this->size; + } + + public function read($length) + { + $content = ''; + if ($this->buffer && !$this->buffer->eof()) { + $content .= $this->buffer->read($length); + } + if ($delta = $length - strlen($content)) { + $content .= $this->readData($delta); + } + + if ($content === '' && !$this->sentLast) { + $this->sentLast = true; + $content = "\r\n--{$this->boundary}--"; + } + + return $content; + } + + public function seek($offset, $whence = SEEK_SET) + { + if ($offset != 0 || $whence != SEEK_SET || !$this->isSeekable()) { + return false; + } + + foreach ($this->files as $file) { + if (!$file->getContent()->seek(0)) { + throw new \RuntimeException('Rewind on multipart file failed ' + . 'even though it shouldn\'t have'); + } + } + + $this->buffer = $this->sentLast = null; + $this->pos = $this->currentField = $this->currentFile = 0; + $this->bufferedHeaders = []; + + return true; + } + + public function write($string) + { + return false; + } + + /** + * No data is in the read buffer, so more needs to be pulled in from fields + * and files. + * + * @param int $length Amount of data to read + * + * @return string + */ + private function readData($length) + { + $result = ''; + + if ($this->currentField < count($this->fields)) { + $result = $this->readField($length); + } + + if ($result === '' && $this->currentFile < count($this->files)) { + $result = $this->readFile($length); + } + + return $result; + } + + /** + * Create a new stream buffer and inject form-data + * + * @param int $length Amount of data to read from the stream buffer + * + * @return string + */ + private function readField($length) + { + $name = array_keys($this->fields)[++$this->currentField - 1]; + $this->buffer = Stream\create($this->getFieldString($name)); + + return $this->buffer->read($length); + } + + /** + * Read data from a POST file, fill the read buffer with any overflow + * + * @param int $length Amount of data to read from the file + * + * @return string + */ + private function readFile($length) + { + $current = $this->files[$this->currentFile]; + + // Got to the next file and recursively return the read value, or bail + // if no more data can be read. + if ($current->getContent()->eof()) { + return ++$this->currentFile == count($this->files) + ? '' + : $this->readFile($length); + } + + // If this is the start of a file, then send the headers to the read + // buffer. + if (!isset($this->bufferedHeaders[$this->currentFile])) { + $this->buffer = Stream\create($this->getFileHeaders($current)); + $this->bufferedHeaders[$this->currentFile] = true; + } + + // More data needs to be read to meet the limit, so pull from the file + $content = $this->buffer ? $this->buffer->read($length) : ''; + if (($remaining = $length - strlen($content)) > 0) { + $content .= $current->getContent()->read($remaining); + } + + return $content; + } + + private function getFieldString($key) + { + return sprintf( + "--%s\r\nContent-Disposition: form-data; name=\"%s\"\r\n\r\n%s\r\n", + $this->boundary, + $key, + $this->fields[$key] + ); + } + + private function getFileHeaders(PostFileInterface $file) + { + $headers = ''; + foreach ($file->getHeaders() as $key => $value) { + $headers .= "{$key}: {$value}\r\n"; + } + + return "--{$this->boundary}\r\n" . trim($headers) . "\r\n\r\n"; + } +} diff --git a/core/vendor/guzzlehttp/guzzle/src/Post/PostBody.php b/core/vendor/guzzlehttp/guzzle/src/Post/PostBody.php new file mode 100644 index 00000000000..d6a2f3046f3 --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/src/Post/PostBody.php @@ -0,0 +1,287 @@ +files || $this->forceMultipart) { + $request->setHeader( + 'Content-Type', + 'multipart/form-data; boundary=' . $this->getBody()->getBoundary() + ); + } elseif ($this->fields) { + $request->setHeader('Content-Type', 'application/x-www-form-urlencoded'); + } + + if ($size = $this->getSize()) { + $request->setHeader('Content-Length', $size); + } + } + + public function forceMultipartUpload($force) + { + $this->forceMultipart = $force; + + return $this; + } + + public function setAggregator(callable $aggregator) + { + $this->aggregator = $aggregator; + } + + public function setField($name, $value) + { + $this->fields[$name] = $value; + $this->mutate(); + + return $this; + } + + public function replaceFields(array $fields) + { + $this->fields = $fields; + $this->mutate(); + + return $this; + } + + public function getField($name) + { + return isset($this->fields[$name]) ? $this->fields[$name] : null; + } + + public function removeField($name) + { + unset($this->fields[$name]); + $this->mutate(); + + return $this; + } + + public function getFields($asString = false) + { + if (!$asString) { + return $this->fields; + } + + return (string) (new Query($this->fields)) + ->setEncodingType(Query::RFC1738) + ->setAggregator($this->getAggregator()); + } + + public function hasField($name) + { + return isset($this->fields[$name]); + } + + public function getFile($name) + { + foreach ($this->files as $file) { + if ($file->getName() == $name) { + return $file; + } + } + + return null; + } + + public function getFiles() + { + return $this->files; + } + + public function addFile(PostFileInterface $file) + { + $this->files[] = $file; + $this->mutate(); + + return $this; + } + + public function clearFiles() + { + $this->files = []; + $this->mutate(); + + return $this; + } + + /** + * Returns the numbers of fields + files + * + * @return int + */ + public function count() + { + return count($this->files) + count($this->fields); + } + + public function __toString() + { + return (string) $this->getBody(); + } + + public function getContents($maxLength = -1) + { + return $this->getBody()->getContents(); + } + + public function close() + { + return $this->body ? $this->body->close() : true; + } + + public function detach() + { + $this->body = null; + $this->fields = $this->files = []; + + return $this; + } + + public function eof() + { + return $this->getBody()->eof(); + } + + public function tell() + { + return $this->body ? $this->body->tell() : 0; + } + + public function isSeekable() + { + return true; + } + + public function isReadable() + { + return true; + } + + public function isWritable() + { + return false; + } + + public function getSize() + { + return $this->getBody()->getSize(); + } + + public function seek($offset, $whence = SEEK_SET) + { + return $this->getBody()->seek($offset, $whence); + } + + public function read($length) + { + return $this->getBody()->read($length); + } + + public function write($string) + { + return false; + } + + /** + * Return a stream object that is built from the POST fields and files. + * + * If one has already been created, the previously created stream will be + * returned. + */ + private function getBody() + { + if ($this->body) { + return $this->body; + } elseif ($this->files || $this->forceMultipart) { + return $this->body = $this->createMultipart(); + } elseif ($this->fields) { + return $this->body = $this->createUrlEncoded(); + } else { + return $this->body = Stream\create(); + } + } + + /** + * Get the aggregator used to join multi-valued field parameters + * + * @return callable + */ + final protected function getAggregator() + { + if (!$this->aggregator) { + $this->aggregator = Query::phpAggregator(); + } + + return $this->aggregator; + } + + /** + * Creates a multipart/form-data body stream + * + * @return MultipartBody + */ + private function createMultipart() + { + $fields = $this->fields; + $query = (new Query()) + ->setEncodingType(false) + ->setAggregator($this->getAggregator()); + + // Account for fields with an array value + foreach ($fields as $name => &$field) { + if (is_array($field)) { + $field = (string) $query->replace([$name => $field]); + } + } + + return new MultipartBody($fields, $this->files); + } + + /** + * Creates an application/x-www-form-urlencoded stream body + * + * @return Stream\StreamInterface + */ + private function createUrlEncoded() + { + return Stream\create($this->getFields(true)); + } + + /** + * Get rid of any cached data + */ + private function mutate() + { + $this->body = null; + } +} diff --git a/core/vendor/guzzlehttp/guzzle/src/Post/PostBodyInterface.php b/core/vendor/guzzlehttp/guzzle/src/Post/PostBodyInterface.php new file mode 100644 index 00000000000..4405ce21a42 --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/src/Post/PostBodyInterface.php @@ -0,0 +1,129 @@ +headers = $headers; + $this->name = $name; + $this->prepareContent($content); + $this->prepareFilename($filename); + $this->prepareDefaultHeaders(); + } + + public function getName() + { + return $this->name; + } + + public function getFilename() + { + return $this->filename; + } + + public function getContent() + { + return $this->content; + } + + public function getHeaders() + { + return $this->headers; + } + + /** + * Prepares the contents of a POST file. + * + * @param mixed $content Content of the POST file + */ + private function prepareContent($content) + { + $this->content = $content; + + if (!($this->content instanceof StreamInterface)) { + $this->content = \GuzzleHttp\Stream\create($this->content); + } elseif ($this->content instanceof MultipartBody) { + if (!$this->hasHeader('Content-Disposition')) { + $disposition = 'form-data; name="' . $this->name .'"'; + $this->headers['Content-Disposition'] = $disposition; + } + + if (!$this->hasHeader('Content-Type')) { + $this->headers['Content-Type'] = sprintf( + "multipart/form-data; boundary=%s", + $this->content->getBoundary() + ); + } + } + } + + /** + * Applies a file name to the POST file based on various checks. + * + * @param string|null $filename Filename to apply (or null to guess) + */ + private function prepareFilename($filename) + { + $this->filename = $filename; + + if (!$this->filename && + $this->content instanceof MetadataStreamInterface + ) { + $this->filename = $this->content->getMetadata('uri'); + } + + if (!$this->filename || substr($this->filename, 0, 6) === 'php://') { + $this->filename = $this->name; + } + } + + /** + * Applies default Content-Disposition and Content-Type headers if needed. + */ + private function prepareDefaultHeaders() + { + // Set a default content-disposition header if one was no provided + if (!$this->hasHeader('Content-Disposition')) { + $this->headers['Content-Disposition'] = sprintf( + 'form-data; filename="%s"; name="%s"', + basename($this->filename), + $this->name + ); + } + + // Set a default Content-Type if one was not supplied + if (!$this->hasHeader('Content-Type')) { + $this->headers['Content-Type'] = Mimetypes::getInstance() + ->fromFilename($this->filename) ?: 'text/plain'; + } + } + + /** + * Check if a specific header exists on the POST file by name. + * + * @param string $name Case-insensitive header to check + * + * @return bool + */ + private function hasHeader($name) + { + return isset(array_change_key_case($this->headers)[strtolower($name)]); + } +} diff --git a/core/vendor/guzzlehttp/guzzle/src/Post/PostFileInterface.php b/core/vendor/guzzlehttp/guzzle/src/Post/PostFileInterface.php new file mode 100644 index 00000000000..205dd9676c9 --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/src/Post/PostFileInterface.php @@ -0,0 +1,42 @@ +add($key, $value); + $foundDuplicates = true; + } elseif ($paramIsPhpStyleArray) { + $q[$key] = array($value); + } else { + $q[$key] = $value; + } + } else { + $q->add($key, null); + } + } + + // Use the duplicate aggregator if duplicates were found and not using + // PHP style arrays. + if ($foundDuplicates && !$foundPhpStyle) { + $q->setAggregator(self::duplicateAggregator()); + } + + return $q; + } + + /** + * Convert the query string parameters to a query string string + * + * @return string + */ + public function __toString() + { + if (!$this->data) { + return ''; + } + + // The default aggregator is statically cached + static $defaultAggregator; + + if (!$this->aggregator) { + if (!$defaultAggregator) { + $defaultAggregator = self::phpAggregator(); + } + $this->aggregator = $defaultAggregator; + } + + $result = ''; + $aggregator = $this->aggregator; + + foreach ($aggregator($this->data) as $key => $values) { + foreach ($values as $value) { + if ($result) { + $result .= '&'; + } + if ($this->encoding == self::RFC1738) { + $result .= urlencode($key); + if ($value !== null) { + $result .= '=' . urlencode($value); + } + } elseif ($this->encoding == self::RFC3986) { + $result .= rawurlencode($key); + if ($value !== null) { + $result .= '=' . rawurlencode($value); + } + } else { + $result .= $key; + if ($value !== null) { + $result .= '=' . $value; + } + } + } + } + + return $result; + } + + /** + * Controls how multi-valued query string parameters are aggregated into a + * string. + * + * $query->setAggregator($query::duplicateAggregator()); + * + * @param callable $aggregator Callable used to convert a deeply nested + * array of query string variables into a flattened array of key value + * pairs. The callable accepts an array of query data and returns a + * flattened array of key value pairs where each value is an array of + * strings. + * + * @return self + */ + public function setAggregator(callable $aggregator) + { + $this->aggregator = $aggregator; + + return $this; + } + + /** + * Specify how values are URL encoded + * + * @param string|bool $type One of 'RFC1738', 'RFC3986', or false to disable encoding + * + * @return self + * @throws \InvalidArgumentException + */ + public function setEncodingType($type) + { + if ($type === false || $type === self::RFC1738 || $type === self::RFC3986) { + $this->encoding = $type; + } else { + throw new \InvalidArgumentException('Invalid URL encoding type'); + } + + return $this; + } + + /** + * Query string aggregator that does not aggregate nested query string + * values and allows duplicates in the resulting array. + * + * Example: http://test.com?q=1&q=2 + * + * @return callable + */ + public static function duplicateAggregator() + { + return function (array $data) { + return self::walkQuery($data, '', function ($key, $prefix) { + return is_int($key) ? $prefix : "{$prefix}[{$key}]"; + }); + }; + } + + /** + * Aggregates nested query string variables using the same technique as + * ``http_build_query()``. + * + * @param bool $numericIndices Pass false to not include numeric indices + * when multi-values query string parameters are present. + * + * @return callable + */ + public static function phpAggregator($numericIndices = true) + { + return function (array $data) use ($numericIndices) { + return self::walkQuery( + $data, + '', + function ($key, $prefix) use ($numericIndices) { + return !$numericIndices && is_int($key) + ? "{$prefix}[]" + : "{$prefix}[{$key}]"; + } + ); + }; + } + + /** + * Easily create query aggregation functions by providing a key prefix + * function to this query string array walker. + * + * @param array $query Query string to walk + * @param string $keyPrefix Key prefix (start with '') + * @param callable $prefixer Function used to create a key prefix + * + * @return array + */ + public static function walkQuery(array $query, $keyPrefix, callable $prefixer) + { + $result = []; + foreach ($query as $key => $value) { + if ($keyPrefix) { + $key = $prefixer($key, $keyPrefix); + } + if (is_array($value)) { + $result += self::walkQuery($value, $key, $prefixer); + } elseif (isset($result[$key])) { + $result[$key][] = $value; + } else { + $result[$key] = array($value); + } + } + + return $result; + } +} diff --git a/core/vendor/guzzlehttp/guzzle/src/Subscriber/Cookie.php b/core/vendor/guzzlehttp/guzzle/src/Subscriber/Cookie.php new file mode 100644 index 00000000000..4b8a2c081be --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/src/Subscriber/Cookie.php @@ -0,0 +1,59 @@ +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() + ); + } +} diff --git a/core/vendor/guzzlehttp/guzzle/src/Subscriber/History.php b/core/vendor/guzzlehttp/guzzle/src/Subscriber/History.php new file mode 100644 index 00000000000..b2a49e04453 --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/src/Subscriber/History.php @@ -0,0 +1,138 @@ +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) + { + $this->add($event->getRequest(), $event->getResponse()); + } + + /** + * 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); + } + } +} diff --git a/core/vendor/guzzlehttp/guzzle/src/Subscriber/HttpError.php b/core/vendor/guzzlehttp/guzzle/src/Subscriber/HttpError.php new file mode 100644 index 00000000000..f2f72f15e9d --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/src/Subscriber/HttpError.php @@ -0,0 +1,34 @@ + ['onComplete', RequestEvents::VERIFY_RESPONSE]]; + } + + /** + * Throw a RequestException on an HTTP protocol error + * + * @param CompleteEvent $event Emitted event + * @throws RequestException + */ + public function onComplete(CompleteEvent $event) + { + $code = (string) $event->getResponse()->getStatusCode(); + // Throw an exception for an unsuccessful response + if ($code[0] === '4' || $code[0] === '5') { + throw RequestException::create($event->getRequest(), $event->getResponse()); + } + } +} diff --git a/core/vendor/guzzlehttp/guzzle/src/Subscriber/Mock.php b/core/vendor/guzzlehttp/guzzle/src/Subscriber/Mock.php new file mode 100644 index 00000000000..99a3d18d72c --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/src/Subscriber/Mock.php @@ -0,0 +1,143 @@ +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 = []; + } +} diff --git a/core/vendor/guzzlehttp/guzzle/src/Subscriber/Prepare.php b/core/vendor/guzzlehttp/guzzle/src/Subscriber/Prepare.php new file mode 100644 index 00000000000..2d82acd6d8a --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/src/Subscriber/Prepare.php @@ -0,0 +1,136 @@ + ['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'); + } + } +} diff --git a/core/vendor/guzzlehttp/guzzle/src/Subscriber/Redirect.php b/core/vendor/guzzlehttp/guzzle/src/Subscriber/Redirect.php new file mode 100644 index 00000000000..a8962091ea7 --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/src/Subscriber/Redirect.php @@ -0,0 +1,171 @@ + ['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; + $request = $event->getRequest(); + $redirectResponse = $response; + $max = $request->getConfig()->getPath('redirect/max') ?: 5; + + do { + if (++$redirectCount > $max) { + throw new TooManyRedirectsException( + "Will not follow more than {$redirectCount} redirects", + $request + ); + } + $redirectRequest = $this->createRedirectRequest($request, $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); + + if ($request->getBody() && + !$config->getPath('redirect/strict') && + $response->getStatusCode() <= 302 + ) { + $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); + } +} diff --git a/core/vendor/guzzle/common/Guzzle/Common/ToArrayInterface.php b/core/vendor/guzzlehttp/guzzle/src/ToArrayInterface.php similarity index 89% rename from core/vendor/guzzle/common/Guzzle/Common/ToArrayInterface.php rename to core/vendor/guzzlehttp/guzzle/src/ToArrayInterface.php index 245328c1b3a..7c4120fbca6 100644 --- a/core/vendor/guzzle/common/Guzzle/Common/ToArrayInterface.php +++ b/core/vendor/guzzlehttp/guzzle/src/ToArrayInterface.php @@ -1,6 +1,6 @@ true, '#' => true, '.' => true, '/' => true, ';' => true, '?' => true, '&' => true + '' => array('prefix' => '', 'joiner' => ',', 'query' => false), + '+' => array('prefix' => '', 'joiner' => ',', 'query' => false), + '#' => array('prefix' => '#', 'joiner' => ',', 'query' => false), + '.' => array('prefix' => '.', 'joiner' => '.', 'query' => false), + '/' => array('prefix' => '/', 'joiner' => '/', 'query' => false), + ';' => array('prefix' => ';', 'joiner' => ';', 'query' => true), + '?' => array('prefix' => '?', 'joiner' => '&', 'query' => true), + '&' => array('prefix' => '&', 'joiner' => '&', 'query' => true) ); /** @var array Delimiters */ - private static $delims = array( - ':', '/', '?', '#', '[', ']', '@', '!', '$', '&', '\'', '(', ')', '*', '+', ',', ';', '=' - ); + private static $delims = array(':', '/', '?', '#', '[', ']', '@', '!', '$', + '&', '\'', '(', ')', '*', '+', ',', ';', '='); /** @var array Percent encoded delimiters */ - private static $delimsPct = array( - '%3A', '%2F', '%3F', '%23', '%5B', '%5D', '%40', '%21', '%24', '%26', '%27', '%28', '%29', '%2A', '%2B', '%2C', - '%3B', '%3D' - ); + private static $delimsPct = array('%3A', '%2F', '%3F', '%23', '%5B', '%5D', + '%40', '%21', '%24', '%26', '%27', '%28', '%29', '%2A', '%2B', '%2C', + '%3B', '%3D'); public function expand($template, array $variables) { + if (false === strpos($template, '{')) { + return $template; + } + $this->template = $template; $this->variables = $variables; - // Check to ensure that the preg_* function is needed - if (false === strpos($this->template, '{')) { - return $this->template; - } - - return preg_replace_callback(self::$regex, array($this, 'expandMatch'), $this->template); + return preg_replace_callback( + '/\{([^\}]+)\}/', + [$this, 'expandMatch'], + $this->template + ); } /** @@ -56,23 +61,22 @@ class UriTemplate implements UriTemplateInterface */ private function parseExpression($expression) { - // Check for URI operators - $operator = ''; + $result = array(); if (isset(self::$operatorHash[$expression[0]])) { - $operator = $expression[0]; + $result['operator'] = $expression[0]; $expression = substr($expression, 1); + } else { + $result['operator'] = ''; } - $values = explode(',', $expression); - foreach ($values as &$value) { + foreach (explode(',', $expression) as $value) { $value = trim($value); $varspec = array(); - $substrPos = strpos($value, ':'); - if ($substrPos) { - $varspec['value'] = substr($value, 0, $substrPos); + if ($colonPos = strpos($value, ':')) { + $varspec['value'] = substr($value, 0, $colonPos); $varspec['modifier'] = ':'; - $varspec['position'] = (int) substr($value, $substrPos + 1); + $varspec['position'] = (int) substr($value, $colonPos + 1); } elseif (substr($value, -1) == '*') { $varspec['modifier'] = '*'; $varspec['value'] = substr($value, 0, -1); @@ -80,13 +84,10 @@ class UriTemplate implements UriTemplateInterface $varspec['value'] = (string) $value; $varspec['modifier'] = ''; } - $value = $varspec; + $result['values'][] = $varspec; } - return array( - 'operator' => $operator, - 'values' => $values - ); + return $result; } /** @@ -98,39 +99,22 @@ class UriTemplate implements UriTemplateInterface */ private function expandMatch(array $matches) { - static $rfc1738to3986 = array( - '+' => '%20', - '%7e' => '~' - ); + static $rfc1738to3986 = array('+' => '%20', '%7e' => '~'); - $parsed = self::parseExpression($matches[1]); $replacements = array(); - - $prefix = $parsed['operator']; - $joiner = $parsed['operator']; - $useQueryString = false; - if ($parsed['operator'] == '?') { - $joiner = '&'; - $useQueryString = true; - } elseif ($parsed['operator'] == '&') { - $useQueryString = true; - } elseif ($parsed['operator'] == '#') { - $joiner = ','; - } elseif ($parsed['operator'] == ';') { - $useQueryString = true; - } elseif ($parsed['operator'] == '' || $parsed['operator'] == '+') { - $joiner = ','; - $prefix = ''; - } + $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 (!array_key_exists($value['value'], $this->variables) || $this->variables[$value['value']] === null) { + if (!isset($this->variables[$value['value']])) { continue; } $variable = $this->variables[$value['value']]; - $actuallyUseQueryString = $useQueryString; + $actuallyUseQuery = $useQuery; $expanded = ''; if (is_array($variable)) { @@ -148,7 +132,9 @@ class UriTemplate implements UriTemplateInterface if (!$isNestedArray) { $var = rawurlencode($var); - if ($parsed['operator'] == '+' || $parsed['operator'] == '#') { + if ($parsed['operator'] == '+' || + $parsed['operator'] == '#' + ) { $var = $this->decodeReserved($var); } } @@ -156,12 +142,16 @@ class UriTemplate implements UriTemplateInterface if ($value['modifier'] == '*') { if ($isAssoc) { if ($isNestedArray) { - // Nested arrays must allow for deeply nested structures - $var = strtr(http_build_query(array($key => $var)), $rfc1738to3986); + // Nested arrays must allow for deeply nested + // structures. + $var = strtr( + http_build_query([$key => $var]), + $rfc1738to3986 + ); } else { $var = $key . '=' . $var; } - } elseif ($key > 0 && $actuallyUseQueryString) { + } elseif ($key > 0 && $actuallyUseQuery) { $var = $value['value'] . '=' . $var; } } @@ -170,17 +160,20 @@ class UriTemplate implements UriTemplateInterface } if (empty($variable)) { - $actuallyUseQueryString = false; + $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 - $actuallyUseQueryString = false; + // 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. + // 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; } @@ -198,7 +191,7 @@ class UriTemplate implements UriTemplateInterface } } - if ($actuallyUseQueryString) { + if ($actuallyUseQuery) { if (!$expanded && $joiner != '&') { $expanded = $value['value']; } else { @@ -218,7 +211,12 @@ class UriTemplate implements UriTemplateInterface } /** - * Determines if an array is associative + * 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 * @@ -226,11 +224,12 @@ class UriTemplate implements UriTemplateInterface */ private function isAssoc(array $array) { - return (bool) count(array_filter(array_keys($array), 'is_string')); + return $array && array_keys($array)[0] !== 0; } /** - * Removes percent encoding on reserved characters (used with + and # modifiers) + * Removes percent encoding on reserved characters (used with + and # + * modifiers). * * @param string $string String to fix * diff --git a/core/vendor/guzzle/http/Guzzle/Http/Url.php b/core/vendor/guzzlehttp/guzzle/src/Url.php similarity index 53% rename from core/vendor/guzzle/http/Guzzle/Http/Url.php rename to core/vendor/guzzlehttp/guzzle/src/Url.php index b9b87c634fe..6bf68e8e79c 100644 --- a/core/vendor/guzzle/http/Guzzle/Http/Url.php +++ b/core/vendor/guzzlehttp/guzzle/src/Url.php @@ -1,25 +1,23 @@ 80, 'https' => 443, 'ftp' => 21]; - /** @var QueryString Query part of the URL */ - protected $query; + /** @var Query Query part of the URL */ + private $query; /** * Factory method to create a new URL from a URL string @@ -27,31 +25,34 @@ class Url * @param string $url Full URL used to create a Url object * * @return Url - * @throws InvalidArgumentException + * @throws \InvalidArgumentException */ - public static function factory($url) + public static function fromString($url) { - static $defaults = array('scheme' => null, 'host' => null, 'path' => null, 'port' => null, 'query' => null, + static $defaults = array('scheme' => null, 'host' => null, + 'path' => null, 'port' => null, 'query' => null, 'user' => null, 'pass' => null, 'fragment' => null); if (false === ($parts = parse_url($url))) { - throw new InvalidArgumentException('Was unable to parse malformed url: ' . $url); + throw new \InvalidArgumentException('Unable to parse malformed ' + . 'url: ' . $url); } $parts += $defaults; - // Convert the query string into a QueryString object + // Convert the query string into a Query object if ($parts['query'] || 0 !== strlen($parts['query'])) { - $parts['query'] = QueryString::fromString($parts['query']); + $parts['query'] = Query::fromString($parts['query']); } - return new self($parts['scheme'], $parts['host'], $parts['user'], + return new static($parts['scheme'], $parts['host'], $parts['user'], $parts['pass'], $parts['port'], $parts['path'], $parts['query'], $parts['fragment']); } /** - * Build a URL from parse_url parts. The generated URL will be a relative URL if a scheme or host are not provided. + * Build a URL from parse_url parts. The generated URL will be a relative + * URL if a scheme or host are not provided. * * @param array $parts Array of parse_url parts * @@ -61,12 +62,12 @@ class Url { $url = $scheme = ''; - if (isset($parts['scheme'])) { + if (!empty($parts['scheme'])) { $scheme = $parts['scheme']; $url .= $scheme . ':'; } - if (isset($parts['host'])) { + if (!empty($parts['host'])) { $url .= '//'; if (isset($parts['user'])) { $url .= $parts['user']; @@ -79,17 +80,19 @@ class Url $url .= $parts['host']; // Only include the port if it is not the default port of the scheme - if (isset($parts['port']) - && !(($scheme == 'http' && $parts['port'] == 80) || ($scheme == 'https' && $parts['port'] == 443)) + if (isset($parts['port']) && + (!isset(self::$defaultPorts[$scheme]) || + $parts['port'] != self::$defaultPorts[$scheme]) ) { $url .= ':' . $parts['port']; } } // Add the path component if present - if (isset($parts['path']) && 0 !== strlen($parts['path'])) { - // Always ensure that the path begins with '/' if set and something is before the path - if ($url && $parts['path'][0] != '/' && substr($url, -1) != '/') { + if (isset($parts['path']) && strlen($parts['path'])) { + // Always ensure that the path begins with '/' if set and something + // is before the path + if (isset($parts['host']) && $parts['path'][0] != '/') { $url .= '/'; } $url .= $parts['path']; @@ -97,7 +100,10 @@ class Url // Add the query string if present if (isset($parts['query'])) { - $url .= '?' . $parts['query']; + $queryStr = (string) $parts['query']; + if ($queryStr || $queryStr === '0') { + $url .= '?' . $queryStr; + } } // Ensure that # is only added to the url if fragment contains anything. @@ -117,11 +123,19 @@ class Url * @param string $password Password of the URL * @param int $port Port of the URL * @param string $path Path of the URL - * @param QueryString|array|string $query Query string of the URL + * @param Query|array|string $query Query string of the URL * @param string $fragment Fragment of the URL */ - public function __construct($scheme, $host, $username = null, $password = null, $port = null, $path = null, QueryString $query = null, $fragment = null) - { + public function __construct( + $scheme, + $host, + $username = null, + $password = null, + $port = null, + $path = null, + Query $query = null, + $fragment = null + ) { $this->scheme = $scheme; $this->host = $host; $this->port = $port; @@ -129,7 +143,7 @@ class Url $this->password = $password; $this->fragment = $fragment; if (!$query) { - $this->query = new QueryString(); + $this->query = new Query(); } else { $this->setQuery($query); } @@ -151,7 +165,7 @@ class Url */ public function __toString() { - return self::buildUrl($this->getParts()); + return static::buildUrl($this->getParts()); } /** @@ -162,13 +176,13 @@ class Url public function getParts() { return array( - 'scheme' => $this->scheme, - 'user' => $this->username, - 'pass' => $this->password, - 'host' => $this->host, - 'port' => $this->port, - 'path' => $this->getPath(), - 'query' => (string) $this->query ?: null, + 'scheme' => $this->scheme, + 'user' => $this->username, + 'pass' => $this->password, + 'host' => $this->host, + 'port' => $this->port, + 'path' => $this->path, + 'query' => $this->query, 'fragment' => $this->fragment, ); } @@ -212,6 +226,13 @@ class Url */ public function setScheme($scheme) { + // Remove the default port if one is specified + if ($this->port && isset(self::$defaultPorts[$this->scheme]) && + self::$defaultPorts[$this->scheme] == $this->port + ) { + $this->port = null; + } + $this->scheme = $scheme; return $this; @@ -242,7 +263,10 @@ class Url } /** - * Get the port part of the URl. Will return the default port for a given scheme if no port has been set. + * Get the port part of the URl. + * + * If no port was set, this method will return the default port for the + * scheme of the URI. * * @return int|null */ @@ -250,10 +274,8 @@ class Url { if ($this->port) { return $this->port; - } elseif ($this->scheme == 'http') { - return 80; - } elseif ($this->scheme == 'https') { - return 443; + } elseif (isset(self::$defaultPorts[$this->scheme])) { + return self::$defaultPorts[$this->scheme]; } return null; @@ -262,68 +284,61 @@ class Url /** * Set the path part of the URL * - * @param array|string $path Path string or array of path segments + * @param string $path Path string to set * * @return Url */ public function setPath($path) { - if (is_array($path)) { - $this->path = '/' . implode('/', $path); - } else { - $this->path = (string) $path; - } + static $search = [' ', '?']; + static $replace = ['%20', '%3F']; + $this->path = str_replace($search, $replace, $path); return $this; } /** - * Normalize the URL so that double slashes and relative paths are removed + * Removes dot segments from a URL * * @return Url + * @link http://tools.ietf.org/html/rfc3986#section-5.2.4 */ - public function normalizePath() + public function removeDotSegments() { - if (!$this->path || $this->path == '/' || $this->path == '*') { + static $noopPaths = ['' => true, '/' => true, '*' => true]; + static $ignoreSegments = ['' => true, '.' => true, '..' => true]; + + if (isset($noopPaths[$this->path])) { return $this; } - // Replace // and /./ with / - $this->path = str_replace(array('/./', '//'), '/', $this->path); - - // Remove dot segments - if (strpos($this->path, '..') !== false) { - - // Remove trailing relative paths if possible - $segments = $this->getPathSegments(); - $last = end($segments); - $trailingSlash = false; - if ($last === '') { - array_pop($segments); - $trailingSlash = true; + $results = []; + $segments = $this->getPathSegments(); + foreach ($segments as $segment) { + if ($segment == '..') { + array_pop($results); + } elseif (!isset($ignoreSegments[$segment])) { + $results[] = $segment; } + } - while ($last == '..' || $last == '.') { - if ($last == '..') { - array_pop($segments); - $last = array_pop($segments); - } - if ($last == '.' || $last == '') { - $last = array_pop($segments); - } - } + // Combine the normalized parts and add the leading slash if needed + if ($this->path[0] == '/') { + $this->path = '/' . implode('/', $results); + } else { + $this->path = implode('/', $results); + } - $this->path = implode('/', $segments); - if ($trailingSlash) { - $this->path .= '/'; - } + // Add the trailing slash if necessary + if ($this->path != '/' && isset($ignoreSegments[end($segments)])) { + $this->path .= '/'; } return $this; } /** - * Add a relative path to the currently set path + * Add a relative path to the currently set path. * * @param string $relativePath Relative path to add * @@ -331,16 +346,18 @@ class Url */ public function addPath($relativePath) { - if (!$relativePath || $relativePath == '/') { - return $this; + if ($relativePath != '/' && + is_string($relativePath) && + strlen($relativePath) > 0 + ) { + // Add a leading slash if needed + if ($relativePath[0] != '/') { + $relativePath = '/' . $relativePath; + } + $this->setPath(str_replace('//', '/', $this->path . $relativePath)); } - // Add a leading slash if needed - if ($relativePath[0] != '/') { - $relativePath = '/' . $relativePath; - } - - return $this->setPath(str_replace('//', '/', $this->getPath() . $relativePath)); + return $this; } /** @@ -360,7 +377,7 @@ class Url */ public function getPathSegments() { - return array_slice(explode('/', $this->getPath()), 1); + return explode('/', $this->path); } /** @@ -412,9 +429,9 @@ class Url } /** - * Get the query part of the URL as a QueryString object + * Get the query part of the URL as a Query object * - * @return QueryString + * @return Query */ public function getQuery() { @@ -424,20 +441,24 @@ class Url /** * Set the query part of the URL * - * @param QueryString|string|array $query Query to set + * @param Query|string|array $query Query string value to set. Can + * be a string that will be parsed into a Query object, an array + * of key value pairs, or a Query object. * * @return Url + * @throws \InvalidArgumentException */ public function setQuery($query) { - if (is_string($query)) { - $output = null; - parse_str($query, $output); - $this->query = new QueryString($output); - } elseif (is_array($query)) { - $this->query = new QueryString($query); - } elseif ($query instanceof QueryString) { + if ($query instanceof Query) { $this->query = $query; + } elseif (is_string($query)) { + $this->query = Query::fromString($query); + } elseif (is_array($query)) { + $this->query = new Query($query); + } else { + throw new \InvalidArgumentException('Query must be a ' + . 'QueryInterface, array, or string'); } return $this; @@ -478,66 +499,87 @@ class Url } /** - * Combine the URL with another URL. Follows the rules specific in RFC 3986 section 5.4. + * Combine the URL with another URL and return a new URL instance. + * + * Follows the rules specific in RFC 3986 section 5.4. * * @param string $url Relative URL to combine with * * @return Url - * @throws InvalidArgumentException + * @throws \InvalidArgumentException * @link http://tools.ietf.org/html/rfc3986#section-5.4 */ public function combine($url) { - $url = self::factory($url); + $url = static::fromString($url); // Use the more absolute URL as the base URL if (!$this->isAbsolute() && $url->isAbsolute()) { $url = $url->combine($this); } + $parts = $url->getParts(); + // Passing a URL with a scheme overrides everything - if ($buffer = $url->getScheme()) { - $this->scheme = $buffer; - $this->host = $url->getHost(); - $this->port = $url->getPort(); - $this->username = $url->getUsername(); - $this->password = $url->getPassword(); - $this->path = $url->getPath(); - $this->query = $url->getQuery(); - $this->fragment = $url->getFragment(); - return $this; + if ($parts['scheme']) { + return new static( + $parts['scheme'], + $parts['host'], + $parts['user'], + $parts['pass'], + $parts['port'], + $parts['path'], + clone $parts['query'], + $parts['fragment'] + ); } // Setting a host overrides the entire rest of the URL - if ($buffer = $url->getHost()) { - $this->host = $buffer; - $this->port = $url->getPort(); - $this->username = $url->getUsername(); - $this->password = $url->getPassword(); - $this->path = $url->getPath(); - $this->fragment = $url->getFragment(); - return $this; + if ($parts['host']) { + return new static( + $this->scheme, + $parts['host'], + $parts['user'], + $parts['pass'], + $parts['port'], + $parts['path'], + clone $parts['query'], + $parts['fragment'] + ); } - $path = $url->getPath(); - $query = $url->getQuery(); - - if (!$path) { - if (count($query)) { - $this->query = $query; - } + if (!$parts['path']) { + // The relative URL has no path, so check if it is just a query + $path = $this->path ?: ''; + $query = count($parts['query']) ? $parts['query'] : $this->query; } else { - if ($path[0] == '/') { - $this->path = $path; + $query = $parts['query']; + if ($parts['path'][0] == '/' || !$this->path) { + // Overwrite the existing path if the rel path starts with "/" + $path = $parts['path']; } else { - $this->path .= '/' . $path; + // If the relative URL does not have a path or the base URL + // path does not end in a "/" then overwrite the existing path + // up to the last "/" + $path = substr($this->path, 0, strrpos($this->path, '/') + 1) . $parts['path']; } - $this->normalizePath(); - $this->query = $query; } - $this->fragment = $url->getFragment(); + $result = new self( + $this->scheme, + $this->host, + $this->username, + $this->password, + $this->port, + $path, + clone $query, + $parts['fragment'] + ); - return $this; + if ($path) { + $result->removeDotSegments(); + } + + return $result; } } diff --git a/core/vendor/guzzle/http/Guzzle/Http/Resources/cacert.pem b/core/vendor/guzzlehttp/guzzle/src/cacert.pem similarity index 88% rename from core/vendor/guzzle/http/Guzzle/Http/Resources/cacert.pem rename to core/vendor/guzzlehttp/guzzle/src/cacert.pem index 99b310bce91..67f696abc44 100644 --- a/core/vendor/guzzle/http/Guzzle/Http/Resources/cacert.pem +++ b/core/vendor/guzzlehttp/guzzle/src/cacert.pem @@ -1,12 +1,12 @@ ## ## ca-bundle.crt -- Bundle of CA Root Certificates ## -## Certificate data from Mozilla as of: Sat Dec 29 20:03:40 2012 +## Certificate data from Mozilla as of: Tue Jan 28 09:38:07 2014 ## ## This is a bundle of X.509 certificates of public Certificate Authorities ## (CA). These were automatically extracted from Mozilla's root certificates ## file (certdata.txt). This file can be found in the mozilla source tree: -## http://mxr.mozilla.org/mozilla/source/security/nss/lib/ckfw/builtins/certdata.txt?raw=1 +## http://mxr.mozilla.org/mozilla-release/source/security/nss/lib/ckfw/builtins/certdata.txt?raw=1 ## ## It contains the certificates in PEM format and therefore ## can be directly used with curl / libcurl / php_curl, or with @@ -14,7 +14,6 @@ ## Just configure this file as the SSLCACertificateFile. ## -# @(#) $RCSfile: certdata.txt,v $ $Revision: 1.87 $ $Date: 2012/12/29 16:32:45 $ GTE CyberTrust Global Root ========================== @@ -91,46 +90,6 @@ BIZCe/zuf6IWUrVnZ9NA2zsmWLIodz2uFHdh1voqZiegDfqnc1zqcPGUIWVEX/r87yloqaKHee95 70+sB3c4 -----END CERTIFICATE----- -Digital Signature Trust Co. Global CA 1 -======================================= ------BEGIN CERTIFICATE----- -MIIDKTCCApKgAwIBAgIENnAVljANBgkqhkiG9w0BAQUFADBGMQswCQYDVQQGEwJVUzEkMCIGA1UE -ChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMREwDwYDVQQLEwhEU1RDQSBFMTAeFw05ODEy -MTAxODEwMjNaFw0xODEyMTAxODQwMjNaMEYxCzAJBgNVBAYTAlVTMSQwIgYDVQQKExtEaWdpdGFs -IFNpZ25hdHVyZSBUcnVzdCBDby4xETAPBgNVBAsTCERTVENBIEUxMIGdMA0GCSqGSIb3DQEBAQUA -A4GLADCBhwKBgQCgbIGpzzQeJN3+hijM3oMv+V7UQtLodGBmE5gGHKlREmlvMVW5SXIACH7TpWJE -NySZj9mDSI+ZbZUTu0M7LklOiDfBu1h//uG9+LthzfNHwJmm8fOR6Hh8AMthyUQncWlVSn5JTe2i -o74CTADKAqjuAQIxZA9SLRN0dja1erQtcQIBA6OCASQwggEgMBEGCWCGSAGG+EIBAQQEAwIABzBo -BgNVHR8EYTBfMF2gW6BZpFcwVTELMAkGA1UEBhMCVVMxJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0 -dXJlIFRydXN0IENvLjERMA8GA1UECxMIRFNUQ0EgRTExDTALBgNVBAMTBENSTDEwKwYDVR0QBCQw -IoAPMTk5ODEyMTAxODEwMjNagQ8yMDE4MTIxMDE4MTAyM1owCwYDVR0PBAQDAgEGMB8GA1UdIwQY -MBaAFGp5fpFpRhgTCgJ3pVlbYJglDqL4MB0GA1UdDgQWBBRqeX6RaUYYEwoCd6VZW2CYJQ6i+DAM -BgNVHRMEBTADAQH/MBkGCSqGSIb2fQdBAAQMMAobBFY0LjADAgSQMA0GCSqGSIb3DQEBBQUAA4GB -ACIS2Hod3IEGtgllsofIH160L+nEHvI8wbsEkBFKg05+k7lNQseSJqBcNJo4cvj9axY+IO6CizEq -kzaFI4iKPANo08kJD038bKTaKHKTDomAsH3+gG9lbRgzl4vCa4nuYD3Im+9/KzJic5PLPON74nZ4 -RbyhkwS7hp86W0N6w4pl ------END CERTIFICATE----- - -Digital Signature Trust Co. Global CA 3 -======================================= ------BEGIN CERTIFICATE----- -MIIDKTCCApKgAwIBAgIENm7TzjANBgkqhkiG9w0BAQUFADBGMQswCQYDVQQGEwJVUzEkMCIGA1UE -ChMbRGlnaXRhbCBTaWduYXR1cmUgVHJ1c3QgQ28uMREwDwYDVQQLEwhEU1RDQSBFMjAeFw05ODEy -MDkxOTE3MjZaFw0xODEyMDkxOTQ3MjZaMEYxCzAJBgNVBAYTAlVTMSQwIgYDVQQKExtEaWdpdGFs -IFNpZ25hdHVyZSBUcnVzdCBDby4xETAPBgNVBAsTCERTVENBIEUyMIGdMA0GCSqGSIb3DQEBAQUA -A4GLADCBhwKBgQC/k48Xku8zExjrEH9OFr//Bo8qhbxe+SSmJIi2A7fBw18DW9Fvrn5C6mYjuGOD -VvsoLeE4i7TuqAHhzhy2iCoiRoX7n6dwqUcUP87eZfCocfdPJmyMvMa1795JJ/9IKn3oTQPMx7JS -xhcxEzu1TdvIxPbDDyQq2gyd55FbgM2UnQIBA6OCASQwggEgMBEGCWCGSAGG+EIBAQQEAwIABzBo -BgNVHR8EYTBfMF2gW6BZpFcwVTELMAkGA1UEBhMCVVMxJDAiBgNVBAoTG0RpZ2l0YWwgU2lnbmF0 -dXJlIFRydXN0IENvLjERMA8GA1UECxMIRFNUQ0EgRTIxDTALBgNVBAMTBENSTDEwKwYDVR0QBCQw -IoAPMTk5ODEyMDkxOTE3MjZagQ8yMDE4MTIwOTE5MTcyNlowCwYDVR0PBAQDAgEGMB8GA1UdIwQY -MBaAFB6CTShlgDzJQW6sNS5ay97u+DlbMB0GA1UdDgQWBBQegk0oZYA8yUFurDUuWsve7vg5WzAM -BgNVHRMEBTADAQH/MBkGCSqGSIb2fQdBAAQMMAobBFY0LjADAgSQMA0GCSqGSIb3DQEBBQUAA4GB -AEeNg61i8tuwnkUiBbmi1gMOOHLnnvx75pO2mqWilMg0HZHRxdf0CiUPPXiBng+xZ8SQTGPdXqfi -up/1902lMXucKS1M/mQ+7LZT/uqb7YLbdHVLB3luHtgZg3Pe9T7Qtd7nS2h9Qy4qIOF+oHhEngj1 -mPnHfxsb1gYgAlihw6ID ------END CERTIFICATE----- - Verisign Class 3 Public Primary Certification Authority ======================================================= -----BEGIN CERTIFICATE----- @@ -147,44 +106,6 @@ WM1pF+NEHJwZRDmJXNycAA9WjQKZ7aKQRUzkuxCkPfAyAw7xzvjoyVGM5mKf5p/AfbdynMk2Omuf Tqj/ZA1k -----END CERTIFICATE----- -Verisign Class 1 Public Primary Certification Authority - G2 -============================================================ ------BEGIN CERTIFICATE----- -MIIDAjCCAmsCEEzH6qqYPnHTkxD4PTqJkZIwDQYJKoZIhvcNAQEFBQAwgcExCzAJBgNVBAYTAlVT -MRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMSBQdWJsaWMgUHJpbWFy -eSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2ln -biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVz -dCBOZXR3b3JrMB4XDTk4MDUxODAwMDAwMFoXDTI4MDgwMTIzNTk1OVowgcExCzAJBgNVBAYTAlVT -MRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjE8MDoGA1UECxMzQ2xhc3MgMSBQdWJsaWMgUHJpbWFy -eSBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEcyMTowOAYDVQQLEzEoYykgMTk5OCBWZXJpU2ln -biwgSW5jLiAtIEZvciBhdXRob3JpemVkIHVzZSBvbmx5MR8wHQYDVQQLExZWZXJpU2lnbiBUcnVz -dCBOZXR3b3JrMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCq0Lq+Fi24g9TK0g+8djHKlNgd -k4xWArzZbxpvUjZudVYKVdPfQ4chEWWKfo+9Id5rMj8bhDSVBZ1BNeuS65bdqlk/AVNtmU/t5eIq -WpDBucSmFc/IReumXY6cPvBkJHalzasab7bYe1FhbqZ/h8jit+U03EGI6glAvnOSPWvndQIDAQAB -MA0GCSqGSIb3DQEBBQUAA4GBAKlPww3HZ74sy9mozS11534Vnjty637rXC0Jh9ZrbWB85a7FkCMM -XErQr7Fd88e2CtvgFZMN3QO8x3aKtd1Pw5sTdbgBwObJW2uluIncrKTdcu1OofdPvAbT6shkdHvC -lUGcZXNY8ZCaPGqxmMnEh7zPRW1F4m4iP/68DzFc6PLZ ------END CERTIFICATE----- - -Verisign Class 2 Public Primary Certification Authority - G2 -============================================================ ------BEGIN CERTIFICATE----- -MIIDAzCCAmwCEQC5L2DMiJ+hekYJuFtwbIqvMA0GCSqGSIb3DQEBBQUAMIHBMQswCQYDVQQGEwJV -UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xPDA6BgNVBAsTM0NsYXNzIDIgUHVibGljIFByaW1h -cnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMjE6MDgGA1UECxMxKGMpIDE5OTggVmVyaVNp -Z24sIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1 -c3QgTmV0d29yazAeFw05ODA1MTgwMDAwMDBaFw0yODA4MDEyMzU5NTlaMIHBMQswCQYDVQQGEwJV -UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xPDA6BgNVBAsTM0NsYXNzIDIgUHVibGljIFByaW1h -cnkgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMjE6MDgGA1UECxMxKGMpIDE5OTggVmVyaVNp -Z24sIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ugb25seTEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1 -c3QgTmV0d29yazCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEAp4gBIXQs5xoD8JjhlzwPIQjx -nNuX6Zr8wgQGE75fUsjMHiwSViy4AWkszJkfrbCWrnkE8hM5wXuYuggs6MKEEyyqaekJ9MepAqRC -wiNPStjwDqL7MWzJ5m+ZJwf15vRMeJ5t60aG+rmGyVTyssSv1EYcWskVMP8NbPUtDm3Of3cCAwEA -ATANBgkqhkiG9w0BAQUFAAOBgQByLvl/0fFx+8Se9sVeUYpAmLho+Jscg9jinb3/7aHmZuovCfTK -1+qlK5X2JGCGTUQug6XELaDTrnhpb3LabK4I8GOSN+a7xDAXrXfMSTWqz9iP0b63GJZHc2pUIjRk -LbYWm1lbtFFZOrMLFPQS32eg9K0yZF6xRnInjBJ7xUS0rg== ------END CERTIFICATE----- - Verisign Class 3 Public Primary Certification Authority - G2 ============================================================ -----BEGIN CERTIFICATE----- @@ -304,54 +225,6 @@ V9+vqDWzf4mH6eglkrh/hXqu1rweN1gqZ8mRzyqBPu3GOd/APhmcGcwTTYJBtYze4D1gCCAPRX5r on+jjBXu -----END CERTIFICATE----- -Verisign Class 1 Public Primary Certification Authority - G3 -============================================================ ------BEGIN CERTIFICATE----- -MIIEGjCCAwICEQCLW3VWhFSFCwDPrzhIzrGkMA0GCSqGSIb3DQEBBQUAMIHKMQswCQYDVQQGEwJV -UzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRydXN0IE5ldHdv -cmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhvcml6ZWQgdXNl -IG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDEgUHVibGljIFByaW1hcnkgQ2VydGlmaWNh -dGlvbiBBdXRob3JpdHkgLSBHMzAeFw05OTEwMDEwMDAwMDBaFw0zNjA3MTYyMzU5NTlaMIHKMQsw -CQYDVQQGEwJVUzEXMBUGA1UEChMOVmVyaVNpZ24sIEluYy4xHzAdBgNVBAsTFlZlcmlTaWduIFRy -dXN0IE5ldHdvcmsxOjA4BgNVBAsTMShjKSAxOTk5IFZlcmlTaWduLCBJbmMuIC0gRm9yIGF1dGhv -cml6ZWQgdXNlIG9ubHkxRTBDBgNVBAMTPFZlcmlTaWduIENsYXNzIDEgUHVibGljIFByaW1hcnkg -Q2VydGlmaWNhdGlvbiBBdXRob3JpdHkgLSBHMzCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoC -ggEBAN2E1Lm0+afY8wR4nN493GwTFtl63SRRZsDHJlkNrAYIwpTRMx/wgzUfbhvI3qpuFU5UJ+/E -bRrsC+MO8ESlV8dAWB6jRx9x7GD2bZTIGDnt/kIYVt/kTEkQeE4BdjVjEjbdZrwBBDajVWjVojYJ -rKshJlQGrT/KFOCsyq0GHZXi+J3x4GD/wn91K0zM2v6HmSHquv4+VNfSWXjbPG7PoBMAGrgnoeS+ -Z5bKoMWznN3JdZ7rMJpfo83ZrngZPyPpXNspva1VyBtUjGP26KbqxzcSXKMpHgLZ2x87tNcPVkeB -FQRKr4Mn0cVYiMHd9qqnoxjaaKptEVHhv2Vrn5Z20T0CAwEAATANBgkqhkiG9w0BAQUFAAOCAQEA -q2aN17O6x5q25lXQBfGfMY1aqtmqRiYPce2lrVNWYgFHKkTp/j90CxObufRNG7LRX7K20ohcs5/N -y9Sn2WCVhDr4wTcdYcrnsMXlkdpUpqwxga6X3s0IrLjAl4B/bnKk52kTlWUfxJM8/XmPBNQ+T+r3 -ns7NZ3xPZQL/kYVUc8f/NveGLezQXk//EZ9yBta4GvFMDSZl4kSAHsef493oCtrspSCAaWihT37h -a88HQfqDjrw43bAuEbFrskLMmrz5SCJ5ShkPshw+IHTZasO+8ih4E1Z5T21Q6huwtVexN2ZYI/Pc -D98Kh8TvhgXVOBRgmaNL3gaWcSzy27YfpO8/7g== ------END CERTIFICATE----- - -Verisign Class 2 Public Primary Certification Authority - G3 -============================================================ ------BEGIN CERTIFICATE----- -MIIEGTCCAwECEGFwy0mMX5hFKeewptlQW3owDQYJKoZIhvcNAQEFBQAwgcoxCzAJBgNVBAYTAlVT -MRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1c3QgTmV0d29y -azE6MDgGA1UECxMxKGMpIDE5OTkgVmVyaVNpZ24sIEluYy4gLSBGb3IgYXV0aG9yaXplZCB1c2Ug -b25seTFFMEMGA1UEAxM8VmVyaVNpZ24gQ2xhc3MgMiBQdWJsaWMgUHJpbWFyeSBDZXJ0aWZpY2F0 -aW9uIEF1dGhvcml0eSAtIEczMB4XDTk5MTAwMTAwMDAwMFoXDTM2MDcxNjIzNTk1OVowgcoxCzAJ -BgNVBAYTAlVTMRcwFQYDVQQKEw5WZXJpU2lnbiwgSW5jLjEfMB0GA1UECxMWVmVyaVNpZ24gVHJ1 -c3QgTmV0d29yazE6MDgGA1UECxMxKGMpIDE5OTkgVmVyaVNpZ24sIEluYy4gLSBGb3IgYXV0aG9y -aXplZCB1c2Ugb25seTFFMEMGA1UEAxM8VmVyaVNpZ24gQ2xhc3MgMiBQdWJsaWMgUHJpbWFyeSBD -ZXJ0aWZpY2F0aW9uIEF1dGhvcml0eSAtIEczMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKC -AQEArwoNwtUs22e5LeWUJ92lvuCwTY+zYVY81nzD9M0+hsuiiOLh2KRpxbXiv8GmR1BeRjmL1Za6 -tW8UvxDOJxOeBUebMXoT2B/Z0wI3i60sR/COgQanDTAM6/c8DyAd3HJG7qUCyFvDyVZpTMUYwZF7 -C9UTAJu878NIPkZgIIUq1ZC2zYugzDLdt/1AVbJQHFauzI13TccgTacxdu9okoqQHgiBVrKtaaNS -0MscxCM9H5n+TOgWY47GCI72MfbS+uV23bUckqNJzc0BzWjNqWm6o+sdDZykIKbBoMXRRkwXbdKs -Zj+WjOCE1Db/IlnF+RFgqF8EffIa9iVCYQ/ESrg+iQIDAQABMA0GCSqGSIb3DQEBBQUAA4IBAQA0 -JhU8wI1NQ0kdvekhktdmnLfexbjQ5F1fdiLAJvmEOjr5jLX77GDx6M4EsMjdpwOPMPOY36TmpDHf -0xwLRtxyID+u7gU8pDM/CzmscHhzS5kr3zDCVLCoO1Wh/hYozUK9dG6A2ydEp85EXdQbkJgNHkKU -sQAsBNB0owIFImNjzYO1+8FtYmtpdf1dcEG59b98377BMnMiIYtYgXsVkXq642RIsH/7NiXaldDx -JBQX3RiAa0YjOVT1jmIJBB2UkKab5iXiQkWquJCtvgiPqQtCGJTPcjnhsUPgKM+351psE2tJs//j -GHyJizNdrDPXp/naOlXJWBD5qu9ats9LS98q ------END CERTIFICATE----- - Verisign Class 3 Public Primary Certification Authority - G3 ============================================================ -----BEGIN CERTIFICATE----- @@ -430,11 +303,11 @@ n9cd2cNgQ4xYDiKWL2KjLB+6rQXvqzJ4h6BUcxm1XAX5Uj5tLUUL9wqT6u0G+bI= Entrust.net Premium 2048 Secure Server CA ========================================= -----BEGIN CERTIFICATE----- -MIIEXDCCA0SgAwIBAgIEOGO5ZjANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChMLRW50cnVzdC5u +MIIEKjCCAxKgAwIBAgIEOGPe+DANBgkqhkiG9w0BAQUFADCBtDEUMBIGA1UEChMLRW50cnVzdC5u ZXQxQDA+BgNVBAsUN3d3dy5lbnRydXN0Lm5ldC9DUFNfMjA0OCBpbmNvcnAuIGJ5IHJlZi4gKGxp bWl0cyBsaWFiLikxJTAjBgNVBAsTHChjKSAxOTk5IEVudHJ1c3QubmV0IExpbWl0ZWQxMzAxBgNV BAMTKkVudHJ1c3QubmV0IENlcnRpZmljYXRpb24gQXV0aG9yaXR5ICgyMDQ4KTAeFw05OTEyMjQx -NzUwNTFaFw0xOTEyMjQxODIwNTFaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3 +NzUwNTFaFw0yOTA3MjQxNDE1MTJaMIG0MRQwEgYDVQQKEwtFbnRydXN0Lm5ldDFAMD4GA1UECxQ3 d3d3LmVudHJ1c3QubmV0L0NQU18yMDQ4IGluY29ycC4gYnkgcmVmLiAobGltaXRzIGxpYWIuKTEl MCMGA1UECxMcKGMpIDE5OTkgRW50cnVzdC5uZXQgTGltaXRlZDEzMDEGA1UEAxMqRW50cnVzdC5u ZXQgQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgKDIwNDgpMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A @@ -442,14 +315,13 @@ MIIBCgKCAQEArU1LqRKGsuqjIAcVFmQqK0vRvwtKTY7tgHalZ7d4QMBzQshowNtTK91euHaYNZOL Gp18EzoOH1u3Hs/lJBQesYGpjX24zGtLA/ECDNyrpUAkAH90lKGdCCmziAv1h3edVc3kw37XamSr hRSGlVuXMlBvPci6Zgzj/L24ScF2iUkZ/cCovYmjZy/Gn7xxGWC4LeksyZB2ZnuU4q941mVTXTzW nLLPKQP5L6RQstRIzgUyVYr9smRMDuSYB3Xbf9+5CFVghTAp+XtIpGmG4zU/HoZdenoVve8AjhUi -VBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH4QIDAQABo3QwcjARBglghkgBhvhC -AQEEBAMCAAcwHwYDVR0jBBgwFoAUVeSB0RGAvtiJuQijMfmhJAkWuXAwHQYDVR0OBBYEFFXkgdER -gL7YibkIozH5oSQJFrlwMB0GCSqGSIb2fQdBAAQQMA4bCFY1LjA6NC4wAwIEkDANBgkqhkiG9w0B -AQUFAAOCAQEAWUesIYSKF8mciVMeuoCFGsY8Tj6xnLZ8xpJdGGQC49MGCBFhfGPjK50xA3B20qMo -oPS7mmNz7W3lKtvtFKkrxjYR0CvrB4ul2p5cGZ1WEvVUKcgF7bISKo30Axv/55IQh7A6tcOdBTcS -o8f0FbnVpDkWm1M6I5HxqIKiaohowXkCIryqptau37AUX7iH0N18f3v/rxzP5tsHrV7bhZ3QKw0z -2wTR5klAEyt2+z7pnIkPFc4YsIV4IU9rTw76NmfNB/L/CNDi3tm/Kq+4h4YhPATKt5Rof8886ZjX -OP/swNlQ8C5LWK5Gb9Auw2DaclVyvUxFnmG6v4SBkgPR0ml8xQ== +VBcAkCaTvA5JaJG/+EfTnZVCwQ5N328mz8MYIWJmQ3DW1cAH4QIDAQABo0IwQDAOBgNVHQ8BAf8E +BAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUVeSB0RGAvtiJuQijMfmhJAkWuXAwDQYJ +KoZIhvcNAQEFBQADggEBADubj1abMOdTmXx6eadNl9cZlZD7Bh/KM3xGY4+WZiT6QBshJ8rmcnPy +T/4xmf3IDExoU8aAghOY+rat2l098c5u9hURlIIM7j+VrxGrD9cv3h8Dj1csHsm7mhpElesYT6Yf +zX1XEC+bBAlahLVu2B064dae0Wx5XnkcFMXj0EyTO2U87d89vqbllRrDtRnDvV5bu/8j72gZyxKT +J1wDLW8w0B62GqzeWvfRqqgnpv55gcR5mTNXuhKwqeBCbJPKVt7+bYQLCIt+jerXmCHG8+c8eS9e +nNFMFY3h7CI3zJpDC5fcgJCNs2ebb0gIFVbPv/ErfF6adulZkMV8gzURZVE= -----END CERTIFICATE----- Baltimore CyberTrust Root @@ -507,26 +379,6 @@ lSE/9dR+WB5Hh1Q+WKG1tfgq73HnvMP2sUlG4tega+VWeponmHxGYhTnyfxuAxJ5gDgdSIKN/Bf+ KpYrtWKmpj29f5JZzVoqgrI3eQ== -----END CERTIFICATE----- -Equifax Secure eBusiness CA 2 -============================= ------BEGIN CERTIFICATE----- -MIIDIDCCAomgAwIBAgIEN3DPtTANBgkqhkiG9w0BAQUFADBOMQswCQYDVQQGEwJVUzEXMBUGA1UE -ChMORXF1aWZheCBTZWN1cmUxJjAkBgNVBAsTHUVxdWlmYXggU2VjdXJlIGVCdXNpbmVzcyBDQS0y -MB4XDTk5MDYyMzEyMTQ0NVoXDTE5MDYyMzEyMTQ0NVowTjELMAkGA1UEBhMCVVMxFzAVBgNVBAoT -DkVxdWlmYXggU2VjdXJlMSYwJAYDVQQLEx1FcXVpZmF4IFNlY3VyZSBlQnVzaW5lc3MgQ0EtMjCB -nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA5Dk5kx5SBhsoNviyoynF7Y6yEb3+6+e0dMKP/wXn -2Z0GvxLIPw7y1tEkshHe0XMJitSxLJgJDR5QRrKDpkWNYmi7hRsgcDKqQM2mll/EcTc/BPO3QSQ5 -BxoeLmFYoBIL5aXfxavqN3HMHMg3OrmXUqesxWoklE6ce8/AatbfIb0CAwEAAaOCAQkwggEFMHAG -A1UdHwRpMGcwZaBjoGGkXzBdMQswCQYDVQQGEwJVUzEXMBUGA1UEChMORXF1aWZheCBTZWN1cmUx -JjAkBgNVBAsTHUVxdWlmYXggU2VjdXJlIGVCdXNpbmVzcyBDQS0yMQ0wCwYDVQQDEwRDUkwxMBoG -A1UdEAQTMBGBDzIwMTkwNjIzMTIxNDQ1WjALBgNVHQ8EBAMCAQYwHwYDVR0jBBgwFoAUUJ4L6q9e -uSBIplBqy/3YIHqngnYwHQYDVR0OBBYEFFCeC+qvXrkgSKZQasv92CB6p4J2MAwGA1UdEwQFMAMB -Af8wGgYJKoZIhvZ9B0EABA0wCxsFVjMuMGMDAgbAMA0GCSqGSIb3DQEBBQUAA4GBAAyGgq3oThr1 -jokn4jVYPSm0B482UJW/bsGe68SQsoWou7dC4A8HOd/7npCy0cE+U58DRLB+S/Rv5Hwf5+Kx5Lia -78O9zt4LMjTZ3ijtM2vE1Nc9ElirfQkty3D1E4qUoSek1nDFbZS1yX2doNLGCEnZZpum0/QL3MUm -V+GRMOrN ------END CERTIFICATE----- - AddTrust Low-Value Services Root ================================ -----BEGIN CERTIFICATE----- @@ -772,31 +624,6 @@ gn2Z9DH2canPLAEnpQW5qrJITirvn5NSUZU8UnOOVkwXQMAJKOSLakhT2+zNVVXxxvjpoixMptEm X36vWkzaH6byHCx+rgIW0lbQL1dTR+iS -----END CERTIFICATE----- -UTN-USER First-Network Applications -=================================== ------BEGIN CERTIFICATE----- -MIIEZDCCA0ygAwIBAgIQRL4Mi1AAJLQR0zYwS8AzdzANBgkqhkiG9w0BAQUFADCBozELMAkGA1UE -BhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhl -IFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xKzAp -BgNVBAMTIlVUTi1VU0VSRmlyc3QtTmV0d29yayBBcHBsaWNhdGlvbnMwHhcNOTkwNzA5MTg0ODM5 -WhcNMTkwNzA5MTg1NzQ5WjCBozELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5T -YWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhlIFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExho -dHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xKzApBgNVBAMTIlVUTi1VU0VSRmlyc3QtTmV0d29yayBB -cHBsaWNhdGlvbnMwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCz+5Gh5DZVhawGNFug -mliy+LUPBXeDrjKxdpJo7CNKyXY/45y2N3kDuatpjQclthln5LAbGHNhSuh+zdMvZOOmfAz6F4Cj -DUeJT1FxL+78P/m4FoCHiZMlIJpDgmkkdihZNaEdwH+DBmQWICzTSaSFtMBhf1EI+GgVkYDLpdXu -Ozr0hAReYFmnjDRy7rh4xdE7EkpvfmUnuaRVxblvQ6TFHSyZwFKkeEwVs0CYCGtDxgGwenv1axwi -P8vv/6jQOkt2FZ7S0cYu49tXGzKiuG/ohqY/cKvlcJKrRB5AUPuco2LkbG6gyN7igEL66S/ozjIE -j3yNtxyjNTwV3Z7DrpelAgMBAAGjgZEwgY4wCwYDVR0PBAQDAgHGMA8GA1UdEwEB/wQFMAMBAf8w -HQYDVR0OBBYEFPqGydvguul49Uuo1hXf8NPhahQ8ME8GA1UdHwRIMEYwRKBCoECGPmh0dHA6Ly9j -cmwudXNlcnRydXN0LmNvbS9VVE4tVVNFUkZpcnN0LU5ldHdvcmtBcHBsaWNhdGlvbnMuY3JsMA0G -CSqGSIb3DQEBBQUAA4IBAQCk8yXM0dSRgyLQzDKrm5ZONJFUICU0YV8qAhXhi6r/fWRRzwr/vH3Y -IWp4yy9Rb/hCHTO967V7lMPDqaAt39EpHx3+jz+7qEUqf9FuVSTiuwL7MT++6LzsQCv4AdRWOOTK -RIK1YSAhZ2X28AvnNPilwpyjXEAfhZOVBt5P1CeptqX8Fs1zMT+4ZSfP1FMa8Kxun08FDAOBp4Qp -xFq9ZFdyrTvPNximmMatBrTcCKME1SmklpoSZ0qMYEWd8SOasACcaLWYUNPvji6SZbFIPiG+FTAq -DbUMo2s/rn9X9R+WfN9v3YIwLGUbQErNaLly7HF27FSOH4UMAWr6pjisH8SE ------END CERTIFICATE----- - America Online Root Certification Authority 1 ============================================= -----BEGIN CERTIFICATE----- @@ -1084,26 +911,6 @@ s58+OmJYxUmtYg5xpTKqL8aJdkNAExNnPaJUJRDL8Try2frbSVa7pv6nQTXD4IhhyYjH3zYQIphZ FL39vmwLAw== -----END CERTIFICATE----- -Sonera Class 1 Root CA -====================== ------BEGIN CERTIFICATE----- -MIIDIDCCAgigAwIBAgIBJDANBgkqhkiG9w0BAQUFADA5MQswCQYDVQQGEwJGSTEPMA0GA1UEChMG -U29uZXJhMRkwFwYDVQQDExBTb25lcmEgQ2xhc3MxIENBMB4XDTAxMDQwNjEwNDkxM1oXDTIxMDQw -NjEwNDkxM1owOTELMAkGA1UEBhMCRkkxDzANBgNVBAoTBlNvbmVyYTEZMBcGA1UEAxMQU29uZXJh -IENsYXNzMSBDQTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALWJHytPZwp5/8Ue+H88 -7dF+2rDNbS82rDTG29lkFwhjMDMiikzujrsPDUJVyZ0upe/3p4zDq7mXy47vPxVnqIJyY1MPQYx9 -EJUkoVqlBvqSV536pQHydekfvFYmUk54GWVYVQNYwBSujHxVX3BbdyMGNpfzJLWaRpXk3w0LBUXl -0fIdgrvGE+D+qnr9aTCU89JFhfzyMlsy3uhsXR/LpCJ0sICOXZT3BgBLqdReLjVQCfOAl/QMF645 -2F/NM8EcyonCIvdFEu1eEpOdY6uCLrnrQkFEy0oaAIINnvmLVz5MxxftLItyM19yejhW1ebZrgUa -HXVFsculJRwSVzb9IjcCAwEAAaMzMDEwDwYDVR0TAQH/BAUwAwEB/zARBgNVHQ4ECgQIR+IMi/ZT -iFIwCwYDVR0PBAQDAgEGMA0GCSqGSIb3DQEBBQUAA4IBAQCLGrLJXWG04bkruVPRsoWdd44W7hE9 -28Jj2VuXZfsSZ9gqXLar5V7DtxYvyOirHYr9qxp81V9jz9yw3Xe5qObSIjiHBxTZ/75Wtf0HDjxV -yhbMp6Z3N/vbXB9OWQaHowND9Rart4S9Tu+fMTfwRvFAttEMpWT4Y14h21VOTzF2nBBhjrZTOqMR -vq9tfB69ri3iDGnHhVNoomG6xT60eVR4ngrHAr5i0RGCS2UvkVrCqIexVmiUefkl98HVrhq4uz2P -qYo4Ffdz0Fpg0YCw8NzVUM1O7pJIae2yIx4wzMiUyLb1O4Z/P6Yun/Y+LLWSlj7fLJOK/4GMDw9Z -IRlXvVWa ------END CERTIFICATE----- - Sonera Class 2 Root CA ====================== -----BEGIN CERTIFICATE----- @@ -1170,34 +977,6 @@ O0ESm70NRyN/PErQr8Cv9u8btRXE64PECV90i9kR+8JWsTz4cMo0jUNAE4z9mQNUecYu6oah9jrU Cbz0vGbMPVjQV0kK7iXiQe4T+Zs4NNEA9X7nlB38aQNiuJkFBT1reBK9sG9l -----END CERTIFICATE----- -TDC OCES Root CA -================ ------BEGIN CERTIFICATE----- -MIIFGTCCBAGgAwIBAgIEPki9xDANBgkqhkiG9w0BAQUFADAxMQswCQYDVQQGEwJESzEMMAoGA1UE -ChMDVERDMRQwEgYDVQQDEwtUREMgT0NFUyBDQTAeFw0wMzAyMTEwODM5MzBaFw0zNzAyMTEwOTA5 -MzBaMDExCzAJBgNVBAYTAkRLMQwwCgYDVQQKEwNUREMxFDASBgNVBAMTC1REQyBPQ0VTIENBMIIB -IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEArGL2YSCyz8DGhdfjeebM7fI5kqSXLmSjhFuH -nEz9pPPEXyG9VhDr2y5h7JNp46PMvZnDBfwGuMo2HP6QjklMxFaaL1a8z3sM8W9Hpg1DTeLpHTk0 -zY0s2RKY+ePhwUp8hjjEqcRhiNJerxomTdXkoCJHhNlktxmW/OwZ5LKXJk5KTMuPJItUGBxIYXvV -iGjaXbXqzRowwYCDdlCqT9HU3Tjw7xb04QxQBr/q+3pJoSgrHPb8FTKjdGqPqcNiKXEx5TukYBde -dObaE+3pHx8b0bJoc8YQNHVGEBDjkAB2QMuLt0MJIf+rTpPGWOmlgtt3xDqZsXKVSQTwtyv6e1mO -3QIDAQABo4ICNzCCAjMwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwgewGA1UdIASB -5DCB4TCB3gYIKoFQgSkBAQEwgdEwLwYIKwYBBQUHAgEWI2h0dHA6Ly93d3cuY2VydGlmaWthdC5k -ay9yZXBvc2l0b3J5MIGdBggrBgEFBQcCAjCBkDAKFgNUREMwAwIBARqBgUNlcnRpZmlrYXRlciBm -cmEgZGVubmUgQ0EgdWRzdGVkZXMgdW5kZXIgT0lEIDEuMi4yMDguMTY5LjEuMS4xLiBDZXJ0aWZp -Y2F0ZXMgZnJvbSB0aGlzIENBIGFyZSBpc3N1ZWQgdW5kZXIgT0lEIDEuMi4yMDguMTY5LjEuMS4x -LjARBglghkgBhvhCAQEEBAMCAAcwgYEGA1UdHwR6MHgwSKBGoESkQjBAMQswCQYDVQQGEwJESzEM -MAoGA1UEChMDVERDMRQwEgYDVQQDEwtUREMgT0NFUyBDQTENMAsGA1UEAxMEQ1JMMTAsoCqgKIYm -aHR0cDovL2NybC5vY2VzLmNlcnRpZmlrYXQuZGsvb2Nlcy5jcmwwKwYDVR0QBCQwIoAPMjAwMzAy -MTEwODM5MzBagQ8yMDM3MDIxMTA5MDkzMFowHwYDVR0jBBgwFoAUYLWF7FZkfhIZJ2cdUBVLc647 -+RIwHQYDVR0OBBYEFGC1hexWZH4SGSdnHVAVS3OuO/kSMB0GCSqGSIb2fQdBAAQQMA4bCFY2LjA6 -NC4wAwIEkDANBgkqhkiG9w0BAQUFAAOCAQEACromJkbTc6gJ82sLMJn9iuFXehHTuJTXCRBuo7E4 -A9G28kNBKWKnctj7fAXmMXAnVBhOinxO5dHKjHiIzxvTkIvmI/gLDjNDfZziChmPyQE+dF10yYsc -A+UYyAFMP8uXBV2YcaaYb7Z8vTd/vuGTJW1v8AqtFxjhA7wHKcitJuj4YfD9IQl+mo6paH1IYnK9 -AOoBmbgGglGBTvH1tJFUuSN6AJqfXY3gPGS5GhKSKseCRHI53OI8xthV9RVOyAUO28bQYqbsFbS1 -AoLbrIyigfCbmTH1ICCoiGEKB5+U/NDXG8wuF/MEJ3Zn61SD/aSQfgY9BKNDLdr8C2LqL19iUw== ------END CERTIFICATE----- - UTN DATACorp SGC Root CA ======================== -----BEGIN CERTIFICATE----- @@ -1223,32 +1002,6 @@ EZ4du5A/EkdOjtd+D2JzHVImOBwYSf0wdJrE5SIv2MCN7ZF6TACPcn9d2t0bi0Vr591pl6jFVkwP DPafepE39peC4N1xaf92P2BNPM/3mfnGV/TJVTl4uix5yaaIK/QI -----END CERTIFICATE----- -UTN USERFirst Email Root CA -=========================== ------BEGIN CERTIFICATE----- -MIIEojCCA4qgAwIBAgIQRL4Mi1AAJLQR0zYlJWfJiTANBgkqhkiG9w0BAQUFADCBrjELMAkGA1UE -BhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhl -IFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xNjA0 -BgNVBAMTLVVUTi1VU0VSRmlyc3QtQ2xpZW50IEF1dGhlbnRpY2F0aW9uIGFuZCBFbWFpbDAeFw05 -OTA3MDkxNzI4NTBaFw0xOTA3MDkxNzM2NThaMIGuMQswCQYDVQQGEwJVUzELMAkGA1UECBMCVVQx -FzAVBgNVBAcTDlNhbHQgTGFrZSBDaXR5MR4wHAYDVQQKExVUaGUgVVNFUlRSVVNUIE5ldHdvcmsx -ITAfBgNVBAsTGGh0dHA6Ly93d3cudXNlcnRydXN0LmNvbTE2MDQGA1UEAxMtVVROLVVTRVJGaXJz -dC1DbGllbnQgQXV0aGVudGljYXRpb24gYW5kIEVtYWlsMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A -MIIBCgKCAQEAsjmFpPJ9q0E7YkY3rs3BYHW8OWX5ShpHornMSMxqmNVNNRm5pELlzkniii8efNIx -B8dOtINknS4p1aJkxIW9hVE1eaROaJB7HHqkkqgX8pgV8pPMyaQylbsMTzC9mKALi+VuG6JG+ni8 -om+rWV6lL8/K2m2qL+usobNqqrcuZzWLeeEeaYji5kbNoKXqvgvOdjp6Dpvq/NonWz1zHyLmSGHG -TPNpsaguG7bUMSAsvIKKjqQOpdeJQ/wWWq8dcdcRWdq6hw2v+vPhwvCkxWeM1tZUOt4KpLoDd7Nl -yP0e03RiqhjKaJMeoYV+9Udly/hNVyh00jT/MLbu9mIwFIws6wIDAQABo4G5MIG2MAsGA1UdDwQE -AwIBxjAPBgNVHRMBAf8EBTADAQH/MB0GA1UdDgQWBBSJgmd9xJ0mcABLtFBIfN49rgRufTBYBgNV -HR8EUTBPME2gS6BJhkdodHRwOi8vY3JsLnVzZXJ0cnVzdC5jb20vVVROLVVTRVJGaXJzdC1DbGll -bnRBdXRoZW50aWNhdGlvbmFuZEVtYWlsLmNybDAdBgNVHSUEFjAUBggrBgEFBQcDAgYIKwYBBQUH -AwQwDQYJKoZIhvcNAQEFBQADggEBALFtYV2mGn98q0rkMPxTbyUkxsrt4jFcKw7u7mFVbwQ+zzne -xRtJlOTrIEy05p5QLnLZjfWqo7NK2lYcYJeA3IKirUq9iiv/Cwm0xtcgBEXkzYABurorbs6q15L+ -5K/r9CYdFip/bDCVNy8zEqx/3cfREYxRmLLQo5HQrfafnoOTHh1CuEava2bwm3/q4wMC5QJRwarV -NZ1yQAOJujEdxRBoUp7fooXFXAimeOZTT7Hot9MUnpOmw2TjrH5xzbyf6QMbzPvprDHBr3wVdAKZ -w7JHpsIyYdfHb0gkUSeh1YdV8nuPmD0Wnu51tvjQjvLzxq4oW6fw8zYX/MMF08oDSlQ= ------END CERTIFICATE----- - UTN USERFirst Hardware Root CA ============================== -----BEGIN CERTIFICATE----- @@ -1275,31 +1028,6 @@ iCrVWFCVH/A7HFe7fRQ5YiuayZSSKqMiDP+JJn1fIytH1xUdqWqeUQ0qUZ6B+dQ7XnASfxAynB67 nfhmqA== -----END CERTIFICATE----- -UTN USERFirst Object Root CA -============================ ------BEGIN CERTIFICATE----- -MIIEZjCCA06gAwIBAgIQRL4Mi1AAJLQR0zYt4LNfGzANBgkqhkiG9w0BAQUFADCBlTELMAkGA1UE -BhMCVVMxCzAJBgNVBAgTAlVUMRcwFQYDVQQHEw5TYWx0IExha2UgQ2l0eTEeMBwGA1UEChMVVGhl -IFVTRVJUUlVTVCBOZXR3b3JrMSEwHwYDVQQLExhodHRwOi8vd3d3LnVzZXJ0cnVzdC5jb20xHTAb -BgNVBAMTFFVUTi1VU0VSRmlyc3QtT2JqZWN0MB4XDTk5MDcwOTE4MzEyMFoXDTE5MDcwOTE4NDAz -NlowgZUxCzAJBgNVBAYTAlVTMQswCQYDVQQIEwJVVDEXMBUGA1UEBxMOU2FsdCBMYWtlIENpdHkx -HjAcBgNVBAoTFVRoZSBVU0VSVFJVU1QgTmV0d29yazEhMB8GA1UECxMYaHR0cDovL3d3dy51c2Vy -dHJ1c3QuY29tMR0wGwYDVQQDExRVVE4tVVNFUkZpcnN0LU9iamVjdDCCASIwDQYJKoZIhvcNAQEB -BQADggEPADCCAQoCggEBAM6qgT+jo2F4qjEAVZURnicPHxzfOpuCaDDASmEd8S8O+r5596Uj71VR -loTN2+O5bj4x2AogZ8f02b+U60cEPgLOKqJdhwQJ9jCdGIqXsqoc/EHSoTbL+z2RuufZcDX65OeQ -w5ujm9M89RKZd7G3CeBo5hy485RjiGpq/gt2yb70IuRnuasaXnfBhQfdDWy/7gbHd2pBnqcP1/vu -lBe3/IW+pKvEHDHd17bR5PDv3xaPslKT16HUiaEHLr/hARJCHhrh2JU022R5KP+6LhHC5ehbkkj7 -RwvCbNqtMoNB86XlQXD9ZZBt+vpRxPm9lisZBCzTbafc8H9vg2XiaquHhnUCAwEAAaOBrzCBrDAL -BgNVHQ8EBAMCAcYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQU2u1kdBScFDyr3ZmpvVsoTYs8 -ydgwQgYDVR0fBDswOTA3oDWgM4YxaHR0cDovL2NybC51c2VydHJ1c3QuY29tL1VUTi1VU0VSRmly -c3QtT2JqZWN0LmNybDApBgNVHSUEIjAgBggrBgEFBQcDAwYIKwYBBQUHAwgGCisGAQQBgjcKAwQw -DQYJKoZIhvcNAQEFBQADggEBAAgfUrE3RHjb/c652pWWmKpVZIC1WkDdIaXFwfNfLEzIR1pp6ujw -NTX00CXzyKakh0q9G7FzCL3Uw8q2NbtZhncxzaeAFK4T7/yxSPlrJSUtUbYsbUXBmMiKVl0+7kNO -PmsnjtA6S4ULX9Ptaqd1y9Fahy85dRNacrACgZ++8A+EVCBibGnU4U3GDZlDAQ0Slox4nb9QorFE -qmrPF3rPbw/U+CRVX/A0FklmPlBGyWNxODFiuGK581OtbLUrohKqGU8J2l7nk8aOFAj+8DCAGKCG -hU3IfdeLA/5u1fedFqySLKAj5ZyRUh+U3xeUc8OzwcFxBSAAeL0TUh2oPs0AH8g= ------END CERTIFICATE----- - Camerfirma Chambers of Commerce Root ==================================== -----BEGIN CERTIFICATE----- @@ -1354,42 +1082,6 @@ IBHNfTIzSJRUTN3cecQwn+uOuFW114hcxWokPbLTBQNRxgfvzBRydD1ucs4YKIxKoHflCStFREes t2d/AYoFWpO+ocH/+OcOZ6RHSXZddZAa9SaP8A== -----END CERTIFICATE----- -NetLock Qualified (Class QA) Root -================================= ------BEGIN CERTIFICATE----- -MIIG0TCCBbmgAwIBAgIBezANBgkqhkiG9w0BAQUFADCByTELMAkGA1UEBhMCSFUxETAPBgNVBAcT -CEJ1ZGFwZXN0MScwJQYDVQQKEx5OZXRMb2NrIEhhbG96YXRiaXp0b25zYWdpIEtmdC4xGjAYBgNV -BAsTEVRhbnVzaXR2YW55a2lhZG9rMUIwQAYDVQQDEzlOZXRMb2NrIE1pbm9zaXRldHQgS296amVn -eXpvaSAoQ2xhc3MgUUEpIFRhbnVzaXR2YW55a2lhZG8xHjAcBgkqhkiG9w0BCQEWD2luZm9AbmV0 -bG9jay5odTAeFw0wMzAzMzAwMTQ3MTFaFw0yMjEyMTUwMTQ3MTFaMIHJMQswCQYDVQQGEwJIVTER -MA8GA1UEBxMIQnVkYXBlc3QxJzAlBgNVBAoTHk5ldExvY2sgSGFsb3phdGJpenRvbnNhZ2kgS2Z0 -LjEaMBgGA1UECxMRVGFudXNpdHZhbnlraWFkb2sxQjBABgNVBAMTOU5ldExvY2sgTWlub3NpdGV0 -dCBLb3pqZWd5em9pIChDbGFzcyBRQSkgVGFudXNpdHZhbnlraWFkbzEeMBwGCSqGSIb3DQEJARYP -aW5mb0BuZXRsb2NrLmh1MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAx1Ilstg91IRV -CacbvWy5FPSKAtt2/GoqeKvld/Bu4IwjZ9ulZJm53QE+b+8tmjwi8F3JV6BVQX/yQ15YglMxZc4e -8ia6AFQer7C8HORSjKAyr7c3sVNnaHRnUPYtLmTeriZ539+Zhqurf4XsoPuAzPS4DB6TRWO53Lhb -m+1bOdRfYrCnjnxmOCyqsQhjF2d9zL2z8cM/z1A57dEZgxXbhxInlrfa6uWdvLrqOU+L73Sa58XQ -0uqGURzk/mQIKAR5BevKxXEOC++r6uwSEaEYBTJp0QwsGj0lmT+1fMptsK6ZmfoIYOcZwvK9UdPM -0wKswREMgM6r3JSda6M5UzrWhQIDAMV9o4ICwDCCArwwEgYDVR0TAQH/BAgwBgEB/wIBBDAOBgNV -HQ8BAf8EBAMCAQYwggJ1BglghkgBhvhCAQ0EggJmFoICYkZJR1lFTEVNISBFemVuIHRhbnVzaXR2 -YW55IGEgTmV0TG9jayBLZnQuIE1pbm9zaXRldHQgU3pvbGdhbHRhdGFzaSBTemFiYWx5emF0YWJh -biBsZWlydCBlbGphcmFzb2sgYWxhcGphbiBrZXN6dWx0LiBBIG1pbm9zaXRldHQgZWxla3Ryb25p -a3VzIGFsYWlyYXMgam9naGF0YXMgZXJ2ZW55ZXN1bGVzZW5laywgdmFsYW1pbnQgZWxmb2dhZGFz -YW5hayBmZWx0ZXRlbGUgYSBNaW5vc2l0ZXR0IFN6b2xnYWx0YXRhc2kgU3phYmFseXphdGJhbiwg -YXogQWx0YWxhbm9zIFN6ZXJ6b2Rlc2kgRmVsdGV0ZWxla2JlbiBlbG9pcnQgZWxsZW5vcnplc2kg -ZWxqYXJhcyBtZWd0ZXRlbGUuIEEgZG9rdW1lbnR1bW9rIG1lZ3RhbGFsaGF0b2sgYSBodHRwczov -L3d3dy5uZXRsb2NrLmh1L2RvY3MvIGNpbWVuIHZhZ3kga2VyaGV0b2sgYXogaW5mb0BuZXRsb2Nr -Lm5ldCBlLW1haWwgY2ltZW4uIFdBUk5JTkchIFRoZSBpc3N1YW5jZSBhbmQgdGhlIHVzZSBvZiB0 -aGlzIGNlcnRpZmljYXRlIGFyZSBzdWJqZWN0IHRvIHRoZSBOZXRMb2NrIFF1YWxpZmllZCBDUFMg -YXZhaWxhYmxlIGF0IGh0dHBzOi8vd3d3Lm5ldGxvY2suaHUvZG9jcy8gb3IgYnkgZS1tYWlsIGF0 -IGluZm9AbmV0bG9jay5uZXQwHQYDVR0OBBYEFAlqYhaSsFq7VQ7LdTI6MuWyIckoMA0GCSqGSIb3 -DQEBBQUAA4IBAQCRalCc23iBmz+LQuM7/KbD7kPgz/PigDVJRXYC4uMvBcXxKufAQTPGtpvQMznN -wNuhrWw3AkxYQTvyl5LGSKjN5Yo5iWH5Upfpvfb5lHTocQ68d4bDBsxafEp+NFAwLvt/MpqNPfMg -W/hqyobzMUwsWYACff44yTB1HLdV47yfuqhthCgFdbOLDcCRVCHnpgu0mfVRQdzNo0ci2ccBgcTc -R08m6h/t280NmPSjnLRzMkqWmf68f8glWPhY83ZmiVSkpj7EUFy6iRiCdUgh0k8T6GB+B3bbELVR -5qq5aKrN9p2QdRLqOBrKROi3macqaJVmlaut74nLYKkGEsaUR+ko ------END CERTIFICATE----- - NetLock Notary (Class A) Root ============================= -----BEGIN CERTIFICATE----- @@ -1651,29 +1343,6 @@ wUpgpZKpsaSgYMN4h7Mi8yrrW6ntBas3D7Hi05V2Y1Z0jFhyGzflZKG+TQyTmAyX9odtsz/ny4Cm VM+h4k0460tQtcsm9MracEpqoeJ5quGnM/b9Sh/22WA= -----END CERTIFICATE----- -Wells Fargo Root CA -=================== ------BEGIN CERTIFICATE----- -MIID5TCCAs2gAwIBAgIEOeSXnjANBgkqhkiG9w0BAQUFADCBgjELMAkGA1UEBhMCVVMxFDASBgNV -BAoTC1dlbGxzIEZhcmdvMSwwKgYDVQQLEyNXZWxscyBGYXJnbyBDZXJ0aWZpY2F0aW9uIEF1dGhv -cml0eTEvMC0GA1UEAxMmV2VsbHMgRmFyZ28gUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwHhcN -MDAxMDExMTY0MTI4WhcNMjEwMTE0MTY0MTI4WjCBgjELMAkGA1UEBhMCVVMxFDASBgNVBAoTC1dl -bGxzIEZhcmdvMSwwKgYDVQQLEyNXZWxscyBGYXJnbyBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTEv -MC0GA1UEAxMmV2VsbHMgRmFyZ28gUm9vdCBDZXJ0aWZpY2F0ZSBBdXRob3JpdHkwggEiMA0GCSqG -SIb3DQEBAQUAA4IBDwAwggEKAoIBAQDVqDM7Jvk0/82bfuUER84A4n135zHCLielTWi5MbqNQ1mX -x3Oqfz1cQJ4F5aHiidlMuD+b+Qy0yGIZLEWukR5zcUHESxP9cMIlrCL1dQu3U+SlK93OvRw6esP3 -E48mVJwWa2uv+9iWsWCaSOAlIiR5NM4OJgALTqv9i86C1y8IcGjBqAr5dE8Hq6T54oN+J3N0Prj5 -OEL8pahbSCOz6+MlsoCultQKnMJ4msZoGK43YjdeUXWoWGPAUe5AeH6orxqg4bB4nVCMe+ez/I4j -sNtlAHCEAQgAFG5Uhpq6zPk3EPbg3oQtnaSFN9OH4xXQwReQfhkhahKpdv0SAulPIV4XAgMBAAGj -YTBfMA8GA1UdEwEB/wQFMAMBAf8wTAYDVR0gBEUwQzBBBgtghkgBhvt7hwcBCzAyMDAGCCsGAQUF -BwIBFiRodHRwOi8vd3d3LndlbGxzZmFyZ28uY29tL2NlcnRwb2xpY3kwDQYJKoZIhvcNAQEFBQAD -ggEBANIn3ZwKdyu7IvICtUpKkfnRLb7kuxpo7w6kAOnu5+/u9vnldKTC2FJYxHT7zmu1Oyl5GFrv -m+0fazbuSCUlFLZWohDo7qd/0D+j0MNdJu4HzMPBJCGHHt8qElNvQRbn7a6U+oxy+hNH8Dx+rn0R -OhPs7fpvcmR7nX1/Jv16+yWt6j4pf0zjAFcysLPp7VMX2YuyFA4w6OXVE8Zkr8QA1dhYJPz1j+zx -x32l2w8n0cbyQIjmH/ZhqPRCyLk306m+LFZ4wnKbWV01QIroTmMatukgalHizqSQ33ZwmVxwQ023 -tqcZZE6St8WRPH9IFmV7Fv3L/PvZ1dZPIWU7Sn9Ho/s= ------END CERTIFICATE----- - Swisscom Root CA 1 ================== -----BEGIN CERTIFICATE----- @@ -1886,37 +1555,6 @@ hGIAF728JRhX8tepb1mIvDS3LoV4nZbcFMMsilKbloxSZj2GFotHuFEJjOp9zYhys2AzsfAKRO8P UrbnBEI= -----END CERTIFICATE----- -SwissSign Platinum CA - G2 -========================== ------BEGIN CERTIFICATE----- -MIIFwTCCA6mgAwIBAgIITrIAZwwDXU8wDQYJKoZIhvcNAQEFBQAwSTELMAkGA1UEBhMCQ0gxFTAT -BgNVBAoTDFN3aXNzU2lnbiBBRzEjMCEGA1UEAxMaU3dpc3NTaWduIFBsYXRpbnVtIENBIC0gRzIw -HhcNMDYxMDI1MDgzNjAwWhcNMzYxMDI1MDgzNjAwWjBJMQswCQYDVQQGEwJDSDEVMBMGA1UEChMM -U3dpc3NTaWduIEFHMSMwIQYDVQQDExpTd2lzc1NpZ24gUGxhdGludW0gQ0EgLSBHMjCCAiIwDQYJ -KoZIhvcNAQEBBQADggIPADCCAgoCggIBAMrfogLi2vj8Bxax3mCq3pZcZB/HL37PZ/pEQtZ2Y5Wu -669yIIpFR4ZieIbWIDkm9K6j/SPnpZy1IiEZtzeTIsBQnIJ71NUERFzLtMKfkr4k2HtnIuJpX+UF -eNSH2XFwMyVTtIc7KZAoNppVRDBopIOXfw0enHb/FZ1glwCNioUD7IC+6ixuEFGSzH7VozPY1kne -WCqv9hbrS3uQMpe5up1Y8fhXSQQeol0GcN1x2/ndi5objM89o03Oy3z2u5yg+gnOI2Ky6Q0f4nIo -j5+saCB9bzuohTEJfwvH6GXp43gOCWcwizSC+13gzJ2BbWLuCB4ELE6b7P6pT1/9aXjvCR+htL/6 -8++QHkwFix7qepF6w9fl+zC8bBsQWJj3Gl/QKTIDE0ZNYWqFTFJ0LwYfexHihJfGmfNtf9dng34T -aNhxKFrYzt3oEBSa/m0jh26OWnA81Y0JAKeqvLAxN23IhBQeW71FYyBrS3SMvds6DsHPWhaPpZjy -domyExI7C3d3rLvlPClKknLKYRorXkzig3R3+jVIeoVNjZpTxN94ypeRSCtFKwH3HBqi7Ri6Cr2D -+m+8jVeTO9TUps4e8aCxzqv9KyiaTxvXw3LbpMS/XUz13XuWae5ogObnmLo2t/5u7Su9IPhlGdpV -CX4l3P5hYnL5fhgC72O00Puv5TtjjGePAgMBAAGjgawwgakwDgYDVR0PAQH/BAQDAgEGMA8GA1Ud -EwEB/wQFMAMBAf8wHQYDVR0OBBYEFFCvzAeHFUdvOMW0ZdHelarp35zMMB8GA1UdIwQYMBaAFFCv -zAeHFUdvOMW0ZdHelarp35zMMEYGA1UdIAQ/MD0wOwYJYIV0AVkBAQEBMC4wLAYIKwYBBQUHAgEW -IGh0dHA6Ly9yZXBvc2l0b3J5LnN3aXNzc2lnbi5jb20vMA0GCSqGSIb3DQEBBQUAA4ICAQAIhab1 -Fgz8RBrBY+D5VUYI/HAcQiiWjrfFwUF1TglxeeVtlspLpYhg0DB0uMoI3LQwnkAHFmtllXcBrqS3 -NQuB2nEVqXQXOHtYyvkv+8Bldo1bAbl93oI9ZLi+FHSjClTTLJUYFzX1UWs/j6KWYTl4a0vlpqD4 -U99REJNi54Av4tHgvI42Rncz7Lj7jposiU0xEQ8mngS7twSNC/K5/FqdOxa3L8iYq/6KUFkuozv8 -KV2LwUvJ4ooTHbG/u0IdUt1O2BReEMYxB+9xJ/cbOQncguqLs5WGXv312l0xpuAxtpTmREl0xRbl -9x8DYSjFyMsSoEJL+WuICI20MhjzdZ/EfwBPBZWcoxcCw7NTm6ogOSkrZvqdr16zktK1puEa+S1B -aYEUtLS17Yk9zvupnTVCRLEcFHOBzyoBNZox1S2PbYTfgE1X4z/FhHXaicYwu+uPyyIIoK6q8QNs -OktNCaUOcsZWayFCTiMlFGiudgp8DAdwZPmaL/YFOSbGDI8Zf0NebvRbFS/bYV3mZy8/CJT5YLSY -Mdp08YSTcU1f+2BY0fvEwW2JorsgH51xkcsymxM9Pn2SUjWskpSi0xjCfMfqr3YFFt1nJ8J+HAci -IfNAChs0B0QTwoRqjt8ZWr9/6x3iGjjRXK9HkmuAtTClyY3YqzGBH9/CZjfTk6mFhnll0g== ------END CERTIFICATE----- - SwissSign Gold CA - G2 ====================== -----BEGIN CERTIFICATE----- @@ -2254,32 +1892,6 @@ hNVQA7bihKOmNqoROgHhGEvWRGizPflTdISzRpFGlgC3gCy24eMQ4tui5yiPAZZiFj4A4xylNoEY okxSdsARo27mHbrjWr42U8U+dY+GaSlYU7Wcu2+fXMUY7N0v4ZjJ/L7fCg0= -----END CERTIFICATE----- -S-TRUST Authentication and Encryption Root CA 2005 PN -===================================================== ------BEGIN CERTIFICATE----- -MIIEezCCA2OgAwIBAgIQNxkY5lNUfBq1uMtZWts1tzANBgkqhkiG9w0BAQUFADCBrjELMAkGA1UE -BhMCREUxIDAeBgNVBAgTF0JhZGVuLVd1ZXJ0dGVtYmVyZyAoQlcpMRIwEAYDVQQHEwlTdHV0dGdh -cnQxKTAnBgNVBAoTIERldXRzY2hlciBTcGFya2Fzc2VuIFZlcmxhZyBHbWJIMT4wPAYDVQQDEzVT -LVRSVVNUIEF1dGhlbnRpY2F0aW9uIGFuZCBFbmNyeXB0aW9uIFJvb3QgQ0EgMjAwNTpQTjAeFw0w -NTA2MjIwMDAwMDBaFw0zMDA2MjEyMzU5NTlaMIGuMQswCQYDVQQGEwJERTEgMB4GA1UECBMXQmFk -ZW4tV3VlcnR0ZW1iZXJnIChCVykxEjAQBgNVBAcTCVN0dXR0Z2FydDEpMCcGA1UEChMgRGV1dHNj -aGVyIFNwYXJrYXNzZW4gVmVybGFnIEdtYkgxPjA8BgNVBAMTNVMtVFJVU1QgQXV0aGVudGljYXRp -b24gYW5kIEVuY3J5cHRpb24gUm9vdCBDQSAyMDA1OlBOMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8A -MIIBCgKCAQEA2bVKwdMz6tNGs9HiTNL1toPQb9UY6ZOvJ44TzbUlNlA0EmQpoVXhOmCTnijJ4/Ob -4QSwI7+Vio5bG0F/WsPoTUzVJBY+h0jUJ67m91MduwwA7z5hca2/OnpYH5Q9XIHV1W/fuJvS9eXL -g3KSwlOyggLrra1fFi2SU3bxibYs9cEv4KdKb6AwajLrmnQDaHgTncovmwsdvs91DSaXm8f1Xgqf -eN+zvOyauu9VjxuapgdjKRdZYgkqeQd3peDRF2npW932kKvimAoA0SVtnteFhy+S8dF2g08LOlk3 -KC8zpxdQ1iALCvQm+Z845y2kuJuJja2tyWp9iRe79n+Ag3rm7QIDAQABo4GSMIGPMBIGA1UdEwEB -/wQIMAYBAf8CAQAwDgYDVR0PAQH/BAQDAgEGMCkGA1UdEQQiMCCkHjAcMRowGAYDVQQDExFTVFJv -bmxpbmUxLTIwNDgtNTAdBgNVHQ4EFgQUD8oeXHngovMpttKFswtKtWXsa1IwHwYDVR0jBBgwFoAU -D8oeXHngovMpttKFswtKtWXsa1IwDQYJKoZIhvcNAQEFBQADggEBAK8B8O0ZPCjoTVy7pWMciDMD -pwCHpB8gq9Yc4wYfl35UvbfRssnV2oDsF9eK9XvCAPbpEW+EoFolMeKJ+aQAPzFoLtU96G7m1R08 -P7K9n3frndOMusDXtk3sU5wPBG7qNWdX4wple5A64U8+wwCSersFiXOMy6ZNwPv2AtawB6MDwidA -nwzkhYItr5pCHdDHjfhA7p0GVxzZotiAFP7hYy0yh9WUUpY6RsZxlj33mA6ykaqP2vROJAA5Veit -F7nTNCtKqUDMFypVZUF0Qn71wK/Ik63yGFs9iQzbRzkk+OBM8h+wPQrKBU6JIRrjKpms/H+h8Q8b -Hz2eBIPdltkdOpQ= ------END CERTIFICATE----- - Microsec e-Szigno Root CA ========================= -----BEGIN CERTIFICATE----- @@ -2475,28 +2087,6 @@ dyd1Lx+4ivn+xbrYNuSD7Odlt79jWvNGr4GUN9RBjNYj1h7P9WgbRGOiWrqnNVmh5XAFmw4jV5mU Cm26OWMohpLzGITY+9HPBVZkVw== -----END CERTIFICATE----- -ComSign CA -========== ------BEGIN CERTIFICATE----- -MIIDkzCCAnugAwIBAgIQFBOWgxRVjOp7Y+X8NId3RDANBgkqhkiG9w0BAQUFADA0MRMwEQYDVQQD -EwpDb21TaWduIENBMRAwDgYDVQQKEwdDb21TaWduMQswCQYDVQQGEwJJTDAeFw0wNDAzMjQxMTMy -MThaFw0yOTAzMTkxNTAyMThaMDQxEzARBgNVBAMTCkNvbVNpZ24gQ0ExEDAOBgNVBAoTB0NvbVNp -Z24xCzAJBgNVBAYTAklMMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA8ORUaSvTx49q -ROR+WCf4C9DklBKK8Rs4OC8fMZwG1Cyn3gsqrhqg455qv588x26i+YtkbDqthVVRVKU4VbirgwTy -P2Q298CNQ0NqZtH3FyrV7zb6MBBC11PN+fozc0yz6YQgitZBJzXkOPqUm7h65HkfM/sb2CEJKHxN -GGleZIp6GZPKfuzzcuc3B1hZKKxC+cX/zT/npfo4sdAMx9lSGlPWgcxCejVb7Us6eva1jsz/D3zk -YDaHL63woSV9/9JLEYhwVKZBqGdTUkJe5DSe5L6j7KpiXd3DTKaCQeQzC6zJMw9kglcq/QytNuEM -rkvF7zuZ2SOzW120V+x0cAwqTwIDAQABo4GgMIGdMAwGA1UdEwQFMAMBAf8wPQYDVR0fBDYwNDAy -oDCgLoYsaHR0cDovL2ZlZGlyLmNvbXNpZ24uY28uaWwvY3JsL0NvbVNpZ25DQS5jcmwwDgYDVR0P -AQH/BAQDAgGGMB8GA1UdIwQYMBaAFEsBmz5WGmU2dst7l6qSBe4y5ygxMB0GA1UdDgQWBBRLAZs+ -VhplNnbLe5eqkgXuMucoMTANBgkqhkiG9w0BAQUFAAOCAQEA0Nmlfv4pYEWdfoPPbrxHbvUanlR2 -QnG0PFg/LUAlQvaBnPGJEMgOqnhPOAlXsDzACPw1jvFIUY0McXS6hMTXcpuEfDhOZAYnKuGntewI -mbQKDdSFc8gS4TXt8QUxHXOZDOuWyt3T5oWq8Ir7dcHyCTxlZWTzTNity4hp8+SDtwy9F1qWF8pb -/627HOkthIDYIb6FUtnUdLlphbpN7Sgy6/lhSuTENh4Z3G+EER+V9YMoGKgzkkMn3V0TBEVPh9VG -zT2ouvDzuFYkRes3x+F2T3I5GN9+dHLHcy056mDmrRGiVod7w2ia/viMcKjfZTL0pECMocJEAw6U -AGegcQCCSA== ------END CERTIFICATE----- - ComSign Secured CA ================== -----BEGIN CERTIFICATE----- @@ -3045,22 +2635,6 @@ MCwXEGCSn1WHElkQwg9naRHMTh5+Spqtr0CodaxWkHS4oJyleW/c6RrIaQXpuvoDs3zk4E7Czp3o tkYNbn5XOmeUwssfnHdKZ05phkOTOPu220+DkdRgfks+KzgHVZhepA== -----END CERTIFICATE----- -Verisign Class 1 Public Primary Certification Authority -======================================================= ------BEGIN CERTIFICATE----- -MIICPDCCAaUCED9pHoGc8JpK83P/uUii5N0wDQYJKoZIhvcNAQEFBQAwXzELMAkGA1UEBhMCVVMx -FzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAxIFB1YmxpYyBQcmltYXJ5 -IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MB4XDTk2MDEyOTAwMDAwMFoXDTI4MDgwMjIzNTk1OVow -XzELMAkGA1UEBhMCVVMxFzAVBgNVBAoTDlZlcmlTaWduLCBJbmMuMTcwNQYDVQQLEy5DbGFzcyAx -IFB1YmxpYyBQcmltYXJ5IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIGfMA0GCSqGSIb3DQEBAQUA -A4GNADCBiQKBgQDlGb9to1ZhLZlIcfZn3rmN67eehoAKkQ76OCWvRoiC5XOooJskXQ0fzGVuDLDQ -VoQYh5oGmxChc9+0WDlrbsH2FdWoqD+qEgaNMax/sDTXjzRniAnNFBHiTkVWaR94AoDa3EeRKbs2 -yWNcxeDXLYd7obcysHswuiovMaruo2fa2wIDAQABMA0GCSqGSIb3DQEBBQUAA4GBAFgVKTk8d6Pa -XCUDfGD67gmZPCcQcMgMCeazh88K4hiWNWLMv5sneYlfycQJ9M61Hd8qveXbhpxoJeUwfLaJFf5n -0a3hUKw8fGJLj7qE1xIVGx/KXQ/BUpQqEZnae88MNhPVNdwQGVnqlMEAv3WP2fr9dgTbYruQagPZ -RjXZ+Hxb ------END CERTIFICATE----- - Verisign Class 3 Public Primary Certification Authority ======================================================= -----BEGIN CERTIFICATE----- @@ -3144,29 +2718,6 @@ YIvDQVETI53O9zJrlAGomecsMx86OyXShkDOOyyGeMlhLxS67ttVb9+E7gUJTb0o2HLO02JQZR7r kpeDMdmztcpHWD9f -----END CERTIFICATE----- -TC TrustCenter Universal CA III -=============================== ------BEGIN CERTIFICATE----- -MIID4TCCAsmgAwIBAgIOYyUAAQACFI0zFQLkbPQwDQYJKoZIhvcNAQEFBQAwezELMAkGA1UEBhMC -REUxHDAaBgNVBAoTE1RDIFRydXN0Q2VudGVyIEdtYkgxJDAiBgNVBAsTG1RDIFRydXN0Q2VudGVy -IFVuaXZlcnNhbCBDQTEoMCYGA1UEAxMfVEMgVHJ1c3RDZW50ZXIgVW5pdmVyc2FsIENBIElJSTAe -Fw0wOTA5MDkwODE1MjdaFw0yOTEyMzEyMzU5NTlaMHsxCzAJBgNVBAYTAkRFMRwwGgYDVQQKExNU -QyBUcnVzdENlbnRlciBHbWJIMSQwIgYDVQQLExtUQyBUcnVzdENlbnRlciBVbml2ZXJzYWwgQ0Ex -KDAmBgNVBAMTH1RDIFRydXN0Q2VudGVyIFVuaXZlcnNhbCBDQSBJSUkwggEiMA0GCSqGSIb3DQEB -AQUAA4IBDwAwggEKAoIBAQDC2pxisLlxErALyBpXsq6DFJmzNEubkKLF5+cvAqBNLaT6hdqbJYUt -QCggbergvbFIgyIpRJ9Og+41URNzdNW88jBmlFPAQDYvDIRlzg9uwliT6CwLOunBjvvya8o84pxO -juT5fdMnnxvVZ3iHLX8LR7PH6MlIfK8vzArZQe+f/prhsq75U7Xl6UafYOPfjdN/+5Z+s7Vy+Eut -CHnNaYlAJ/Uqwa1D7KRTyGG299J5KmcYdkhtWyUB0SbFt1dpIxVbYYqt8Bst2a9c8SaQaanVDED1 -M4BDj5yjdipFtK+/fz6HP3bFzSreIMUWWMv5G/UPyw0RUmS40nZid4PxWJ//AgMBAAGjYzBhMB8G -A1UdIwQYMBaAFFbn4VslQ4Dg9ozhcbyO5YAvxEjiMA8GA1UdEwEB/wQFMAMBAf8wDgYDVR0PAQH/ -BAQDAgEGMB0GA1UdDgQWBBRW5+FbJUOA4PaM4XG8juWAL8RI4jANBgkqhkiG9w0BAQUFAAOCAQEA -g8ev6n9NCjw5sWi+e22JLumzCecYV42FmhfzdkJQEw/HkG8zrcVJYCtsSVgZ1OK+t7+rSbyUyKu+ -KGwWaODIl0YgoGhnYIg5IFHYaAERzqf2EQf27OysGh+yZm5WZ2B6dF7AbZc2rrUNXWZzwCUyRdhK -BgePxLcHsU0GDeGl6/R1yrqc0L2z0zIkTO5+4nYES0lT2PLpVDP85XEfPRRclkvxOvIAu2y0+pZV -CIgJwcyRGSmwIC3/yzikQOEXvnlhgP8HA4ZMTnsGnxGGjYnuJ8Tb4rwZjgvDwxPHLQNjO9Po5KIq -woIIlBZU8O8fJ5AluA0OKBtHd0e9HKgl8ZS0Zg== ------END CERTIFICATE----- - Autoridad de Certificacion Firmaprofesional CIF A62634068 ========================================================= -----BEGIN CERTIFICATE----- @@ -3893,3 +3444,342 @@ uSlNDUmJEYcyW+ZLBMjkXOZ0c5RdFpgTlf7727FE5TpwrDdr5rMzcijJs1eg9gIWiAYLtqZLICjU 3j2LrTcFU3T+bsy8QxdxXvnFzBqpYe73dgzzcvRyrc9yAjYHR8/vGVCJYMzpJJUPwssd8m92kMfM dcGWxZ0= -----END CERTIFICATE----- + +TURKTRUST Certificate Services Provider Root 2007 +================================================= +-----BEGIN CERTIFICATE----- +MIIEPTCCAyWgAwIBAgIBATANBgkqhkiG9w0BAQUFADCBvzE/MD0GA1UEAww2VMOcUktUUlVTVCBF +bGVrdHJvbmlrIFNlcnRpZmlrYSBIaXptZXQgU2HEn2xhecSxY8Sxc8SxMQswCQYDVQQGEwJUUjEP +MA0GA1UEBwwGQW5rYXJhMV4wXAYDVQQKDFVUw5xSS1RSVVNUIEJpbGdpIMSwbGV0acWfaW0gdmUg +QmlsacWfaW0gR8O8dmVubGnEn2kgSGl6bWV0bGVyaSBBLsWeLiAoYykgQXJhbMSxayAyMDA3MB4X +DTA3MTIyNTE4MzcxOVoXDTE3MTIyMjE4MzcxOVowgb8xPzA9BgNVBAMMNlTDnFJLVFJVU1QgRWxl +a3Ryb25payBTZXJ0aWZpa2EgSGl6bWV0IFNhxJ9sYXnEsWPEsXPEsTELMAkGA1UEBhMCVFIxDzAN +BgNVBAcMBkFua2FyYTFeMFwGA1UECgxVVMOcUktUUlVTVCBCaWxnaSDEsGxldGnFn2ltIHZlIEJp +bGnFn2ltIEfDvHZlbmxpxJ9pIEhpem1ldGxlcmkgQS7Fni4gKGMpIEFyYWzEsWsgMjAwNzCCASIw +DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKu3PgqMyKVYFeaK7yc9SrToJdPNM8Ig3BnuiD9N +YvDdE3ePYakqtdTyuTFYKTsvP2qcb3N2Je40IIDu6rfwxArNK4aUyeNgsURSsloptJGXg9i3phQv +KUmi8wUG+7RP2qFsmmaf8EMJyupyj+sA1zU511YXRxcw9L6/P8JorzZAwan0qafoEGsIiveGHtya +KhUG9qPw9ODHFNRRf8+0222vR5YXm3dx2KdxnSQM9pQ/hTEST7ruToK4uT6PIzdezKKqdfcYbwnT +rqdUKDT74eA7YH2gvnmJhsifLfkKS8RQouf9eRbHegsYz85M733WB2+Y8a+xwXrXgTW4qhe04MsC +AwEAAaNCMEAwHQYDVR0OBBYEFCnFkKslrxHkYb+j/4hhkeYO/pyBMA4GA1UdDwEB/wQEAwIBBjAP +BgNVHRMBAf8EBTADAQH/MA0GCSqGSIb3DQEBBQUAA4IBAQAQDdr4Ouwo0RSVgrESLFF6QSU2TJ/s +Px+EnWVUXKgWAkD6bho3hO9ynYYKVZ1WKKxmLNA6VpM0ByWtCLCPyA8JWcqdmBzlVPi5RX9ql2+I +aE1KBiY3iAIOtsbWcpnOa3faYjGkVh+uX4132l32iPwa2Z61gfAyuOOI0JzzaqC5mxRZNTZPz/OO +Xl0XrRWV2N2y1RVuAE6zS89mlOTgzbUF2mNXi+WzqtvALhyQRNsaXRik7r4EW5nVcV9VZWRi1aKb +BFmGyGJ353yCRWo9F7/snXUMrqNvWtMvmDb08PUZqxFdyKbjKlhqQgnDvZImZjINXQhVdP+MmNAK +poRq0Tl9 +-----END CERTIFICATE----- + +D-TRUST Root Class 3 CA 2 2009 +============================== +-----BEGIN CERTIFICATE----- +MIIEMzCCAxugAwIBAgIDCYPzMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQK +DAxELVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTAe +Fw0wOTExMDUwODM1NThaFw0yOTExMDUwODM1NThaME0xCzAJBgNVBAYTAkRFMRUwEwYDVQQKDAxE +LVRydXN0IEdtYkgxJzAlBgNVBAMMHkQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgMjAwOTCCASIw +DQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANOySs96R+91myP6Oi/WUEWJNTrGa9v+2wBoqOAD +ER03UAifTUpolDWzU9GUY6cgVq/eUXjsKj3zSEhQPgrfRlWLJ23DEE0NkVJD2IfgXU42tSHKXzlA +BF9bfsyjxiupQB7ZNoTWSPOSHjRGICTBpFGOShrvUD9pXRl/RcPHAY9RySPocq60vFYJfxLLHLGv +KZAKyVXMD9O0Gu1HNVpK7ZxzBCHQqr0ME7UAyiZsxGsMlFqVlNpQmvH/pStmMaTJOKDfHR+4CS7z +p+hnUquVH+BGPtikw8paxTGA6Eian5Rp/hnd2HN8gcqW3o7tszIFZYQ05ub9VxC1X3a/L7AQDcUC +AwEAAaOCARowggEWMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFP3aFMSfMN4hvR5COfyrYyNJ +4PGEMA4GA1UdDwEB/wQEAwIBBjCB0wYDVR0fBIHLMIHIMIGAoH6gfIZ6bGRhcDovL2RpcmVjdG9y +eS5kLXRydXN0Lm5ldC9DTj1ELVRSVVNUJTIwUm9vdCUyMENsYXNzJTIwMyUyMENBJTIwMiUyMDIw +MDksTz1ELVRydXN0JTIwR21iSCxDPURFP2NlcnRpZmljYXRlcmV2b2NhdGlvbmxpc3QwQ6BBoD+G +PWh0dHA6Ly93d3cuZC10cnVzdC5uZXQvY3JsL2QtdHJ1c3Rfcm9vdF9jbGFzc18zX2NhXzJfMjAw +OS5jcmwwDQYJKoZIhvcNAQELBQADggEBAH+X2zDI36ScfSF6gHDOFBJpiBSVYEQBrLLpME+bUMJm +2H6NMLVwMeniacfzcNsgFYbQDfC+rAF1hM5+n02/t2A7nPPKHeJeaNijnZflQGDSNiH+0LS4F9p0 +o3/U37CYAqxva2ssJSRyoWXuJVrl5jLn8t+rSfrzkGkj2wTZ51xY/GXUl77M/C4KzCUqNQT4YJEV +dT1B/yMfGchs64JTBKbkTCJNjYy6zltz7GRUUG3RnFX7acM2w4y8PIWmawomDeCTmGCufsYkl4ph +X5GOZpIJhzbNi5stPvZR1FDUWSi9g/LMKHtThm3YJohw1+qRzT65ysCQblrGXnRl11z+o+I= +-----END CERTIFICATE----- + +D-TRUST Root Class 3 CA 2 EV 2009 +================================= +-----BEGIN CERTIFICATE----- +MIIEQzCCAyugAwIBAgIDCYP0MA0GCSqGSIb3DQEBCwUAMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQK +DAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAw +OTAeFw0wOTExMDUwODUwNDZaFw0yOTExMDUwODUwNDZaMFAxCzAJBgNVBAYTAkRFMRUwEwYDVQQK +DAxELVRydXN0IEdtYkgxKjAoBgNVBAMMIUQtVFJVU1QgUm9vdCBDbGFzcyAzIENBIDIgRVYgMjAw +OTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJnxhDRwui+3MKCOvXwEz75ivJn9gpfS +egpnljgJ9hBOlSJzmY3aFS3nBfwZcyK3jpgAvDw9rKFs+9Z5JUut8Mxk2og+KbgPCdM03TP1YtHh +zRnp7hhPTFiu4h7WDFsVWtg6uMQYZB7jM7K1iXdODL/ZlGsTl28So/6ZqQTMFexgaDbtCHu39b+T +7WYxg4zGcTSHThfqr4uRjRxWQa4iN1438h3Z0S0NL2lRp75mpoo6Kr3HGrHhFPC+Oh25z1uxav60 +sUYgovseO3Dvk5h9jHOW8sXvhXCtKSb8HgQ+HKDYD8tSg2J87otTlZCpV6LqYQXY+U3EJ/pure35 +11H3a6UCAwEAAaOCASQwggEgMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFNOUikxiEyoZLsyv +cop9NteaHNxnMA4GA1UdDwEB/wQEAwIBBjCB3QYDVR0fBIHVMIHSMIGHoIGEoIGBhn9sZGFwOi8v +ZGlyZWN0b3J5LmQtdHJ1c3QubmV0L0NOPUQtVFJVU1QlMjBSb290JTIwQ2xhc3MlMjAzJTIwQ0El +MjAyJTIwRVYlMjAyMDA5LE89RC1UcnVzdCUyMEdtYkgsQz1ERT9jZXJ0aWZpY2F0ZXJldm9jYXRp +b25saXN0MEagRKBChkBodHRwOi8vd3d3LmQtdHJ1c3QubmV0L2NybC9kLXRydXN0X3Jvb3RfY2xh +c3NfM19jYV8yX2V2XzIwMDkuY3JsMA0GCSqGSIb3DQEBCwUAA4IBAQA07XtaPKSUiO8aEXUHL7P+ +PPoeUSbrh/Yp3uDx1MYkCenBz1UbtDDZzhr+BlGmFaQt77JLvyAoJUnRpjZ3NOhk31KxEcdzes05 +nsKtjHEh8lprr988TlWvsoRlFIm5d8sqMb7Po23Pb0iUMkZv53GMoKaEGTcH8gNFCSuGdXzfX2lX +ANtu2KZyIktQ1HWYVt+3GP9DQ1CuekR78HlR10M9p9OB0/DJT7naxpeG0ILD5EJt/rDiZE4OJudA +NCa1CInXCGNjOCd1HjPqbqjdn5lPdE2BiYBL3ZqXKVwvvoFBuYz/6n1gBp7N1z3TLqMVvKjmJuVv +w9y4AyHqnxbxLFS1 +-----END CERTIFICATE----- + +PSCProcert +========== +-----BEGIN CERTIFICATE----- +MIIJhjCCB26gAwIBAgIBCzANBgkqhkiG9w0BAQsFADCCAR4xPjA8BgNVBAMTNUF1dG9yaWRhZCBk +ZSBDZXJ0aWZpY2FjaW9uIFJhaXogZGVsIEVzdGFkbyBWZW5lem9sYW5vMQswCQYDVQQGEwJWRTEQ +MA4GA1UEBxMHQ2FyYWNhczEZMBcGA1UECBMQRGlzdHJpdG8gQ2FwaXRhbDE2MDQGA1UEChMtU2lz +dGVtYSBOYWNpb25hbCBkZSBDZXJ0aWZpY2FjaW9uIEVsZWN0cm9uaWNhMUMwQQYDVQQLEzpTdXBl +cmludGVuZGVuY2lhIGRlIFNlcnZpY2lvcyBkZSBDZXJ0aWZpY2FjaW9uIEVsZWN0cm9uaWNhMSUw +IwYJKoZIhvcNAQkBFhZhY3JhaXpAc3VzY2VydGUuZ29iLnZlMB4XDTEwMTIyODE2NTEwMFoXDTIw +MTIyNTIzNTk1OVowgdExJjAkBgkqhkiG9w0BCQEWF2NvbnRhY3RvQHByb2NlcnQubmV0LnZlMQ8w +DQYDVQQHEwZDaGFjYW8xEDAOBgNVBAgTB01pcmFuZGExKjAoBgNVBAsTIVByb3ZlZWRvciBkZSBD +ZXJ0aWZpY2Fkb3MgUFJPQ0VSVDE2MDQGA1UEChMtU2lzdGVtYSBOYWNpb25hbCBkZSBDZXJ0aWZp +Y2FjaW9uIEVsZWN0cm9uaWNhMQswCQYDVQQGEwJWRTETMBEGA1UEAxMKUFNDUHJvY2VydDCCAiIw +DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBANW39KOUM6FGqVVhSQ2oh3NekS1wwQYalNo97BVC +wfWMrmoX8Yqt/ICV6oNEolt6Vc5Pp6XVurgfoCfAUFM+jbnADrgV3NZs+J74BCXfgI8Qhd19L3uA +3VcAZCP4bsm+lU/hdezgfl6VzbHvvnpC2Mks0+saGiKLt38GieU89RLAu9MLmV+QfI4tL3czkkoh +RqipCKzx9hEC2ZUWno0vluYC3XXCFCpa1sl9JcLB/KpnheLsvtF8PPqv1W7/U0HU9TI4seJfxPmO +EO8GqQKJ/+MMbpfg353bIdD0PghpbNjU5Db4g7ayNo+c7zo3Fn2/omnXO1ty0K+qP1xmk6wKImG2 +0qCZyFSTXai20b1dCl53lKItwIKOvMoDKjSuc/HUtQy9vmebVOvh+qBa7Dh+PsHMosdEMXXqP+UH +0quhJZb25uSgXTcYOWEAM11G1ADEtMo88aKjPvM6/2kwLkDd9p+cJsmWN63nOaK/6mnbVSKVUyqU +td+tFjiBdWbjxywbk5yqjKPK2Ww8F22c3HxT4CAnQzb5EuE8XL1mv6JpIzi4mWCZDlZTOpx+FIyw +Bm/xhnaQr/2v/pDGj59/i5IjnOcVdo/Vi5QTcmn7K2FjiO/mpF7moxdqWEfLcU8UC17IAggmosvp +r2uKGcfLFFb14dq12fy/czja+eevbqQ34gcnAgMBAAGjggMXMIIDEzASBgNVHRMBAf8ECDAGAQH/ +AgEBMDcGA1UdEgQwMC6CD3N1c2NlcnRlLmdvYi52ZaAbBgVghl4CAqASDBBSSUYtRy0yMDAwNDAz +Ni0wMB0GA1UdDgQWBBRBDxk4qpl/Qguk1yeYVKIXTC1RVDCCAVAGA1UdIwSCAUcwggFDgBStuyId +xuDSAaj9dlBSk+2YwU2u06GCASakggEiMIIBHjE+MDwGA1UEAxM1QXV0b3JpZGFkIGRlIENlcnRp +ZmljYWNpb24gUmFpeiBkZWwgRXN0YWRvIFZlbmV6b2xhbm8xCzAJBgNVBAYTAlZFMRAwDgYDVQQH +EwdDYXJhY2FzMRkwFwYDVQQIExBEaXN0cml0byBDYXBpdGFsMTYwNAYDVQQKEy1TaXN0ZW1hIE5h +Y2lvbmFsIGRlIENlcnRpZmljYWNpb24gRWxlY3Ryb25pY2ExQzBBBgNVBAsTOlN1cGVyaW50ZW5k +ZW5jaWEgZGUgU2VydmljaW9zIGRlIENlcnRpZmljYWNpb24gRWxlY3Ryb25pY2ExJTAjBgkqhkiG +9w0BCQEWFmFjcmFpekBzdXNjZXJ0ZS5nb2IudmWCAQowDgYDVR0PAQH/BAQDAgEGME0GA1UdEQRG +MESCDnByb2NlcnQubmV0LnZloBUGBWCGXgIBoAwMClBTQy0wMDAwMDKgGwYFYIZeAgKgEgwQUklG +LUotMzE2MzUzNzMtNzB2BgNVHR8EbzBtMEagRKBChkBodHRwOi8vd3d3LnN1c2NlcnRlLmdvYi52 +ZS9sY3IvQ0VSVElGSUNBRE8tUkFJWi1TSEEzODRDUkxERVIuY3JsMCOgIaAfhh1sZGFwOi8vYWNy +YWl6LnN1c2NlcnRlLmdvYi52ZTA3BggrBgEFBQcBAQQrMCkwJwYIKwYBBQUHMAGGG2h0dHA6Ly9v +Y3NwLnN1c2NlcnRlLmdvYi52ZTBBBgNVHSAEOjA4MDYGBmCGXgMBAjAsMCoGCCsGAQUFBwIBFh5o +dHRwOi8vd3d3LnN1c2NlcnRlLmdvYi52ZS9kcGMwDQYJKoZIhvcNAQELBQADggIBACtZ6yKZu4Sq +T96QxtGGcSOeSwORR3C7wJJg7ODU523G0+1ng3dS1fLld6c2suNUvtm7CpsR72H0xpkzmfWvADmN +g7+mvTV+LFwxNG9s2/NkAZiqlCxB3RWGymspThbASfzXg0gTB1GEMVKIu4YXx2sviiCtxQuPcD4q +uxtxj7mkoP3YldmvWb8lK5jpY5MvYB7Eqvh39YtsL+1+LrVPQA3uvFd359m21D+VJzog1eWuq2w1 +n8GhHVnchIHuTQfiSLaeS5UtQbHh6N5+LwUeaO6/u5BlOsju6rEYNxxik6SgMexxbJHmpHmJWhSn +FFAFTKQAVzAswbVhltw+HoSvOULP5dAssSS830DD7X9jSr3hTxJkhpXzsOfIt+FTvZLm8wyWuevo +5pLtp4EJFAv8lXrPj9Y0TzYS3F7RNHXGRoAvlQSMx4bEqCaJqD8Zm4G7UaRKhqsLEQ+xrmNTbSjq +3TNWOByyrYDT13K9mmyZY+gAu0F2BbdbmRiKw7gSXFbPVgx96OLP7bx0R/vu0xdOIk9W/1DzLuY5 +poLWccret9W6aAjtmcz9opLLabid+Qqkpj5PkygqYWwHJgD/ll9ohri4zspV4KuxPX+Y1zMOWj3Y +eMLEYC/HYvBhkdI4sPaeVdtAgAUSM84dkpvRabP/v/GSCmE1P93+hvS84Bpxs2Km +-----END CERTIFICATE----- + +China Internet Network Information Center EV Certificates Root +============================================================== +-----BEGIN CERTIFICATE----- +MIID9zCCAt+gAwIBAgIESJ8AATANBgkqhkiG9w0BAQUFADCBijELMAkGA1UEBhMCQ04xMjAwBgNV +BAoMKUNoaW5hIEludGVybmV0IE5ldHdvcmsgSW5mb3JtYXRpb24gQ2VudGVyMUcwRQYDVQQDDD5D +aGluYSBJbnRlcm5ldCBOZXR3b3JrIEluZm9ybWF0aW9uIENlbnRlciBFViBDZXJ0aWZpY2F0ZXMg +Um9vdDAeFw0xMDA4MzEwNzExMjVaFw0zMDA4MzEwNzExMjVaMIGKMQswCQYDVQQGEwJDTjEyMDAG +A1UECgwpQ2hpbmEgSW50ZXJuZXQgTmV0d29yayBJbmZvcm1hdGlvbiBDZW50ZXIxRzBFBgNVBAMM +PkNoaW5hIEludGVybmV0IE5ldHdvcmsgSW5mb3JtYXRpb24gQ2VudGVyIEVWIENlcnRpZmljYXRl +cyBSb290MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAm35z7r07eKpkQ0H1UN+U8i6y +jUqORlTSIRLIOTJCBumD1Z9S7eVnAztUwYyZmczpwA//DdmEEbK40ctb3B75aDFk4Zv6dOtouSCV +98YPjUesWgbdYavi7NifFy2cyjw1l1VxzUOFsUcW9SxTgHbP0wBkvUCZ3czY28Sf1hNfQYOL+Q2H +klY0bBoQCxfVWhyXWIQ8hBouXJE0bhlffxdpxWXvayHG1VA6v2G5BY3vbzQ6sm8UY78WO5upKv23 +KzhmBsUs4qpnHkWnjQRmQvaPK++IIGmPMowUc9orhpFjIpryp9vOiYurXccUwVswah+xt54ugQEC +7c+WXmPbqOY4twIDAQABo2MwYTAfBgNVHSMEGDAWgBR8cks5x8DbYqVPm6oYNJKiyoOCWTAPBgNV +HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUfHJLOcfA22KlT5uqGDSSosqD +glkwDQYJKoZIhvcNAQEFBQADggEBACrDx0M3j92tpLIM7twUbY8opJhJywyA6vPtI2Z1fcXTIWd5 +0XPFtQO3WKwMVC/GVhMPMdoG52U7HW8228gd+f2ABsqjPWYWqJ1MFn3AlUa1UeTiH9fqBk1jjZaM +7+czV0I664zBechNdn3e9rG3geCg+aF4RhcaVpjwTj2rHO3sOdwHSPdj/gauwqRcalsyiMXHM4Ws +ZkJHwlgkmeHlPuV1LI5D1l08eB6olYIpUNHRFrrvwb562bTYzB5MRuF3sTGrvSrIzo9uoV1/A3U0 +5K2JRVRevq4opbs/eHnrc7MKDf2+yfdWrPa37S+bISnHOLaVxATywy39FCqQmbkHzJ8= +-----END CERTIFICATE----- + +Swisscom Root CA 2 +================== +-----BEGIN CERTIFICATE----- +MIIF2TCCA8GgAwIBAgIQHp4o6Ejy5e/DfEoeWhhntjANBgkqhkiG9w0BAQsFADBkMQswCQYDVQQG +EwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsTHERpZ2l0YWwgQ2VydGlmaWNhdGUgU2Vy +dmljZXMxGzAZBgNVBAMTElN3aXNzY29tIFJvb3QgQ0EgMjAeFw0xMTA2MjQwODM4MTRaFw0zMTA2 +MjUwNzM4MTRaMGQxCzAJBgNVBAYTAmNoMREwDwYDVQQKEwhTd2lzc2NvbTElMCMGA1UECxMcRGln +aXRhbCBDZXJ0aWZpY2F0ZSBTZXJ2aWNlczEbMBkGA1UEAxMSU3dpc3Njb20gUm9vdCBDQSAyMIIC +IjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAlUJOhJ1R5tMJ6HJaI2nbeHCOFvErjw0DzpPM +LgAIe6szjPTpQOYXTKueuEcUMncy3SgM3hhLX3af+Dk7/E6J2HzFZ++r0rk0X2s682Q2zsKwzxNo +ysjL67XiPS4h3+os1OD5cJZM/2pYmLcX5BtS5X4HAB1f2uY+lQS3aYg5oUFgJWFLlTloYhyxCwWJ +wDaCFCE/rtuh/bxvHGCGtlOUSbkrRsVPACu/obvLP+DHVxxX6NZp+MEkUp2IVd3Chy50I9AU/SpH +Wrumnf2U5NGKpV+GY3aFy6//SSj8gO1MedK75MDvAe5QQQg1I3ArqRa0jG6F6bYRzzHdUyYb3y1a +SgJA/MTAtukxGggo5WDDH8SQjhBiYEQN7Aq+VRhxLKX0srwVYv8c474d2h5Xszx+zYIdkeNL6yxS +NLCK/RJOlrDrcH+eOfdmQrGrrFLadkBXeyq96G4DsguAhYidDMfCd7Camlf0uPoTXGiTOmekl9Ab +mbeGMktg2M7v0Ax/lZ9vh0+Hio5fCHyqW/xavqGRn1V9TrALacywlKinh/LTSlDcX3KwFnUey7QY +Ypqwpzmqm59m2I2mbJYV4+by+PGDYmy7Velhk6M99bFXi08jsJvllGov34zflVEpYKELKeRcVVi3 +qPyZ7iVNTA6z00yPhOgpD/0QVAKFyPnlw4vP5w8CAwEAAaOBhjCBgzAOBgNVHQ8BAf8EBAMCAYYw +HQYDVR0hBBYwFDASBgdghXQBUwIBBgdghXQBUwIBMBIGA1UdEwEB/wQIMAYBAf8CAQcwHQYDVR0O +BBYEFE0mICKJS9PVpAqhb97iEoHF8TwuMB8GA1UdIwQYMBaAFE0mICKJS9PVpAqhb97iEoHF8Twu +MA0GCSqGSIb3DQEBCwUAA4ICAQAyCrKkG8t9voJXiblqf/P0wS4RfbgZPnm3qKhyN2abGu2sEzsO +v2LwnN+ee6FTSA5BesogpxcbtnjsQJHzQq0Qw1zv/2BZf82Fo4s9SBwlAjxnffUy6S8w5X2lejjQ +82YqZh6NM4OKb3xuqFp1mrjX2lhIREeoTPpMSQpKwhI3qEAMw8jh0FcNlzKVxzqfl9NX+Ave5XLz +o9v/tdhZsnPdTSpxsrpJ9csc1fV5yJmz/MFMdOO0vSk3FQQoHt5FRnDsr7p4DooqzgB53MBfGWcs +a0vvaGgLQ+OswWIJ76bdZWGgr4RVSJFSHMYlkSrQwSIjYVmvRRGFHQEkNI/Ps/8XciATwoCqISxx +OQ7Qj1zB09GOInJGTB2Wrk9xseEFKZZZ9LuedT3PDTcNYtsmjGOpI99nBjx8Oto0QuFmtEYE3saW +mA9LSHokMnWRn6z3aOkquVVlzl1h0ydw2Df+n7mvoC5Wt6NlUe07qxS/TFED6F+KBZvuim6c779o ++sjaC+NCydAXFJy3SuCvkychVSa1ZC+N8f+mQAWFBVzKBxlcCxMoTFh/wqXvRdpg065lYZ1Tg3TC +rvJcwhbtkj6EPnNgiLx29CzP0H1907he0ZESEOnN3col49XtmS++dYFLJPlFRpTJKSFTnCZFqhMX +5OfNeOI5wSsSnqaeG8XmDtkx2Q== +-----END CERTIFICATE----- + +Swisscom Root EV CA 2 +===================== +-----BEGIN CERTIFICATE----- +MIIF4DCCA8igAwIBAgIRAPL6ZOJ0Y9ON/RAdBB92ylgwDQYJKoZIhvcNAQELBQAwZzELMAkGA1UE +BhMCY2gxETAPBgNVBAoTCFN3aXNzY29tMSUwIwYDVQQLExxEaWdpdGFsIENlcnRpZmljYXRlIFNl +cnZpY2VzMR4wHAYDVQQDExVTd2lzc2NvbSBSb290IEVWIENBIDIwHhcNMTEwNjI0MDk0NTA4WhcN +MzEwNjI1MDg0NTA4WjBnMQswCQYDVQQGEwJjaDERMA8GA1UEChMIU3dpc3Njb20xJTAjBgNVBAsT +HERpZ2l0YWwgQ2VydGlmaWNhdGUgU2VydmljZXMxHjAcBgNVBAMTFVN3aXNzY29tIFJvb3QgRVYg +Q0EgMjCCAiIwDQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBAMT3HS9X6lds93BdY7BxUglgRCgz +o3pOCvrY6myLURYaVa5UJsTMRQdBTxB5f3HSek4/OE6zAMaVylvNwSqD1ycfMQ4jFrclyxy0uYAy +Xhqdk/HoPGAsp15XGVhRXrwsVgu42O+LgrQ8uMIkqBPHoCE2G3pXKSinLr9xJZDzRINpUKTk4Rti +GZQJo/PDvO/0vezbE53PnUgJUmfANykRHvvSEaeFGHR55E+FFOtSN+KxRdjMDUN/rhPSays/p8Li +qG12W0OfvrSdsyaGOx9/5fLoZigWJdBLlzin5M8J0TbDC77aO0RYjb7xnglrPvMyxyuHxuxenPaH +Za0zKcQvidm5y8kDnftslFGXEBuGCxobP/YCfnvUxVFkKJ3106yDgYjTdLRZncHrYTNaRdHLOdAG +alNgHa/2+2m8atwBz735j9m9W8E6X47aD0upm50qKGsaCnw8qyIL5XctcfaCNYGu+HuB5ur+rPQa +m3Rc6I8k9l2dRsQs0h4rIWqDJ2dVSqTjyDKXZpBy2uPUZC5f46Fq9mDU5zXNysRojddxyNMkM3Ox +bPlq4SjbX8Y96L5V5jcb7STZDxmPX2MYWFCBUWVv8p9+agTnNCRxunZLWB4ZvRVgRaoMEkABnRDi +xzgHcgplwLa7JSnaFp6LNYth7eVxV4O1PHGf40+/fh6Bn0GXAgMBAAGjgYYwgYMwDgYDVR0PAQH/ +BAQDAgGGMB0GA1UdIQQWMBQwEgYHYIV0AVMCAgYHYIV0AVMCAjASBgNVHRMBAf8ECDAGAQH/AgED +MB0GA1UdDgQWBBRF2aWBbj2ITY1x0kbBbkUe88SAnTAfBgNVHSMEGDAWgBRF2aWBbj2ITY1x0kbB +bkUe88SAnTANBgkqhkiG9w0BAQsFAAOCAgEAlDpzBp9SSzBc1P6xXCX5145v9Ydkn+0UjrgEjihL +j6p7jjm02Vj2e6E1CqGdivdj5eu9OYLU43otb98TPLr+flaYC/NUn81ETm484T4VvwYmneTwkLbU +wp4wLh/vx3rEUMfqe9pQy3omywC0Wqu1kx+AiYQElY2NfwmTv9SoqORjbdlk5LgpWgi/UOGED1V7 +XwgiG/W9mR4U9s70WBCCswo9GcG/W6uqmdjyMb3lOGbcWAXH7WMaLgqXfIeTK7KK4/HsGOV1timH +59yLGn602MnTihdsfSlEvoqq9X46Lmgxk7lq2prg2+kupYTNHAq4Sgj5nPFhJpiTt3tm7JFe3VE/ +23MPrQRYCd0EApUKPtN236YQHoA96M2kZNEzx5LH4k5E4wnJTsJdhw4Snr8PyQUQ3nqjsTzyP6Wq +J3mtMX0f/fwZacXduT98zca0wjAefm6S139hdlqP65VNvBFuIXxZN5nQBrz5Bm0yFqXZaajh3DyA +HmBR3NdUIR7KYndP+tiPsys6DXhyyWhBWkdKwqPrGtcKqzwyVcgKEZzfdNbwQBUdyLmPtTbFr/gi +uMod89a2GQ+fYWVq6nTIfI/DT11lgh/ZDYnadXL77/FHZxOzyNEZiCcmmpl5fx7kLD977vHeTYuW +l8PVP3wbI+2ksx0WckNLIOFZfsLorSa/ovc= +-----END CERTIFICATE----- + +CA Disig Root R1 +================ +-----BEGIN CERTIFICATE----- +MIIFaTCCA1GgAwIBAgIJAMMDmu5QkG4oMA0GCSqGSIb3DQEBBQUAMFIxCzAJBgNVBAYTAlNLMRMw +EQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMuMRkwFwYDVQQDExBDQSBEaXNp +ZyBSb290IFIxMB4XDTEyMDcxOTA5MDY1NloXDTQyMDcxOTA5MDY1NlowUjELMAkGA1UEBhMCU0sx +EzARBgNVBAcTCkJyYXRpc2xhdmExEzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERp +c2lnIFJvb3QgUjEwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCqw3j33Jijp1pedxiy +3QRkD2P9m5YJgNXoqqXinCaUOuiZc4yd39ffg/N4T0Dhf9Kn0uXKE5Pn7cZ3Xza1lK/oOI7bm+V8 +u8yN63Vz4STN5qctGS7Y1oprFOsIYgrY3LMATcMjfF9DCCMyEtztDK3AfQ+lekLZWnDZv6fXARz2 +m6uOt0qGeKAeVjGu74IKgEH3G8muqzIm1Cxr7X1r5OJeIgpFy4QxTaz+29FHuvlglzmxZcfe+5nk +CiKxLU3lSCZpq+Kq8/v8kiky6bM+TR8noc2OuRf7JT7JbvN32g0S9l3HuzYQ1VTW8+DiR0jm3hTa +YVKvJrT1cU/J19IG32PK/yHoWQbgCNWEFVP3Q+V8xaCJmGtzxmjOZd69fwX3se72V6FglcXM6pM6 +vpmumwKjrckWtc7dXpl4fho5frLABaTAgqWjR56M6ly2vGfb5ipN0gTco65F97yLnByn1tUD3AjL +LhbKXEAz6GfDLuemROoRRRw1ZS0eRWEkG4IupZ0zXWX4Qfkuy5Q/H6MMMSRE7cderVC6xkGbrPAX +ZcD4XW9boAo0PO7X6oifmPmvTiT6l7Jkdtqr9O3jw2Dv1fkCyC2fg69naQanMVXVz0tv/wQFx1is +XxYb5dKj6zHbHzMVTdDypVP1y+E9Tmgt2BLdqvLmTZtJ5cUoobqwWsagtQIDAQABo0IwQDAPBgNV +HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUiQq0OJMa5qvum5EY+fU8PjXQ +04IwDQYJKoZIhvcNAQEFBQADggIBADKL9p1Kyb4U5YysOMo6CdQbzoaz3evUuii+Eq5FLAR0rBNR +xVgYZk2C2tXck8An4b58n1KeElb21Zyp9HWc+jcSjxyT7Ff+Bw+r1RL3D65hXlaASfX8MPWbTx9B +LxyE04nH4toCdu0Jz2zBuByDHBb6lM19oMgY0sidbvW9adRtPTXoHqJPYNcHKfyyo6SdbhWSVhlM +CrDpfNIZTUJG7L399ldb3Zh+pE3McgODWF3vkzpBemOqfDqo9ayk0d2iLbYq/J8BjuIQscTK5Gfb +VSUZP/3oNn6z4eGBrxEWi1CXYBmCAMBrTXO40RMHPuq2MU/wQppt4hF05ZSsjYSVPCGvxdpHyN85 +YmLLW1AL14FABZyb7bq2ix4Eb5YgOe2kfSnbSM6C3NQCjR0EMVrHS/BsYVLXtFHCgWzN4funodKS +ds+xDzdYpPJScWc/DIh4gInByLUfkmO+p3qKViwaqKactV2zY9ATIKHrkWzQjX2v3wvkF7mGnjix +lAxYjOBVqjtjbZqJYLhkKpLGN/R+Q0O3c+gB53+XD9fyexn9GtePyfqFa3qdnom2piiZk4hA9z7N +UaPK6u95RyG1/jLix8NRb76AdPCkwzryT+lf3xkK8jsTQ6wxpLPn6/wY1gGp8yqPNg7rtLG8t0zJ +a7+h89n07eLw4+1knj0vllJPgFOL +-----END CERTIFICATE----- + +CA Disig Root R2 +================ +-----BEGIN CERTIFICATE----- +MIIFaTCCA1GgAwIBAgIJAJK4iNuwisFjMA0GCSqGSIb3DQEBCwUAMFIxCzAJBgNVBAYTAlNLMRMw +EQYDVQQHEwpCcmF0aXNsYXZhMRMwEQYDVQQKEwpEaXNpZyBhLnMuMRkwFwYDVQQDExBDQSBEaXNp +ZyBSb290IFIyMB4XDTEyMDcxOTA5MTUzMFoXDTQyMDcxOTA5MTUzMFowUjELMAkGA1UEBhMCU0sx +EzARBgNVBAcTCkJyYXRpc2xhdmExEzARBgNVBAoTCkRpc2lnIGEucy4xGTAXBgNVBAMTEENBIERp +c2lnIFJvb3QgUjIwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCio8QACdaFXS1tFPbC +w3OeNcJxVX6B+6tGUODBfEl45qt5WDza/3wcn9iXAng+a0EE6UG9vgMsRfYvZNSrXaNHPWSb6Wia +xswbP7q+sos0Ai6YVRn8jG+qX9pMzk0DIaPY0jSTVpbLTAwAFjxfGs3Ix2ymrdMxp7zo5eFm1tL7 +A7RBZckQrg4FY8aAamkw/dLukO8NJ9+flXP04SXabBbeQTg06ov80egEFGEtQX6sx3dOy1FU+16S +GBsEWmjGycT6txOgmLcRK7fWV8x8nhfRyyX+hk4kLlYMeE2eARKmK6cBZW58Yh2EhN/qwGu1pSqV +g8NTEQxzHQuyRpDRQjrOQG6Vrf/GlK1ul4SOfW+eioANSW1z4nuSHsPzwfPrLgVv2RvPN3YEyLRa +5Beny912H9AZdugsBbPWnDTYltxhh5EF5EQIM8HauQhl1K6yNg3ruji6DOWbnuuNZt2Zz9aJQfYE +koopKW1rOhzndX0CcQ7zwOe9yxndnWCywmZgtrEE7snmhrmaZkCo5xHtgUUDi/ZnWejBBhG93c+A +Ak9lQHhcR1DIm+YfgXvkRKhbhZri3lrVx/k6RGZL5DJUfORsnLMOPReisjQS1n6yqEm70XooQL6i +Fh/f5DcfEXP7kAplQ6INfPgGAVUzfbANuPT1rqVCV3w2EYx7XsQDnYx5nQIDAQABo0IwQDAPBgNV +HRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUtZn4r7CU9eMg1gqtzk5WpC5u +Qu0wDQYJKoZIhvcNAQELBQADggIBACYGXnDnZTPIgm7ZnBc6G3pmsgH2eDtpXi/q/075KMOYKmFM +tCQSin1tERT3nLXK5ryeJ45MGcipvXrA1zYObYVybqjGom32+nNjf7xueQgcnYqfGopTpti72TVV +sRHFqQOzVju5hJMiXn7B9hJSi+osZ7z+Nkz1uM/Rs0mSO9MpDpkblvdhuDvEK7Z4bLQjb/D907Je +dR+Zlais9trhxTF7+9FGs9K8Z7RiVLoJ92Owk6Ka+elSLotgEqv89WBW7xBci8QaQtyDW2QOy7W8 +1k/BfDxujRNt+3vrMNDcTa/F1balTFtxyegxvug4BkihGuLq0t4SOVga/4AOgnXmt8kHbA7v/zjx +mHHEt38OFdAlab0inSvtBfZGR6ztwPDUO+Ls7pZbkBNOHlY667DvlruWIxG68kOGdGSVyCh13x01 +utI3gzhTODY7z2zp+WsO0PsE6E9312UBeIYMej4hYvF/Y3EMyZ9E26gnonW+boE+18DrG5gPcFw0 +sorMwIUY6256s/daoQe/qUKS82Ail+QUoQebTnbAjn39pCXHR+3/H3OszMOl6W8KjptlwlCFtaOg +UxLMVYdh84GuEEZhvUQhuMI9dM9+JDX6HAcOmz0iyu8xL4ysEr3vQCj8KWefshNPZiTEUxnpHikV +7+ZtsH8tZ/3zbBt1RqPlShfppNcL +-----END CERTIFICATE----- + +ACCVRAIZ1 +========= +-----BEGIN CERTIFICATE----- +MIIH0zCCBbugAwIBAgIIXsO3pkN/pOAwDQYJKoZIhvcNAQEFBQAwQjESMBAGA1UEAwwJQUNDVlJB +SVoxMRAwDgYDVQQLDAdQS0lBQ0NWMQ0wCwYDVQQKDARBQ0NWMQswCQYDVQQGEwJFUzAeFw0xMTA1 +MDUwOTM3MzdaFw0zMDEyMzEwOTM3MzdaMEIxEjAQBgNVBAMMCUFDQ1ZSQUlaMTEQMA4GA1UECwwH +UEtJQUNDVjENMAsGA1UECgwEQUNDVjELMAkGA1UEBhMCRVMwggIiMA0GCSqGSIb3DQEBAQUAA4IC +DwAwggIKAoICAQCbqau/YUqXry+XZpp0X9DZlv3P4uRm7x8fRzPCRKPfmt4ftVTdFXxpNRFvu8gM +jmoYHtiP2Ra8EEg2XPBjs5BaXCQ316PWywlxufEBcoSwfdtNgM3802/J+Nq2DoLSRYWoG2ioPej0 +RGy9ocLLA76MPhMAhN9KSMDjIgro6TenGEyxCQ0jVn8ETdkXhBilyNpAlHPrzg5XPAOBOp0KoVdD +aaxXbXmQeOW1tDvYvEyNKKGno6e6Ak4l0Squ7a4DIrhrIA8wKFSVf+DuzgpmndFALW4ir50awQUZ +0m/A8p/4e7MCQvtQqR0tkw8jq8bBD5L/0KIV9VMJcRz/RROE5iZe+OCIHAr8Fraocwa48GOEAqDG +WuzndN9wrqODJerWx5eHk6fGioozl2A3ED6XPm4pFdahD9GILBKfb6qkxkLrQaLjlUPTAYVtjrs7 +8yM2x/474KElB0iryYl0/wiPgL/AlmXz7uxLaL2diMMxs0Dx6M/2OLuc5NF/1OVYm3z61PMOm3WR +5LpSLhl+0fXNWhn8ugb2+1KoS5kE3fj5tItQo05iifCHJPqDQsGH+tUtKSpacXpkatcnYGMN285J +9Y0fkIkyF/hzQ7jSWpOGYdbhdQrqeWZ2iE9x6wQl1gpaepPluUsXQA+xtrn13k/c4LOsOxFwYIRK +Q26ZIMApcQrAZQIDAQABo4ICyzCCAscwfQYIKwYBBQUHAQEEcTBvMEwGCCsGAQUFBzAChkBodHRw +Oi8vd3d3LmFjY3YuZXMvZmlsZWFkbWluL0FyY2hpdm9zL2NlcnRpZmljYWRvcy9yYWl6YWNjdjEu +Y3J0MB8GCCsGAQUFBzABhhNodHRwOi8vb2NzcC5hY2N2LmVzMB0GA1UdDgQWBBTSh7Tj3zcnk1X2 +VuqB5TbMjB4/vTAPBgNVHRMBAf8EBTADAQH/MB8GA1UdIwQYMBaAFNKHtOPfNyeTVfZW6oHlNsyM +Hj+9MIIBcwYDVR0gBIIBajCCAWYwggFiBgRVHSAAMIIBWDCCASIGCCsGAQUFBwICMIIBFB6CARAA +QQB1AHQAbwByAGkAZABhAGQAIABkAGUAIABDAGUAcgB0AGkAZgBpAGMAYQBjAGkA8wBuACAAUgBh +AO0AegAgAGQAZQAgAGwAYQAgAEEAQwBDAFYAIAAoAEEAZwBlAG4AYwBpAGEAIABkAGUAIABUAGUA +YwBuAG8AbABvAGcA7QBhACAAeQAgAEMAZQByAHQAaQBmAGkAYwBhAGMAaQDzAG4AIABFAGwAZQBj +AHQAcgDzAG4AaQBjAGEALAAgAEMASQBGACAAUQA0ADYAMAAxADEANQA2AEUAKQAuACAAQwBQAFMA +IABlAG4AIABoAHQAdABwADoALwAvAHcAdwB3AC4AYQBjAGMAdgAuAGUAczAwBggrBgEFBQcCARYk +aHR0cDovL3d3dy5hY2N2LmVzL2xlZ2lzbGFjaW9uX2MuaHRtMFUGA1UdHwROMEwwSqBIoEaGRGh0 +dHA6Ly93d3cuYWNjdi5lcy9maWxlYWRtaW4vQXJjaGl2b3MvY2VydGlmaWNhZG9zL3JhaXphY2N2 +MV9kZXIuY3JsMA4GA1UdDwEB/wQEAwIBBjAXBgNVHREEEDAOgQxhY2N2QGFjY3YuZXMwDQYJKoZI +hvcNAQEFBQADggIBAJcxAp/n/UNnSEQU5CmH7UwoZtCPNdpNYbdKl02125DgBS4OxnnQ8pdpD70E +R9m+27Up2pvZrqmZ1dM8MJP1jaGo/AaNRPTKFpV8M9xii6g3+CfYCS0b78gUJyCpZET/LtZ1qmxN +YEAZSUNUY9rizLpm5U9EelvZaoErQNV/+QEnWCzI7UiRfD+mAM/EKXMRNt6GGT6d7hmKG9Ww7Y49 +nCrADdg9ZuM8Db3VlFzi4qc1GwQA9j9ajepDvV+JHanBsMyZ4k0ACtrJJ1vnE5Bc5PUzolVt3OAJ +TS+xJlsndQAJxGJ3KQhfnlmstn6tn1QwIgPBHnFk/vk4CpYY3QIUrCPLBhwepH2NDd4nQeit2hW3 +sCPdK6jT2iWH7ehVRE2I9DZ+hJp4rPcOVkkO1jMl1oRQQmwgEh0q1b688nCBpHBgvgW1m54ERL5h +I6zppSSMEYCUWqKiuUnSwdzRp+0xESyeGabu4VXhwOrPDYTkF7eifKXeVSUG7szAh1xA2syVP1Xg +Nce4hL60Xc16gwFy7ofmXx2utYXGJt/mwZrpHgJHnyqobalbz+xFd3+YJ5oyXSrjhO7FmGYvliAd +3djDJ9ew+f7Zfc3Qn48LFFhRny+Lwzgt3uiP1o2HpPVWQxaZLPSkVrQ0uGE3ycJYgBugl6H8WY3p +EfbRD0tVNEYqi4Y7 +-----END CERTIFICATE----- + +TWCA Global Root CA +=================== +-----BEGIN CERTIFICATE----- +MIIFQTCCAymgAwIBAgICDL4wDQYJKoZIhvcNAQELBQAwUTELMAkGA1UEBhMCVFcxEjAQBgNVBAoT +CVRBSVdBTi1DQTEQMA4GA1UECxMHUm9vdCBDQTEcMBoGA1UEAxMTVFdDQSBHbG9iYWwgUm9vdCBD +QTAeFw0xMjA2MjcwNjI4MzNaFw0zMDEyMzExNTU5NTlaMFExCzAJBgNVBAYTAlRXMRIwEAYDVQQK +EwlUQUlXQU4tQ0ExEDAOBgNVBAsTB1Jvb3QgQ0ExHDAaBgNVBAMTE1RXQ0EgR2xvYmFsIFJvb3Qg +Q0EwggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQCwBdvI64zEbooh745NnHEKH1Jw7W2C +nJfF10xORUnLQEK1EjRsGcJ0pDFfhQKX7EMzClPSnIyOt7h52yvVavKOZsTuKwEHktSz0ALfUPZV +r2YOy+BHYC8rMjk1Ujoog/h7FsYYuGLWRyWRzvAZEk2tY/XTP3VfKfChMBwqoJimFb3u/Rk28OKR +Q4/6ytYQJ0lM793B8YVwm8rqqFpD/G2Gb3PpN0Wp8DbHzIh1HrtsBv+baz4X7GGqcXzGHaL3SekV +tTzWoWH1EfcFbx39Eb7QMAfCKbAJTibc46KokWofwpFFiFzlmLhxpRUZyXx1EcxwdE8tmx2RRP1W +KKD+u4ZqyPpcC1jcxkt2yKsi2XMPpfRaAok/T54igu6idFMqPVMnaR1sjjIsZAAmY2E2TqNGtz99 +sy2sbZCilaLOz9qC5wc0GZbpuCGqKX6mOL6OKUohZnkfs8O1CWfe1tQHRvMq2uYiN2DLgbYPoA/p +yJV/v1WRBXrPPRXAb94JlAGD1zQbzECl8LibZ9WYkTunhHiVJqRaCPgrdLQABDzfuBSO6N+pjWxn +kjMdwLfS7JLIvgm/LCkFbwJrnu+8vyq8W8BQj0FwcYeyTbcEqYSjMq+u7msXi7Kx/mzhkIyIqJdI +zshNy/MGz19qCkKxHh53L46g5pIOBvwFItIm4TFRfTLcDwIDAQABoyMwITAOBgNVHQ8BAf8EBAMC +AQYwDwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAgEAXzSBdu+WHdXltdkCY4QWwa6g +cFGn90xHNcgL1yg9iXHZqjNB6hQbbCEAwGxCGX6faVsgQt+i0trEfJdLjbDorMjupWkEmQqSpqsn +LhpNgb+E1HAerUf+/UqdM+DyucRFCCEK2mlpc3INvjT+lIutwx4116KD7+U4x6WFH6vPNOw/KP4M +8VeGTslV9xzU2KV9Bnpv1d8Q34FOIWWxtuEXeZVFBs5fzNxGiWNoRI2T9GRwoD2dKAXDOXC4Ynsg +/eTb6QihuJ49CcdP+yz4k3ZB3lLg4VfSnQO8d57+nile98FRYB/e2guyLXW3Q0iT5/Z5xoRdgFlg +lPx4mI88k1HtQJAH32RjJMtOcQWh15QaiDLxInQirqWm2BJpTGCjAu4r7NRjkgtevi92a6O2JryP +A9gK8kxkRr05YuWW6zRjESjMlfGt7+/cgFhI6Uu46mWs6fyAtbXIRfmswZ/ZuepiiI7E8UuDEq3m +i4TWnsLrgxifarsbJGAzcMzs9zLzXNl5fe+epP7JI8Mk7hWSsT2RTyaGvWZzJBPqpK5jwa19hAM8 +EHiGG3njxPPyBJUgriOCxLM6AGK/5jYk4Ve6xx6QddVfP5VhK8E7zeWzaGHQRiapIVJpLesux+t3 +zqY6tQMzT3bR51xUAV3LePTJDL/PEo4XLSNolOer/qmyKwbQBM0= +-----END CERTIFICATE----- diff --git a/core/vendor/guzzlehttp/guzzle/src/functions.php b/core/vendor/guzzlehttp/guzzle/src/functions.php new file mode 100644 index 00000000000..852c6db91fc --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/src/functions.php @@ -0,0 +1,296 @@ +send($client->createRequest($method, $url, $options)); +} + +/** + * Send a GET request + * + * @param string $url URL of the request + * @param array $options Array of request options + * + * @return ResponseInterface + */ +function get($url, array $options = []) +{ + return request('GET', $url, $options); +} + +/** + * Send a HEAD request + * + * @param string $url URL of the request + * @param array $options Array of request options + * + * @return ResponseInterface + */ +function head($url, array $options = []) +{ + return request('HEAD', $url, $options); +} + +/** + * Send a DELETE request + * + * @param string $url URL of the request + * @param array $options Array of request options + * + * @return ResponseInterface + */ +function delete($url, array $options = []) +{ + return request('DELETE', $url, $options); +} + +/** + * Send a POST request + * + * @param string $url URL of the request + * @param array $options Array of request options + * + * @return ResponseInterface + */ +function post($url, array $options = []) +{ + return request('POST', $url, $options); +} + +/** + * Send a PUT request + * + * @param string $url URL of the request + * @param array $options Array of request options + * + * @return ResponseInterface + */ +function put($url, array $options = []) +{ + return request('PUT', $url, $options); +} + +/** + * Send a PATCH request + * + * @param string $url URL of the request + * @param array $options Array of request options + * + * @return ResponseInterface + */ +function patch($url, array $options = []) +{ + return request('PATCH', $url, $options); +} + +/** + * Send an OPTIONS request + * + * @param string $url URL of the request + * @param array $options Array of request options + * + * @return ResponseInterface + */ +function options($url, array $options = []) +{ + return request('OPTIONS', $url, $options); +} + +/** + * Convenience method for sending multiple requests in parallel and retrieving + * a hash map of requests to response objects or RequestException objects. + * + * Note: This method keeps every request and response in memory, and as such is + * NOT recommended when sending a large number or an indeterminable number of + * requests in parallel. + * + * @param ClientInterface $client Client used to send the requests + * @param array|\Iterator $requests Requests to send in parallel + * @param array $options Passes through the options available in + * {@see GuzzleHttp\ClientInterface::sendAll()} + * @return \SplObjectStorage Requests are the key and each value is a + * {@see GuzzleHttp\Message\ResponseInterface} if the request succeeded or + * a {@see GuzzleHttp\Exception\RequestException} if it failed. + * @throws \InvalidArgumentException if the event format is incorrect. + */ +function batch(ClientInterface $client, $requests, array $options = []) +{ + $hash = new \SplObjectStorage(); + foreach ($requests as $request) { + $hash->attach($request); + } + + $handler = [ + 'priority' => RequestEvents::EARLY, + 'once' => true, + 'fn' => function ($e) use ($hash) { $hash[$e->getRequest()] = $e; } + ]; + + // Merge the necessary complete and error events to the event listeners so + // that as each request succeeds or fails, it is added to the result hash. + foreach (['complete', 'error'] as $name) { + if (!isset($options[$name])) { + $options[$name] = $handler; + } elseif (is_callable($options[$name])) { + $options[$name] = [['fn' => $options[$name]], $handler]; + } elseif (is_array($options[$name])) { + $options[$name][] = $handler; + } else { + throw new \InvalidArgumentException('Invalid event format'); + } + } + + // Send the requests in parallel and aggregate the results. + $client->sendAll($requests, $options); + + // Update the received value for any of the intercepted requests. + foreach ($hash as $request) { + if ($hash[$request] instanceof CompleteEvent) { + $hash[$request] = $hash[$request]->getResponse(); + } elseif ($hash[$request] instanceof ErrorEvent) { + $hash[$request] = $hash[$request]->getException(); + } + } + + return $hash; +} + +/** + * Gets a value from an array using a path syntax to retrieve nested data. + * + * This method does not allow for keys that contain "/". You must traverse + * the array manually or using something more advanced like JMESPath to + * work with keys that contain "/". + * + * // Get the bar key of a set of nested arrays. + * // This is equivalent to $collection['foo']['baz']['bar'] but won't + * // throw warnings for missing keys. + * GuzzleHttp\get_path($data, 'foo/baz/bar'); + * + * @param array $data Data to retrieve values from + * @param string $path Path to traverse and retrieve a value from + * + * @return mixed|null + */ +function get_path($data, $path) +{ + $path = explode('/', $path); + + while (null !== ($part = array_shift($path))) { + if (!is_array($data) || !isset($data[$part])) { + return null; + } + $data = $data[$part]; + } + + return $data; +} + +/** + * Set a value in a nested array key. Keys will be created as needed to set the + * value. + * + * This function does not support keys that contain "/" or "[]" characters + * because these are special tokens used when traversing the data structure. + * A value may be prepended to an existing array by using "[]" as the final + * key of a path. + * + * GuzzleHttp\get_path($data, 'foo/baz'); // null + * GuzzleHttp\set_path($data, 'foo/baz/[]', 'a'); + * GuzzleHttp\set_path($data, 'foo/baz/[]', 'b'); + * GuzzleHttp\get_path($data, 'foo/baz'); + * // Returns ['a', 'b'] + * + * @param array $data Data to modify by reference + * @param string $path Path to set + * @param mixed $value Value to set at the key + * @throws \RuntimeException when trying to setPath using a nested path that + * travels through a scalar value. + */ +function set_path(&$data, $path, $value) +{ + $current =& $data; + $queue = explode('/', $path); + while (null !== ($key = array_shift($queue))) { + if (!is_array($current)) { + throw new \RuntimeException("Trying to setPath {$path}, but " + . "{$key} is set and is not an array"); + } elseif (!$queue) { + if ($key == '[]') { + $current[] = $value; + } else { + $current[$key] = $value; + } + } elseif (isset($current[$key])) { + $current =& $current[$key]; + } else { + $current[$key] = []; + $current =& $current[$key]; + } + } +} + +/** + * Expands a URI template + * + * @param string $template URI template + * @param array $variables Template variables + * + * @return string + */ +function uri_template($template, array $variables) +{ + if (function_exists('\\uri_template')) { + return \uri_template($template, $variables); + } + + static $uriTemplate; + if (!$uriTemplate) { + $uriTemplate = new UriTemplate(); + } + + return $uriTemplate->expand($template, $variables); +} + +/** + * @internal + */ +function deprecation_proxy($object, $name, $arguments, $map) +{ + if (!isset($map[$name])) { + throw new \BadMethodCallException('Unknown method, ' . $name); + } + + $message = sprintf('%s is deprecated and will be removed in a future ' + . 'version. Update your code to use the equivalent %s method ' + . 'instead to avoid breaking changes when this shim is removed.', + get_class($object) . '::' . $name . '()', + get_class($object) . '::' . $map[$name] . '()' + ); + + trigger_error($message, E_USER_DEPRECATED); + + return call_user_func_array([$object, $map[$name]], $arguments); +} diff --git a/core/vendor/guzzlehttp/guzzle/tests/Adapter/Curl/AbstractCurl.php b/core/vendor/guzzlehttp/guzzle/tests/Adapter/Curl/AbstractCurl.php new file mode 100644 index 00000000000..fa8f1716d88 --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/tests/Adapter/Curl/AbstractCurl.php @@ -0,0 +1,92 @@ +getAdapter(); + $response = $a->send($t); + $this->assertEquals(200, $response->getStatusCode()); + $this->assertEquals('bar', $response->getHeader('Foo')); + } + + /** + * @expectedException \GuzzleHttp\Exception\RequestException + */ + public function testCatchesErrorWhenPreparing() + { + $r = new Request('GET', Server::$url); + $f = $this->getMockBuilder('GuzzleHttp\Adapter\Curl\CurlFactory') + ->setMethods(['__invoke']) + ->getMock(); + $f->expects($this->once()) + ->method('__invoke') + ->will($this->throwException(new RequestException('foo', $r))); + + $t = new Transaction(new Client(), $r); + $a = $this->getAdapter(null, ['handle_factory' => $f]); + $a->send($t); + } + + public function testDispatchesAfterSendEvent() + { + Server::flush(); + Server::enqueue("HTTP/1.1 201 OK\r\nContent-Length: 0\r\n\r\n"); + $r = new Request('GET', Server::$url); + $t = new Transaction(new Client(), $r); + $a = $this->getAdapter(); + $ev = null; + $r->getEmitter()->on('complete', function (CompleteEvent $e) use (&$ev) { + $ev = $e; + $e->intercept(new Response(200, ['Foo' => 'bar'])); + }); + $response = $a->send($t); + $this->assertEquals(200, $response->getStatusCode()); + $this->assertEquals('bar', $response->getHeader('Foo')); + } + + public function testDispatchesErrorEventAndRecovers() + { + Server::flush(); + Server::enqueue("HTTP/1.1 201 OK\r\nContent-Length: 0\r\n\r\n"); + $r = new Request('GET', Server::$url); + $t = new Transaction(new Client(), $r); + $a = $this->getAdapter(); + $r->getEmitter()->once('complete', function (CompleteEvent $e) { + throw new RequestException('Foo', $e->getRequest()); + }); + $r->getEmitter()->on('error', function (ErrorEvent $e) { + $e->intercept(new Response(200, ['Foo' => 'bar'])); + }); + $response = $a->send($t); + $this->assertEquals(200, $response->getStatusCode()); + $this->assertEquals('bar', $response->getHeader('Foo')); + } + + public function testStripsFragmentFromHost() + { + Server::flush(); + Server::enqueue("HTTP/1.1 200 OK\r\n\r\nContent-Length: 0\r\n\r\n"); + // This will fail if the removal of the #fragment is not performed + $url = Url::fromString(Server::$url)->setPath(null)->setFragment('foo'); + $client = new Client(); + $client->get($url); + } +} diff --git a/core/vendor/guzzlehttp/guzzle/tests/Adapter/Curl/BatchContextTest.php b/core/vendor/guzzlehttp/guzzle/tests/Adapter/Curl/BatchContextTest.php new file mode 100644 index 00000000000..a3c82f2c553 --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/tests/Adapter/Curl/BatchContextTest.php @@ -0,0 +1,93 @@ +assertTrue($b->throwsExceptions()); + $this->assertSame($m, $b->getMultiHandle()); + $this->assertFalse($b->hasPending()); + curl_multi_close($m); + } + + public function testValidatesTransactionsAreNotAddedTwice() + { + $m = curl_multi_init(); + $b = new BatchContext($m, true); + $h = curl_init(); + $t = new Transaction( + new Client(), + new Request('GET', 'http://httbin.org') + ); + $b->addTransaction($t, $h); + try { + $b->addTransaction($t, $h); + $this->fail('Did not throw'); + } catch (\RuntimeException $e) { + curl_close($h); + curl_multi_close($m); + } + } + + public function testManagesHandles() + { + $m = curl_multi_init(); + $b = new BatchContext($m, true); + $h = curl_init(); + $t = new Transaction( + new Client(), + new Request('GET', 'http://httbin.org') + ); + $b->addTransaction($t, $h); + $this->assertSame($t, $b->findTransaction($h)); + $b->removeTransaction($t); + try { + $this->assertEquals([], $b->findTransaction($h)); + $this->fail('Did not throw'); + } catch (\RuntimeException $e) {} + curl_multi_close($m); + } + + /** + * @expectedException \RuntimeException + * @expectedExceptionMessage Transaction not registered + */ + public function testThrowsWhenRemovingNonExistentTransaction() + { + $b = new BatchContext('foo', false); + $t = new Transaction( + new Client(), + new Request('GET', 'http://httbin.org') + ); + $b->removeTransaction($t); + } + + public function testReturnsPendingAsIteratorTypeObject() + { + $t1 = new Transaction(new Client(), new Request('GET', 'http://t.com')); + $t2 = new Transaction(new Client(), new Request('GET', 'http://t.com')); + $t3 = new Transaction(new Client(), new Request('GET', 'http://t.com')); + $iter = new \ArrayIterator([$t1, $t2, $t3]); + $b = new BatchContext('foo', false, $iter); + $this->assertTrue($b->hasPending()); + $this->assertSame($t1, $b->nextPending()); + $this->assertTrue($b->hasPending()); + $this->assertSame($t2, $b->nextPending()); + $this->assertTrue($b->hasPending()); + $this->assertSame($t3, $b->nextPending()); + $this->assertFalse($b->hasPending()); + $this->assertNull($b->nextPending()); + } +} diff --git a/core/vendor/guzzlehttp/guzzle/tests/Adapter/Curl/CurlAdapterTest.php b/core/vendor/guzzlehttp/guzzle/tests/Adapter/Curl/CurlAdapterTest.php new file mode 100644 index 00000000000..dd6389a58ff --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/tests/Adapter/Curl/CurlAdapterTest.php @@ -0,0 +1,120 @@ +markTestSkipped('curl_reset() is not available'); + } + } + + protected function getAdapter($factory = null, $options = []) + { + return new CurlAdapter($factory ?: new MessageFactory(), $options); + } + + public function testCanSetMaxHandles() + { + $a = new CurlAdapter(new MessageFactory(), ['max_handles' => 10]); + $this->assertEquals(10, $this->readAttribute($a, 'maxHandles')); + } + + public function testCanInterceptBeforeSending() + { + $client = new Client(); + $request = new Request('GET', 'http://httpbin.org/get'); + $response = new Response(200); + $request->getEmitter()->on( + 'before', + function (BeforeEvent $e) use ($response) { + $e->intercept($response); + } + ); + $transaction = new Transaction($client, $request); + $f = 'does_not_work'; + $a = new CurlAdapter(new MessageFactory(), ['handle_factory' => $f]); + $a->send($transaction); + $this->assertSame($response, $transaction->getResponse()); + } + + /** + * @expectedException \GuzzleHttp\Exception\RequestException + * @expectedExceptionMessage cURL error + */ + public function testThrowsCurlErrors() + { + $client = new Client(); + $request = $client->createRequest('GET', 'http://localhost:123', [ + 'connect_timeout' => 0.001, + 'timeout' => 0.001, + ]); + $transaction = new Transaction($client, $request); + $a = new CurlAdapter(new MessageFactory()); + $a->send($transaction); + } + + public function testHandlesCurlErrors() + { + $client = new Client(); + $request = $client->createRequest('GET', 'http://localhost:123', [ + 'connect_timeout' => 0.001, + 'timeout' => 0.001, + ]); + $r = new Response(200); + $request->getEmitter()->on('error', function (ErrorEvent $e) use ($r) { + $e->intercept($r); + }); + $transaction = new Transaction($client, $request); + $a = new CurlAdapter(new MessageFactory()); + $a->send($transaction); + $this->assertSame($r, $transaction->getResponse()); + } + + public function testReleasesAdditionalEasyHandles() + { + Server::flush(); + Server::enqueue([ + "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n", + "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n", + "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n", + "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n" + ]); + $a = new CurlAdapter(new MessageFactory(), ['max_handles' => 2]); + $client = new Client(['base_url' => Server::$url, 'adapter' => $a]); + $request = $client->createRequest('GET', '/', [ + 'events' => [ + 'headers' => function (HeadersEvent $e) use ($client) { + $client->get('/', [ + 'events' => [ + 'headers' => function (HeadersEvent $e) { + $e->getClient()->get('/'); + } + ] + ]); + } + ] + ]); + $transaction = new Transaction($client, $request); + $a->send($transaction); + $this->assertCount(2, $this->readAttribute($a, 'handles')); + } +} diff --git a/core/vendor/guzzlehttp/guzzle/tests/Adapter/Curl/CurlFactoryTest.php b/core/vendor/guzzlehttp/guzzle/tests/Adapter/Curl/CurlFactoryTest.php new file mode 100644 index 00000000000..9bf8fc70675 --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/tests/Adapter/Curl/CurlFactoryTest.php @@ -0,0 +1,291 @@ + ' 123'], + Stream::factory('testing') + ); + $stream = Stream::factory(); + $request->getConfig()->set('save_to', $stream); + $request->getConfig()->set('verify', true); + $this->emit($request); + + $t = new Transaction(new Client(), $request); + $f = new CurlFactory(); + $h = $f($t, new MessageFactory()); + $this->assertInternalType('resource', $h); + curl_exec($h); + $response = $t->getResponse(); + $this->assertInstanceOf('GuzzleHttp\Message\ResponseInterface', $response); + $this->assertEquals('hi', $response->getBody()); + $this->assertEquals('Bar', $response->getHeader('Foo')); + $this->assertEquals('bam', $response->getHeader('Baz')); + curl_close($h); + + $sent = Server::received(true)[0]; + $this->assertEquals('PUT', $sent->getMethod()); + $this->assertEquals('/haha', $sent->getPath()); + $this->assertEquals('123', $sent->getHeader('Hi')); + $this->assertEquals('7', $sent->getHeader('Content-Length')); + $this->assertEquals('testing', $sent->getBody()); + $this->assertEquals('1.1', $sent->getProtocolVersion()); + $this->assertEquals('hi', (string) $stream); + + $this->assertEquals(2, $_SERVER['last_curl'][CURLOPT_SSL_VERIFYHOST]); + $this->assertEquals(true, $_SERVER['last_curl'][CURLOPT_SSL_VERIFYPEER]); + } + + public function testSendsHeadRequests() + { + Server::flush(); + Server::enqueue(["HTTP/1.1 200 OK\r\nContent-Length: 2\r\n\r\n"]); + $request = new Request('HEAD', Server::$url); + $this->emit($request); + + $t = new Transaction(new Client(), $request); + $f = new CurlFactory(); + $h = $f($t, new MessageFactory()); + curl_exec($h); + curl_close($h); + $response = $t->getResponse(); + $this->assertEquals('2', $response->getHeader('Content-Length')); + $this->assertEquals('', $response->getBody()); + + $sent = Server::received(true)[0]; + $this->assertEquals('HEAD', $sent->getMethod()); + $this->assertEquals('/', $sent->getPath()); + } + + public function testSendsPostRequestWithNoBody() + { + Server::flush(); + Server::enqueue(["HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"]); + $request = new Request('POST', Server::$url); + $this->emit($request); + $t = new Transaction(new Client(), $request); + $f = new CurlFactory(); + $h = $f($t, new MessageFactory()); + curl_exec($h); + curl_close($h); + $sent = Server::received(true)[0]; + $this->assertEquals('POST', $sent->getMethod()); + $this->assertEquals('', $sent->getBody()); + } + + public function testSendsChunkedRequests() + { + $stream = $this->getMockBuilder('GuzzleHttp\Stream\Stream') + ->setConstructorArgs([fopen('php://temp', 'r+')]) + ->setMethods(['getSize']) + ->getMock(); + $stream->expects($this->any()) + ->method('getSize') + ->will($this->returnValue(null)); + $stream->write('foo'); + $stream->seek(0); + + Server::flush(); + Server::enqueue(["HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n"]); + $request = new Request('PUT', Server::$url, [], $stream); + $this->emit($request); + $this->assertNull($request->getBody()->getSize()); + $t = new Transaction(new Client(), $request); + $f = new CurlFactory(); + $h = $f($t, new MessageFactory()); + curl_exec($h); + curl_close($h); + $sent = Server::received(false)[0]; + $this->assertContains('PUT / HTTP/1.1', $sent); + $this->assertContains('transfer-encoding: chunked', strtolower($sent)); + $this->assertContains("\r\n\r\nfoo", $sent); + } + + public function testDecodesGzippedResponses() + { + Server::flush(); + Server::enqueue(["HTTP/1.1 200 OK\r\nContent-Length: 3\r\n\r\nfoo"]); + $request = new Request('GET', Server::$url, ['Accept-Encoding' => '']); + $this->emit($request); + $t = new Transaction(new Client(), $request); + $f = new CurlFactory(); + $h = $f($t, new MessageFactory()); + curl_exec($h); + curl_close($h); + $this->assertEquals('foo', $t->getResponse()->getBody()); + $sent = Server::received(true)[0]; + $this->assertContains('gzip', $sent->getHeader('Accept-Encoding')); + } + + public function testAddsDebugInfoToBuffer() + { + $r = fopen('php://temp', 'r+'); + Server::flush(); + Server::enqueue(["HTTP/1.1 200 OK\r\nContent-Length: 3\r\n\r\nfoo"]); + $request = new Request('GET', Server::$url); + $request->getConfig()->set('debug', $r); + $this->emit($request); + $t = new Transaction(new Client(), $request); + $f = new CurlFactory(); + $h = $f($t, new MessageFactory()); + curl_exec($h); + curl_close($h); + rewind($r); + $this->assertNotEmpty(stream_get_contents($r)); + } + + public function testAddsProxyOptions() + { + $request = new Request('GET', Server::$url); + $this->emit($request); + $request->getConfig()->set('proxy', '123'); + $request->getConfig()->set('connect_timeout', 1); + $request->getConfig()->set('timeout', 2); + $request->getConfig()->set('cert', __FILE__); + $request->getConfig()->set('ssl_key', [__FILE__, '123']); + $request->getConfig()->set('verify', false); + $t = new Transaction(new Client(), $request); + $f = new CurlFactory(); + curl_close($f($t, new MessageFactory())); + $this->assertEquals('123', $_SERVER['last_curl'][CURLOPT_PROXY]); + $this->assertEquals(1000, $_SERVER['last_curl'][CURLOPT_CONNECTTIMEOUT_MS]); + $this->assertEquals(2000, $_SERVER['last_curl'][CURLOPT_TIMEOUT_MS]); + $this->assertEquals(__FILE__, $_SERVER['last_curl'][CURLOPT_SSLCERT]); + $this->assertEquals(__FILE__, $_SERVER['last_curl'][CURLOPT_SSLKEY]); + $this->assertEquals('123', $_SERVER['last_curl'][CURLOPT_SSLKEYPASSWD]); + $this->assertEquals(0, $_SERVER['last_curl'][CURLOPT_SSL_VERIFYHOST]); + $this->assertEquals(false, $_SERVER['last_curl'][CURLOPT_SSL_VERIFYPEER]); + } + + /** + * @expectedException \RuntimeException + */ + public function testEnsuresCertExists() + { + $request = new Request('GET', Server::$url); + $this->emit($request); + $request->getConfig()->set('cert', __FILE__ . 'ewfwef'); + $f = new CurlFactory(); + $f(new Transaction(new Client(), $request), new MessageFactory()); + } + + /** + * @expectedException \RuntimeException + */ + public function testEnsuresKeyExists() + { + $request = new Request('GET', Server::$url); + $this->emit($request); + $request->getConfig()->set('ssl_key', __FILE__ . 'ewfwef'); + $f = new CurlFactory(); + $f(new Transaction(new Client(), $request), new MessageFactory()); + } + + /** + * @expectedException \RuntimeException + */ + public function testEnsuresCacertExists() + { + $request = new Request('GET', Server::$url); + $this->emit($request); + $request->getConfig()->set('verify', __FILE__ . 'ewfwef'); + $f = new CurlFactory(); + $f(new Transaction(new Client(), $request), new MessageFactory()); + } + + public function testClientUsesSslByDefault() + { + Server::flush(); + Server::enqueue(["HTTP/1.1 200 OK\r\nContent-Length: 3\r\n\r\nfoo"]); + $f = new CurlFactory(); + $client = new Client([ + 'base_url' => Server::$url, + 'adapter' => new MultiAdapter(new MessageFactory(), ['handle_factory' => $f]) + ]); + $client->get(); + $this->assertEquals(2, $_SERVER['last_curl'][CURLOPT_SSL_VERIFYHOST]); + $this->assertEquals(true, $_SERVER['last_curl'][CURLOPT_SSL_VERIFYPEER]); + $this->assertFileExists($_SERVER['last_curl'][CURLOPT_CAINFO]); + } + + public function testConvertsConstantNameKeysToValues() + { + $request = new Request('GET', Server::$url); + $request->getConfig()->set('curl', ['CURLOPT_USERAGENT' => 'foo']); + $this->emit($request); + $f = new CurlFactory(); + curl_close($f(new Transaction(new Client(), $request), new MessageFactory())); + $this->assertEquals('foo', $_SERVER['last_curl'][CURLOPT_USERAGENT]); + } + + public function testStripsFragment() + { + $request = new Request('GET', Server::$url . '#foo'); + $this->emit($request); + $f = new CurlFactory(); + curl_close($f(new Transaction(new Client(), $request), new MessageFactory())); + $this->assertEquals(Server::$url, $_SERVER['last_curl'][CURLOPT_URL]); + } + + public function testDoesNotSendSizeTwice() + { + $request = new Request('PUT', Server::$url, [], Stream::factory(str_repeat('a', 32769))); + $this->emit($request); + $f = new CurlFactory(); + curl_close($f(new Transaction(new Client(), $request), new MessageFactory())); + $this->assertEquals(32769, $_SERVER['last_curl'][CURLOPT_INFILESIZE]); + $this->assertNotContains('Content-Length', implode(' ', $_SERVER['last_curl'][CURLOPT_HTTPHEADER])); + } + + private function emit(RequestInterface $request) + { + $event = new BeforeEvent(new Transaction(new Client(), $request)); + $request->getEmitter()->emit('before', $event); + } + } +} diff --git a/core/vendor/guzzlehttp/guzzle/tests/Adapter/Curl/MultiAdapterTest.php b/core/vendor/guzzlehttp/guzzle/tests/Adapter/Curl/MultiAdapterTest.php new file mode 100644 index 00000000000..7477b53b9a9 --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/tests/Adapter/Curl/MultiAdapterTest.php @@ -0,0 +1,196 @@ +send($t); + $this->assertEquals(200, $response->getStatusCode()); + $this->assertEquals('bar', $response->getHeader('Foo')); + } + + public function testCanSetSelectTimeout() + { + $current = isset($_SERVER[MultiAdapter::ENV_SELECT_TIMEOUT]) + ? $_SERVER[MultiAdapter::ENV_SELECT_TIMEOUT]: null; + unset($_SERVER[MultiAdapter::ENV_SELECT_TIMEOUT]); + $a = new MultiAdapter(new MessageFactory()); + $this->assertEquals(1, $this->readAttribute($a, 'selectTimeout')); + $a = new MultiAdapter(new MessageFactory(), ['select_timeout' => 10]); + $this->assertEquals(10, $this->readAttribute($a, 'selectTimeout')); + $_SERVER[MultiAdapter::ENV_SELECT_TIMEOUT] = 2; + $a = new MultiAdapter(new MessageFactory()); + $this->assertEquals(2, $this->readAttribute($a, 'selectTimeout')); + $_SERVER[MultiAdapter::ENV_SELECT_TIMEOUT] = $current; + } + + /** + * @expectedException \GuzzleHttp\Exception\AdapterException + * @expectedExceptionMessage cURL error -2: + */ + public function testChecksCurlMultiResult() + { + MultiAdapter::throwMultiError(-2); + } + + public function testChecksForCurlException() + { + $request = new Request('GET', 'http://httbin.org'); + $transaction = $this->getMockBuilder('GuzzleHttp\Adapter\Transaction') + ->setMethods(['getRequest']) + ->disableOriginalConstructor() + ->getMock(); + $transaction->expects($this->exactly(2)) + ->method('getRequest') + ->will($this->returnValue($request)); + $context = $this->getMockBuilder('GuzzleHttp\Adapter\Curl\BatchContext') + ->setMethods(['throwsExceptions']) + ->disableOriginalConstructor() + ->getMock(); + $context->expects($this->once()) + ->method('throwsExceptions') + ->will($this->returnValue(true)); + $a = new MultiAdapter(new MessageFactory()); + $r = new \ReflectionMethod($a, 'isCurlException'); + $r->setAccessible(true); + try { + $r->invoke($a, $transaction, ['result' => -10], $context, []); + $this->fail('Did not throw'); + } catch (RequestException $e) { + $this->assertSame($request, $e->getRequest()); + $this->assertContains('[curl] (#-10) ', $e->getMessage()); + $this->assertContains($request->getUrl(), $e->getMessage()); + } + } + + public function testSendsParallelRequestsFromQueue() + { + $c = new Client(); + Server::flush(); + Server::enqueue([ + "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n", + "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n", + "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n", + "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n" + ]); + $transactions = [ + new Transaction($c, new Request('GET', Server::$url)), + new Transaction($c, new Request('PUT', Server::$url)), + new Transaction($c, new Request('HEAD', Server::$url)), + new Transaction($c, new Request('GET', Server::$url)) + ]; + $a = new MultiAdapter(new MessageFactory()); + $a->sendAll(new \ArrayIterator($transactions), 2); + foreach ($transactions as $t) { + $response = $t->getResponse(); + $this->assertNotNull($response); + $this->assertEquals(200, $response->getStatusCode()); + } + } + + public function testCreatesAndReleasesHandlesWhenNeeded() + { + $a = new MultiAdapter(new MessageFactory()); + $c = new Client([ + 'adapter' => $a, + 'base_url' => Server::$url + ]); + + Server::flush(); + Server::enqueue([ + "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n", + "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n", + "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n", + "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n", + "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n", + "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n", + "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n", + ]); + + $ef = function (ErrorEvent $e) { throw $e->getException(); }; + + $request1 = $c->createRequest('GET', '/'); + $request1->getEmitter()->on('headers', function () use ($a, $c, $ef) { + $a->send(new Transaction($c, $c->createRequest('GET', '/', [ + 'events' => [ + 'headers' => function () use ($a, $c, $ef) { + $r = $c->createRequest('GET', '/', [ + 'events' => ['error' => ['fn' => $ef, 'priority' => 9999]] + ]); + $r->getEmitter()->once('headers', function () use ($a, $c, $r) { + $a->send(new Transaction($c, $r)); + }); + $a->send(new Transaction($c, $r)); + // Now, reuse an existing handle + $a->send(new Transaction($c, $r)); + }, + 'error' => ['fn' => $ef, 'priority' => 9999] + ] + ]))); + }); + + $request1->getEmitter()->on('error', $ef); + + $transactions = [ + new Transaction($c, $request1), + new Transaction($c, $c->createRequest('PUT')), + new Transaction($c, $c->createRequest('HEAD')) + ]; + + $a->sendAll(new \ArrayIterator($transactions), 2); + + foreach ($transactions as $index => $t) { + $response = $t->getResponse(); + $this->assertInstanceOf( + 'GuzzleHttp\\Message\\ResponseInterface', + $response, + 'Transaction at index ' . $index . ' did not populate response' + ); + $this->assertEquals(200, $response->getStatusCode()); + } + } + + public function testThrowsAndReleasesWhenErrorDuringCompleteEvent() + { + Server::flush(); + Server::enqueue("HTTP/1.1 500 Internal Server Error\r\nContent-Length: 0\r\n\r\n"); + $request = new Request('GET', Server::$url); + $request->getEmitter()->on('complete', function (CompleteEvent $e) { + throw new RequestException('foo', $e->getRequest()); + }); + $t = new Transaction(new Client(), $request); + $a = new MultiAdapter(new MessageFactory()); + try { + $a->send($t); + $this->fail('Did not throw'); + } catch (RequestException $e) { + $this->assertSame($request, $e->getRequest()); + } + } +} diff --git a/core/vendor/guzzlehttp/guzzle/tests/Adapter/Curl/RequestMediatorTest.php b/core/vendor/guzzlehttp/guzzle/tests/Adapter/Curl/RequestMediatorTest.php new file mode 100644 index 00000000000..740ceaa1e52 --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/tests/Adapter/Curl/RequestMediatorTest.php @@ -0,0 +1,113 @@ +getEmitter()->on( + 'headers', + function (HeadersEvent $e) use (&$ee) { + $ee = $e; + } + ); + $t = new Transaction(new Client(), $request); + $m = new RequestMediator($t, new MessageFactory()); + $m->setResponseBody($body); + $this->assertEquals(18, $m->receiveResponseHeader(null, "HTTP/1.1 202 FOO\r\n")); + $this->assertEquals(10, $m->receiveResponseHeader(null, "Foo: Bar\r\n")); + $this->assertEquals(11, $m->receiveResponseHeader(null, "Baz : Bam\r\n")); + $this->assertEquals(19, $m->receiveResponseHeader(null, "Content-Length: 3\r\n")); + $this->assertEquals(2, $m->receiveResponseHeader(null, "\r\n")); + $this->assertNotNull($ee); + $this->assertEquals(202, $t->getResponse()->getStatusCode()); + $this->assertEquals('FOO', $t->getResponse()->getReasonPhrase()); + $this->assertEquals('Bar', $t->getResponse()->getHeader('Foo')); + $this->assertEquals('Bam', $t->getResponse()->getHeader('Baz')); + $m->writeResponseBody(null, 'foo'); + $this->assertEquals('foo', (string) $body); + $this->assertEquals('3', $t->getResponse()->getHeader('Content-Length')); + } + + public function testSendsToNewBodyWhenNot2xxResponse() + { + $body = Stream::factory(); + $request = new Request('GET', 'http://httbin.org'); + $t = new Transaction(new Client(), $request); + $m = new RequestMediator($t, new MessageFactory()); + $m->setResponseBody($body); + $this->assertEquals(27, $m->receiveResponseHeader(null, "HTTP/1.1 304 Not Modified\r\n")); + $this->assertEquals(2, $m->receiveResponseHeader(null, "\r\n")); + $this->assertEquals(304, $t->getResponse()->getStatusCode()); + $m->writeResponseBody(null, 'foo'); + $this->assertEquals('', (string) $body); + $this->assertEquals('foo', (string) $t->getResponse()->getBody()); + } + + public function testUsesDefaultBodyIfNoneSet() + { + $t = new Transaction(new Client(), new Request('GET', 'http://httbin.org')); + $t->setResponse(new Response(200)); + $m = new RequestMediator($t, new MessageFactory()); + $this->assertEquals(3, $m->writeResponseBody(null, 'foo')); + $this->assertEquals('foo', (string) $t->getResponse()->getBody()); + } + + public function testCanUseResponseBody() + { + $body = Stream::factory(); + $t = new Transaction(new Client(), new Request('GET', 'http://httbin.org')); + $t->setResponse(new Response(200, [], $body)); + $m = new RequestMediator($t, new MessageFactory()); + $this->assertEquals(3, $m->writeResponseBody(null, 'foo')); + $this->assertEquals('foo', (string) $body); + } + + public function testHandlesTransactionWithNoResponseWhenWritingBody() + { + $t = new Transaction(new Client(), new Request('GET', 'http://httbin.org')); + $m = new RequestMediator($t, new MessageFactory()); + $this->assertEquals(0, $m->writeResponseBody(null, 'test')); + } + + public function testReadsFromRequestBody() + { + $body = Stream::factory('foo'); + $t = new Transaction(new Client(), new Request('PUT', 'http://httbin.org', [], $body)); + $m = new RequestMediator($t, new MessageFactory()); + $this->assertEquals('foo', $m->readRequestBody(null, null, 3)); + } + + public function testEmitsHeadersEventForHeadRequest() + { + Server::enqueue(["HTTP/1.1 200 OK\r\nContent-Length: 2\r\n\r\nOK"]); + $ee = null; + $client = new Client(['adapter' => new MultiAdapter(new MessageFactory())]); + $client->head(Server::$url, [ + 'events' => [ + 'headers' => function (HeadersEvent $e) use (&$ee) { + $ee = $e; + } + ] + ]); + $this->assertInstanceOf('GuzzleHttp\\Event\\HeadersEvent', $ee); + } +} diff --git a/core/vendor/guzzlehttp/guzzle/tests/Adapter/FakeParallelAdapterTest.php b/core/vendor/guzzlehttp/guzzle/tests/Adapter/FakeParallelAdapterTest.php new file mode 100644 index 00000000000..8140d462d0c --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/tests/Adapter/FakeParallelAdapterTest.php @@ -0,0 +1,35 @@ +createRequest('GET', 'http://httbin.org'), + $client->createRequest('HEAD', 'http://httbin.org'), + ]; + + $sent = []; + $f = new FakeParallelAdapter(new MockAdapter(function ($trans) use (&$sent) { + $sent[] = $trans->getRequest()->getMethod(); + return new Response(200); + })); + + $tIter = new TransactionIterator($requests, $client, []); + $f->sendAll($tIter, 2); + $this->assertContains('GET', $sent); + $this->assertContains('HEAD', $sent); + } +} diff --git a/core/vendor/guzzlehttp/guzzle/tests/Adapter/MockAdapterTest.php b/core/vendor/guzzlehttp/guzzle/tests/Adapter/MockAdapterTest.php new file mode 100644 index 00000000000..07dbe0d587b --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/tests/Adapter/MockAdapterTest.php @@ -0,0 +1,103 @@ +setResponse($response); + $this->assertSame($response, $m->send(new Transaction(new Client(), new Request('GET', 'http://httbin.org')))); + } + + public function testMocksWithCallable() + { + $response = new Response(200); + $r = function (TransactionInterface $trans) use ($response) { + return $response; + }; + $m = new MockAdapter($r); + $this->assertSame($response, $m->send(new Transaction(new Client(), new Request('GET', 'http://httbin.org')))); + } + + /** + * @expectedException \RuntimeException + */ + public function testValidatesResponses() + { + $m = new MockAdapter(); + $m->setResponse('foo'); + $m->send(new Transaction(new Client(), new Request('GET', 'http://httbin.org'))); + } + + public function testHandlesErrors() + { + $m = new MockAdapter(); + $m->setResponse(new Response(404)); + $request = new Request('GET', 'http://httbin.org'); + $c = false; + $request->getEmitter()->once('complete', function (CompleteEvent $e) use (&$c) { + $c = true; + throw new RequestException('foo', $e->getRequest()); + }); + $request->getEmitter()->on('error', function (ErrorEvent $e) { + $e->intercept(new Response(201)); + }); + $r = $m->send(new Transaction(new Client(), $request)); + $this->assertTrue($c); + $this->assertEquals(201, $r->getStatusCode()); + } + + /** + * @expectedException \GuzzleHttp\Exception\RequestException + */ + public function testThrowsUnhandledErrors() + { + $m = new MockAdapter(); + $m->setResponse(new Response(404)); + $request = new Request('GET', 'http://httbin.org'); + $request->getEmitter()->once('complete', function (CompleteEvent $e) { + throw new RequestException('foo', $e->getRequest()); + }); + $m->send(new Transaction(new Client(), $request)); + } + + public function testReadsRequestBody() + { + $response = new Response(200); + $m = new MockAdapter($response); + $m->setResponse($response); + $body = Stream\create('foo'); + $request = new Request('PUT', 'http://httpbin.org/put', [], $body); + $this->assertSame($response, $m->send(new Transaction(new Client(), $request))); + $this->assertEquals(3, $body->tell()); + } + + public function testEmitsHeadersEvent() + { + $m = new MockAdapter(new Response(404)); + $request = new Request('GET', 'http://httbin.org'); + $called = false; + $request->getEmitter()->once('headers', function () use (&$called) { + $called = true; + }); + $m->send(new Transaction(new Client(), $request)); + $this->assertTrue($called); + } +} diff --git a/core/vendor/guzzlehttp/guzzle/tests/Adapter/StreamAdapterTest.php b/core/vendor/guzzlehttp/guzzle/tests/Adapter/StreamAdapterTest.php new file mode 100644 index 00000000000..b4ed7683bc8 --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/tests/Adapter/StreamAdapterTest.php @@ -0,0 +1,371 @@ + Server::$url, + 'adapter' => new StreamAdapter(new MessageFactory()) + ]); + $response = $client->get('/', ['headers' => ['Foo' => 'Bar']]); + $this->assertEquals(200, $response->getStatusCode()); + $this->assertEquals('OK', $response->getReasonPhrase()); + $this->assertEquals('Bar', $response->getHeader('Foo')); + $this->assertEquals('2', $response->getHeader('Content-Length')); + $this->assertEquals('hi', $response->getBody()); + $sent = Server::received(true)[0]; + $this->assertEquals('GET', $sent->getMethod()); + $this->assertEquals('/', $sent->getResource()); + $this->assertEquals('127.0.0.1:8124', $sent->getHeader('host')); + $this->assertEquals('Bar', $sent->getHeader('foo')); + $this->assertTrue($sent->hasHeader('user-agent')); + } + + /** + * @expectedException \GuzzleHttp\Exception\RequestException + * @expectedExceptionMessage Error creating resource. [url] http://localhost:123 [proxy] tcp://localhost:1234 + */ + public function testThrowsExceptionsCaughtDuringTransfer() + { + Server::flush(); + $client = new Client([ + 'adapter' => new StreamAdapter(new MessageFactory()), + ]); + $client->get('http://localhost:123', [ + 'timeout' => 0.01, + 'proxy' => 'tcp://localhost:1234' + ]); + } + + /** + * @expectedException \GuzzleHttp\Exception\RequestException + * @expectedExceptionMessage URL is invalid: ftp://localhost:123 + */ + public function testEnsuresTheHttpProtocol() + { + Server::flush(); + $client = new Client([ + 'adapter' => new StreamAdapter(new MessageFactory()), + ]); + $client->get('ftp://localhost:123'); + } + + public function testCanHandleExceptionsUsingEvents() + { + Server::flush(); + $client = new Client([ + 'adapter' => new StreamAdapter(new MessageFactory()) + ]); + $request = $client->createRequest('GET', Server::$url); + $mockResponse = new Response(200); + $request->getEmitter()->on( + 'error', + function (ErrorEvent $e) use ($mockResponse) { + $e->intercept($mockResponse); + } + ); + $this->assertSame($mockResponse, $client->send($request)); + } + + public function testEmitsAfterSendEvent() + { + $ee = null; + Server::flush(); + Server::enqueue( + "HTTP/1.1 200 OK\r\nFoo: Bar\r\nContent-Length: 8\r\n\r\nhi there" + ); + $client = new Client(['adapter' => new StreamAdapter(new MessageFactory())]); + $request = $client->createRequest('GET', Server::$url); + $request->getEmitter()->on('complete', function ($e) use (&$ee) { + $ee = $e; + }); + $client->send($request); + $this->assertInstanceOf('GuzzleHttp\Event\CompleteEvent', $ee); + $this->assertSame($request, $ee->getRequest()); + $this->assertEquals(200, $ee->getResponse()->getStatusCode()); + } + + public function testStreamAttributeKeepsStreamOpen() + { + Server::flush(); + Server::enqueue( + "HTTP/1.1 200 OK\r\nFoo: Bar\r\nContent-Length: 8\r\n\r\nhi there" + ); + $client = new Client([ + 'base_url' => Server::$url, + 'adapter' => new StreamAdapter(new MessageFactory()) + ]); + $response = $client->put('/foo', [ + 'headers' => ['Foo' => 'Bar'], + 'body' => 'test', + 'stream' => true + ]); + $this->assertEquals(200, $response->getStatusCode()); + $this->assertEquals('OK', $response->getReasonPhrase()); + $this->assertEquals('8', $response->getHeader('Content-Length')); + $body = $response->getBody(); + $this->assertEquals('http', $body->getMetadata()['wrapper_type']); + $this->assertEquals(8, $body->getMetadata()['unread_bytes']); + $this->assertEquals(Server::$url . 'foo', $body->getMetadata()['uri']); + $this->assertEquals('hi', $body->read(2)); + $body->close(); + + $sent = Server::received(true)[0]; + $this->assertEquals('PUT', $sent->getMethod()); + $this->assertEquals('/foo', $sent->getResource()); + $this->assertEquals('127.0.0.1:8124', $sent->getHeader('host')); + $this->assertEquals('Bar', $sent->getHeader('foo')); + $this->assertTrue($sent->hasHeader('user-agent')); + } + + public function testDrainsResponseIntoTempStream() + { + Server::flush(); + Server::enqueue("HTTP/1.1 200 OK\r\nFoo: Bar\r\nContent-Length: 8\r\n\r\nhi there"); + $client = new Client([ + 'base_url' => Server::$url, + 'adapter' => new StreamAdapter(new MessageFactory()) + ]); + $response = $client->get('/'); + $body = $response->getBody(); + $this->assertEquals('php://temp', $body->getMetadata()['uri']); + $this->assertEquals('hi', $body->read(2)); + $body->close(); + } + + public function testDrainsResponseIntoSaveToBody() + { + $r = fopen('php://temp', 'r+'); + Server::flush(); + Server::enqueue("HTTP/1.1 200 OK\r\nFoo: Bar\r\nContent-Length: 8\r\n\r\nhi there"); + $client = new Client([ + 'base_url' => Server::$url, + 'adapter' => new StreamAdapter(new MessageFactory()) + ]); + $response = $client->get('/', ['save_to' => $r]); + $body = $response->getBody(); + $this->assertEquals('php://temp', $body->getMetadata()['uri']); + $this->assertEquals('hi', $body->read(2)); + $this->assertEquals(' there', stream_get_contents($r)); + $body->close(); + } + + public function testDrainsResponseIntoSaveToBodyAtPath() + { + $tmpfname = tempnam('/tmp', 'save_to_path'); + Server::flush(); + Server::enqueue("HTTP/1.1 200 OK\r\nFoo: Bar\r\nContent-Length: 8\r\n\r\nhi there"); + $client = new Client([ + 'base_url' => Server::$url, + 'adapter' => new StreamAdapter(new MessageFactory()) + ]); + $response = $client->get('/', ['save_to' => $tmpfname]); + $body = $response->getBody(); + $this->assertEquals($tmpfname, $body->getMetadata()['uri']); + $this->assertEquals('hi', $body->read(2)); + $body->close(); + unlink($tmpfname); + } + + public function testAddsGzipFilterIfAcceptHeaderIsPresent() + { + Server::flush(); + Server::enqueue("HTTP/1.1 200 OK\r\nFoo: Bar\r\nContent-Length: 8\r\n\r\nhi there"); + $client = new Client([ + 'base_url' => Server::$url, + 'adapter' => new StreamAdapter(new MessageFactory()) + ]); + $response = $client->get('/', [ + 'headers' => ['Accept-Encoding' => 'gzip'], + 'stream' => true + ]); + $body = $response->getBody(); + $this->assertEquals('compress.zlib://http://127.0.0.1:8124/', $body->getMetadata()['uri']); + } + + protected function getStreamFromBody(Stream $body) + { + $r = new \ReflectionProperty($body, 'stream'); + $r->setAccessible(true); + + return $r->getValue($body); + } + + protected function getSendResult(array $opts) + { + Server::enqueue("HTTP/1.1 200 OK\r\nFoo: Bar\r\nContent-Length: 8\r\n\r\nhi there"); + $client = new Client(['adapter' => new StreamAdapter(new MessageFactory())]); + + return $client->get(Server::$url, $opts); + } + + public function testAddsProxy() + { + $body = $this->getSendResult(['stream' => true, 'proxy' => '127.0.0.1:8124'])->getBody(); + $opts = stream_context_get_options($this->getStreamFromBody($body)); + $this->assertEquals('127.0.0.1:8124', $opts['http']['proxy']); + } + + public function testAddsTimeout() + { + $body = $this->getSendResult(['stream' => true, 'timeout' => 200])->getBody(); + $opts = stream_context_get_options($this->getStreamFromBody($body)); + $this->assertEquals(200, $opts['http']['timeout']); + } + + /** + * @expectedException \RuntimeException + * @expectedExceptionMessage SSL certificate authority file not found: /does/not/exist + */ + public function testVerifiesVerifyIsValidIfPath() + { + (new Client([ + 'adapter' => new StreamAdapter(new MessageFactory()), + 'base_url' => Server::$url, + 'defaults' => ['verify' => '/does/not/exist'] + ]))->get('/'); + } + + public function testVerifyCanBeDisabled() + { + Server::enqueue("HTTP/1.1 200\r\nContent-Length: 0\r\n\r\n"); + (new Client([ + 'adapter' => new StreamAdapter(new MessageFactory()), + 'base_url' => Server::$url, + 'defaults' => ['verify' => false] + ]))->get('/'); + } + + public function testVerifyCanBeSetToPath() + { + $path = __DIR__ . '/../../src/cacert.pem'; + $this->assertFileExists($path); + $body = $this->getSendResult(['stream' => true, 'verify' => $path])->getBody(); + $opts = stream_context_get_options($this->getStreamFromBody($body)); + $this->assertEquals(true, $opts['http']['verify_peer']); + $this->assertEquals($path, $opts['http']['cafile']); + $this->assertTrue(file_exists($opts['http']['cafile'])); + } + + /** + * @expectedException \RuntimeException + * @expectedExceptionMessage SSL certificate not found: /does/not/exist + */ + public function testVerifiesCertIfValidPath() + { + (new Client([ + 'adapter' => new StreamAdapter(new MessageFactory()), + 'base_url' => Server::$url, + 'defaults' => ['cert' => '/does/not/exist'] + ]))->get('/'); + } + + public function testCanSetPasswordWhenSettingCert() + { + $path = __DIR__ . '/../../src/cacert.pem'; + $body = $this->getSendResult(['stream' => true, 'cert' => [$path, 'foo']])->getBody(); + $opts = stream_context_get_options($this->getStreamFromBody($body)); + $this->assertEquals($path, $opts['http']['local_cert']); + $this->assertEquals('foo', $opts['http']['passphrase']); + } + + public function testDebugAttributeWritesStreamInfoToTempBufferByDefault() + { + + Server::flush(); + Server::enqueue("HTTP/1.1 200 OK\r\nFoo: Bar\r\nContent-Length: 8\r\n\r\nhi there"); + $client = new Client([ + 'base_url' => Server::$url, + 'adapter' => new StreamAdapter(new MessageFactory()) + ]); + ob_start(); + $client->get('/', ['debug' => true]); + $contents = ob_get_clean(); + $this->assertContains(' [CONNECT]', $contents); + $this->assertContains(' [FILE_SIZE_IS]', $contents); + $this->assertContains(' [PROGRESS]', $contents); + } + + public function testDebugAttributeWritesStreamInfoToBuffer() + { + $buffer = fopen('php://temp', 'r+'); + Server::flush(); + Server::enqueue("HTTP/1.1 200 OK\r\nContent-Length: 8\r\nContent-Type: text/plain\r\n\r\nhi there"); + $client = new Client([ + 'base_url' => Server::$url, + 'adapter' => new StreamAdapter(new MessageFactory()) + ]); + $client->get('/', ['debug' => $buffer]); + fseek($buffer, 0); + $contents = stream_get_contents($buffer); + $this->assertContains(' [CONNECT]', $contents); + $this->assertContains(' [FILE_SIZE_IS] message: "Content-Length: 8"', $contents); + $this->assertContains(' [PROGRESS] bytes_max: "8"', $contents); + $this->assertContains(' [MIME_TYPE_IS] message: "text/plain"', $contents); + } + + public function testAddsProxyByProtocol() + { + $url = str_replace('http', 'tcp', Server::$url); + $body = $this->getSendResult(['stream' => true, 'proxy' => ['http' => $url]])->getBody(); + $opts = stream_context_get_options($this->getStreamFromBody($body)); + $this->assertEquals($url, $opts['http']['proxy']); + } + + public function testPerformsShallowMergeOfCustomContextOptions() + { + $body = $this->getSendResult([ + 'stream' => true, + 'config' => [ + 'stream_context' => [ + 'http' => [ + 'request_fulluri' => true, + 'method' => 'HEAD' + ], + 'socket' => [ + 'bindto' => '127.0.0.1:0' + ], + 'ssl' => [ + 'verify_peer' => false + ] + ] + ] + ])->getBody(); + + $opts = stream_context_get_options($this->getStreamFromBody($body)); + $this->assertEquals('HEAD', $opts['http']['method']); + $this->assertTrue($opts['http']['request_fulluri']); + $this->assertFalse($opts['ssl']['verify_peer']); + $this->assertEquals('127.0.0.1:0', $opts['socket']['bindto']); + } + + /** + * @expectedException \GuzzleHttp\Exception\RequestException + * @expectedExceptionMessage stream_context must be an array + */ + public function testEnsuresThatStreamContextIsAnArray() + { + $this->getSendResult([ + 'stream' => true, + 'config' => ['stream_context' => 'foo'] + ]); + } +} diff --git a/core/vendor/guzzlehttp/guzzle/tests/Adapter/StreamingProxyAdapterTest.php b/core/vendor/guzzlehttp/guzzle/tests/Adapter/StreamingProxyAdapterTest.php new file mode 100644 index 00000000000..8eb6e686149 --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/tests/Adapter/StreamingProxyAdapterTest.php @@ -0,0 +1,54 @@ +getMockBuilder('GuzzleHttp\Adapter\AdapterInterface') + ->setMethods(['send']) + ->getMockForAbstractClass(); + $mock->expects($this->once()) + ->method('send') + ->will($this->returnValue($response)); + $streaming = $this->getMockBuilder('GuzzleHttp\Adapter\AdapterInterface') + ->setMethods(['send']) + ->getMockForAbstractClass(); + $streaming->expects($this->never()) + ->method('send'); + + $s = new StreamingProxyAdapter($mock, $streaming); + $this->assertSame($response, $s->send(new Transaction(new Client(), new Request('GET', '/')))); + } + + public function testSendsWithStreamingAdapter() + { + $response = new Response(200); + $mock = $this->getMockBuilder('GuzzleHttp\Adapter\AdapterInterface') + ->setMethods(['send']) + ->getMockForAbstractClass(); + $mock->expects($this->never()) + ->method('send'); + $streaming = $this->getMockBuilder('GuzzleHttp\Adapter\AdapterInterface') + ->setMethods(['send']) + ->getMockForAbstractClass(); + $streaming->expects($this->once()) + ->method('send') + ->will($this->returnValue($response)); + $request = new Request('GET', '/'); + $request->getConfig()->set('stream', true); + $s = new StreamingProxyAdapter($mock, $streaming); + $this->assertSame($response, $s->send(new Transaction(new Client(), $request))); + } +} diff --git a/core/vendor/guzzlehttp/guzzle/tests/Adapter/TransactionIteratorTest.php b/core/vendor/guzzlehttp/guzzle/tests/Adapter/TransactionIteratorTest.php new file mode 100644 index 00000000000..c33b1757d5e --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/tests/Adapter/TransactionIteratorTest.php @@ -0,0 +1,172 @@ +createRequest('GET', 'http://test.com'), + $client->createRequest('POST', 'http://test.com'), + $client->createRequest('PUT', 'http://test.com'), + ]; + $t = new TransactionIterator($requests, $client, []); + $this->assertEquals(0, $t->key()); + $this->assertTrue($t->valid()); + $this->assertEquals('GET', $t->current()->getRequest()->getMethod()); + $t->next(); + $this->assertEquals(1, $t->key()); + $this->assertTrue($t->valid()); + $this->assertEquals('POST', $t->current()->getRequest()->getMethod()); + $t->next(); + $this->assertEquals(2, $t->key()); + $this->assertTrue($t->valid()); + $this->assertEquals('PUT', $t->current()->getRequest()->getMethod()); + } + + public function testCanForeach() + { + $c = new Client(); + $requests = [ + $c->createRequest('GET', 'http://test.com'), + $c->createRequest('POST', 'http://test.com'), + $c->createRequest('PUT', 'http://test.com'), + ]; + + $t = new TransactionIterator(new \ArrayIterator($requests), $c, []); + $methods = []; + + foreach ($t as $trans) { + $this->assertInstanceOf( + 'GuzzleHttp\Adapter\TransactionInterface', + $trans + ); + $methods[] = $trans->getRequest()->getMethod(); + } + + $this->assertEquals(['GET', 'POST', 'PUT'], $methods); + } + + /** + * @expectedException \RuntimeException + */ + public function testValidatesEachElement() + { + $c = new Client(); + $requests = ['foo']; + $t = new TransactionIterator(new \ArrayIterator($requests), $c, []); + iterator_to_array($t); + } + + public function testRegistersEvents() + { + $fn = function() {}; + $c = new Client(); + $requests = [$c->createRequest('GET', 'http://test.com')]; + $trans = new TransactionIterator(new \ArrayIterator($requests), $c, [ + 'before' => $fn, + 'complete' => $fn, + 'error' => $fn, + ]); + + $t = iterator_to_array($trans)[0]; + $em = $t->getRequest()->getEmitter(); + $this->assertSame($fn, $em->listeners('before')[0]); + $this->assertSame($fn, $em->listeners('complete')[2]); + $this->assertSame($fn, $em->listeners('error')[0]); + } + + public function testRegistersEventsWithPriorities() + { + $fn = function() {}; + $client = new Client(); + $requests = [$client->createRequest('GET', 'http://test.com')]; + $trans = new TransactionIterator( + new \ArrayIterator($requests), + $client, + [ + 'before' => [['fn' => $fn, 'priority' => 99]], + 'complete' => [['fn' => $fn, 'priority' => 99]], + 'error' => [['fn' => $fn, 'priority' => 99]] + ] + ); + + $t = iterator_to_array($trans)[0]; + $em = $t->getRequest()->getEmitter(); + $this->assertSame($fn, $em->listeners('before')[0]); + $this->assertSame($fn, $em->listeners('complete')[2]); + $this->assertSame($fn, $em->listeners('error')[0]); + } + + public function testRegistersMultipleEvents() + { + $fn = function() {}; + $c = new Client(); + $eventArray = [['fn' => $fn], ['fn' => $fn]]; + $requests = [$c->createRequest('GET', 'http://test.com')]; + $trans = new TransactionIterator(new \ArrayIterator($requests), $c, [ + 'before' => $eventArray, + 'complete' => $eventArray, + 'error' => $eventArray, + ]); + + $t = iterator_to_array($trans)[0]; + $em = $t->getRequest()->getEmitter(); + $this->assertSame($fn, $em->listeners('before')[0]); + $this->assertSame($fn, $em->listeners('before')[1]); + $this->assertSame($fn, $em->listeners('complete')[2]); + $this->assertSame($fn, $em->listeners('complete')[3]); + $this->assertSame($fn, $em->listeners('error')[0]); + $this->assertSame($fn, $em->listeners('error')[1]); + } + + public function testRegistersEventsWithOnce() + { + $called = 0; + $fn = function () use (&$called) { $called++; }; + $client = new Client(); + $requests = [$client->createRequest('GET', 'http://test.com')]; + // Remove an default listeners + foreach ($requests[0]->getEmitter()->listeners('before') as $l) { + $requests[0]->getEmitter()->removeListener('before', $l); + } + $trans = new TransactionIterator( + new \ArrayIterator($requests), + $client, + ['before' => [['fn' => $fn, 'once' => true]]] + ); + // Apply the listeners to the request + iterator_to_array($trans)[0]; + $ev = $this->getMockBuilder('GuzzleHttp\Event\BeforeEvent') + ->disableOriginalConstructor() + ->getMock(); + $requests[0]->getEmitter()->emit('before', $ev); + $requests[0]->getEmitter()->emit('before', $ev); + $this->assertEquals(1, $called); + } + + /** + * @expectedException \InvalidArgumentException + */ + public function testValidatesEvents() + { + $client = new Client(); + $requests = [$client->createRequest('GET', 'http://test.com')]; + new TransactionIterator(new \ArrayIterator($requests), $client, [ + 'before' => 'foo' + ]); + } +} diff --git a/core/vendor/guzzlehttp/guzzle/tests/Adapter/TransactionTest.php b/core/vendor/guzzlehttp/guzzle/tests/Adapter/TransactionTest.php new file mode 100644 index 00000000000..9b7ee1f7976 --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/tests/Adapter/TransactionTest.php @@ -0,0 +1,27 @@ +assertSame($c, $t->getClient()); + $this->assertSame($req, $t->getRequest()); + $this->assertNull($t->getResponse()); + $t->setResponse($response); + $this->assertSame($response, $t->getResponse()); + } +} diff --git a/core/vendor/guzzlehttp/guzzle/tests/ClientTest.php b/core/vendor/guzzlehttp/guzzle/tests/ClientTest.php new file mode 100644 index 00000000000..5f06c333c41 --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/tests/ClientTest.php @@ -0,0 +1,442 @@ +assertEquals(1, preg_match('#^Guzzle/.+ curl/.+ PHP/.+$#', Client::getDefaultUserAgent())); + } + + public function testUsesDefaultDefaultOptions() + { + $client = new Client(); + $this->assertTrue($client->getDefaultOption('allow_redirects')); + $this->assertTrue($client->getDefaultOption('exceptions')); + $this->assertContains('cacert.pem', $client->getDefaultOption('verify')); + } + + public function testUsesProvidedDefaultOptions() + { + $client = new Client([ + 'defaults' => [ + 'allow_redirects' => false, + 'query' => ['foo' => 'bar'] + ] + ]); + $this->assertFalse($client->getDefaultOption('allow_redirects')); + $this->assertTrue($client->getDefaultOption('exceptions')); + $this->assertContains('cacert.pem', $client->getDefaultOption('verify')); + $this->assertEquals(['foo' => 'bar'], $client->getDefaultOption('query')); + } + + public function testCanSpecifyBaseUrl() + { + $this->assertSame('', (new Client())->getBaseUrl()); + $this->assertEquals('http://foo', (new Client([ + 'base_url' => 'http://foo' + ]))->getBaseUrl()); + } + + public function testCanSpecifyBaseUrlUriTemplate() + { + $client = new Client(['base_url' => ['http://foo.com/{var}/', ['var' => 'baz']]]); + $this->assertEquals('http://foo.com/baz/', $client->getBaseUrl()); + } + + public function testClientUsesDefaultAdapterWhenNoneIsSet() + { + $client = new Client(); + if (!extension_loaded('curl')) { + $adapter = 'GuzzleHttp\Adapter\StreamAdapter'; + } elseif (ini_get('allow_url_fopen')) { + $adapter = 'GuzzleHttp\Adapter\StreamingProxyAdapter'; + } else { + $adapter = 'GuzzleHttp\Adapter\Curl\CurlAdapter'; + } + $this->assertInstanceOf($adapter, $this->readAttribute($client, 'adapter')); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage Foo + */ + public function testCanSpecifyAdapter() + { + $adapter = $this->getMockBuilder('GuzzleHttp\Adapter\AdapterInterface') + ->setMethods(['send']) + ->getMockForAbstractClass(); + $adapter->expects($this->once()) + ->method('send') + ->will($this->throwException(new \Exception('Foo'))); + $client = new Client(['adapter' => $adapter]); + $client->get('http://httpbin.org'); + } + + /** + * @expectedException \Exception + * @expectedExceptionMessage Foo + */ + public function testCanSpecifyMessageFactory() + { + $factory = $this->getMockBuilder('GuzzleHttp\Message\MessageFactoryInterface') + ->setMethods(['createRequest']) + ->getMockForAbstractClass(); + $factory->expects($this->once()) + ->method('createRequest') + ->will($this->throwException(new \Exception('Foo'))); + $client = new Client(['message_factory' => $factory]); + $client->get(); + } + + public function testAddsDefaultUserAgentHeaderWithDefaultOptions() + { + $client = new Client(['defaults' => ['allow_redirects' => false]]); + $this->assertFalse($client->getDefaultOption('allow_redirects')); + $this->assertEquals( + ['User-Agent' => Client::getDefaultUserAgent()], + $client->getDefaultOption('headers') + ); + } + + public function testAddsDefaultUserAgentHeaderWithoutDefaultOptions() + { + $client = new Client(); + $this->assertEquals( + ['User-Agent' => Client::getDefaultUserAgent()], + $client->getDefaultOption('headers') + ); + } + + private function getRequestClient() + { + $client = $this->getMockBuilder('GuzzleHttp\Client') + ->setMethods(['send']) + ->getMock(); + $client->expects($this->once()) + ->method('send') + ->will($this->returnArgument(0)); + + return $client; + } + + public function requestMethodProvider() + { + return [ + ['GET', false], + ['HEAD', false], + ['DELETE', false], + ['OPTIONS', false], + ['POST', 'foo'], + ['PUT', 'foo'], + ['PATCH', 'foo'] + ]; + } + + /** + * @dataProvider requestMethodProvider + */ + public function testClientProvidesMethodShortcut($method, $body) + { + $client = $this->getRequestClient(); + if ($body) { + $request = $client->{$method}('http://foo.com', [ + 'headers' => ['X-Baz' => 'Bar'], + 'body' => $body, + 'query' => ['a' => 'b'] + ]); + } else { + $request = $client->{$method}('http://foo.com', [ + 'headers' => ['X-Baz' => 'Bar'], + 'query' => ['a' => 'b'] + ]); + } + $this->assertEquals($method, $request->getMethod()); + $this->assertEquals('Bar', $request->getHeader('X-Baz')); + $this->assertEquals('a=b', $request->getQuery()); + if ($body) { + $this->assertEquals($body, $request->getBody()); + } + } + + public function testClientMergesDefaultOptionsWithRequestOptions() + { + $f = $this->getMockBuilder('GuzzleHttp\Message\MessageFactoryInterface') + ->setMethods(array('createRequest')) + ->getMockForAbstractClass(); + + $o = null; + // Intercept the creation + $f->expects($this->once()) + ->method('createRequest') + ->will($this->returnCallback( + function ($method, $url, array $options = []) use (&$o) { + $o = $options; + return (new MessageFactory())->createRequest($method, $url, $options); + } + )); + + $client = new Client([ + 'message_factory' => $f, + 'defaults' => [ + 'headers' => ['Foo' => 'Bar'], + 'query' => ['baz' => 'bam'], + 'exceptions' => false + ] + ]); + + $request = $client->createRequest('GET', 'http://foo.com?a=b', [ + 'headers' => ['Hi' => 'there', '1' => 'one'], + 'allow_redirects' => false, + 'query' => ['t' => 1] + ]); + + $this->assertFalse($o['allow_redirects']); + $this->assertFalse($o['exceptions']); + $this->assertEquals('Bar', $request->getHeader('Foo')); + $this->assertEquals('there', $request->getHeader('Hi')); + $this->assertEquals('one', $request->getHeader('1')); + $this->assertEquals('a=b&baz=bam&t=1', $request->getQuery()); + } + + public function testUsesBaseUrlWhenNoUrlIsSet() + { + $client = new Client(['base_url' => 'http://www.foo.com/baz?bam=bar']); + $this->assertEquals( + 'http://www.foo.com/baz?bam=bar', + $client->createRequest('GET')->getUrl() + ); + } + + public function testUsesBaseUrlCombinedWithProvidedUrl() + { + $client = new Client(['base_url' => 'http://www.foo.com/baz?bam=bar']); + $this->assertEquals( + 'http://www.foo.com/bar/bam', + $client->createRequest('GET', 'bar/bam')->getUrl() + ); + } + + public function testUsesBaseUrlCombinedWithProvidedUrlViaUriTemplate() + { + $client = new Client(['base_url' => 'http://www.foo.com/baz?bam=bar']); + $this->assertEquals( + 'http://www.foo.com/bar/123', + $client->createRequest('GET', ['bar/{bam}', ['bam' => '123']])->getUrl() + ); + } + + public function testSettingAbsoluteUrlOverridesBaseUrl() + { + $client = new Client(['base_url' => 'http://www.foo.com/baz?bam=bar']); + $this->assertEquals( + 'http://www.foo.com/foo', + $client->createRequest('GET', '/foo')->getUrl() + ); + } + + public function testSettingAbsoluteUriTemplateOverridesBaseUrl() + { + $client = new Client(['base_url' => 'http://www.foo.com/baz?bam=bar']); + $this->assertEquals( + 'http://goo.com/1', + $client->createRequest( + 'GET', + ['http://goo.com/{bar}', ['bar' => '1']] + )->getUrl() + ); + } + + public function testCanSetRelativeUrlStartingWithHttp() + { + $client = new Client(['base_url' => 'http://www.foo.com']); + $this->assertEquals( + 'http://www.foo.com/httpfoo', + $client->createRequest('GET', 'httpfoo')->getUrl() + ); + } + + public function testClientSendsRequests() + { + $response = new Response(200); + $adapter = new MockAdapter(); + $adapter->setResponse($response); + $client = new Client(['adapter' => $adapter]); + $this->assertSame($response, $client->get('http://test.com')); + $this->assertEquals('http://test.com', $response->getEffectiveUrl()); + } + + public function testSendingRequestCanBeIntercepted() + { + $response = new Response(200); + $response2 = new Response(200); + $adapter = new MockAdapter(); + $adapter->setResponse($response); + $client = new Client(['adapter' => $adapter]); + $client->getEmitter()->on( + 'before', + function (BeforeEvent $e) use ($response2) { + $e->intercept($response2); + } + ); + $this->assertSame($response2, $client->get('http://test.com')); + $this->assertEquals('http://test.com', $response2->getEffectiveUrl()); + } + + /** + * @expectedException \GuzzleHttp\Exception\RequestException + * @expectedExceptionMessage No response + */ + public function testEnsuresResponseIsPresentAfterSending() + { + $adapter = $this->getMockBuilder('GuzzleHttp\Adapter\MockAdapter') + ->setMethods(['send']) + ->getMock(); + $adapter->expects($this->once()) + ->method('send'); + $client = new Client(['adapter' => $adapter]); + $client->get('http://httpbin.org'); + } + + public function testClientHandlesErrorsDuringBeforeSend() + { + $client = new Client(); + $client->getEmitter()->on('before', function ($e) { + throw new \Exception('foo'); + }); + $client->getEmitter()->on('error', function ($e) { + $e->intercept(new Response(200)); + }); + $this->assertEquals(200, $client->get('http://test.com')->getStatusCode()); + } + + /** + * @expectedException \GuzzleHttp\Exception\RequestException + * @expectedExceptionMessage foo + */ + public function testClientHandlesErrorsDuringBeforeSendAndThrowsIfUnhandled() + { + $client = new Client(); + $client->getEmitter()->on('before', function ($e) { + throw new RequestException('foo', $e->getRequest()); + }); + $client->get('http://httpbin.org'); + } + + /** + * @expectedException \GuzzleHttp\Exception\RequestException + * @expectedExceptionMessage foo + */ + public function testClientWrapsExceptions() + { + $client = new Client(); + $client->getEmitter()->on('before', function ($e) { + throw new \Exception('foo'); + }); + $client->get('http://httpbin.org'); + } + + public function testCanSetDefaultValues() + { + $client = new Client(['foo' => 'bar']); + $client->setDefaultOption('headers/foo', 'bar'); + $this->assertNull($client->getDefaultOption('foo')); + $this->assertEquals('bar', $client->getDefaultOption('headers/foo')); + } + + public function testSendsAllInParallel() + { + $client = new Client(); + $client->getEmitter()->attach(new Mock([ + new Response(200), + new Response(201), + new Response(202), + ])); + $history = new History(); + $client->getEmitter()->attach($history); + + $requests = [ + $client->createRequest('GET', 'http://test.com'), + $client->createRequest('POST', 'http://test.com'), + $client->createRequest('PUT', 'http://test.com') + ]; + + $client->sendAll($requests); + $requests = array_map(function($r) { return $r->getMethod(); }, $history->getRequests()); + $this->assertContains('GET', $requests); + $this->assertContains('POST', $requests); + $this->assertContains('PUT', $requests); + } + + public function testCanSetCustomParallelAdapter() + { + $called = false; + $pa = new FakeParallelAdapter(new MockAdapter(function () use (&$called) { + $called = true; + return new Response(203); + })); + $client = new Client(['parallel_adapter' => $pa]); + $client->sendAll([$client->createRequest('GET', 'http://www.foo.com')]); + $this->assertTrue($called); + } + + public function testCanDisableAuthPerRequest() + { + $client = new Client(['defaults' => ['auth' => 'foo']]); + $request = $client->createRequest('GET', 'http://test.com'); + $this->assertEquals('foo', $request->getConfig()['auth']); + $request = $client->createRequest('GET', 'http://test.com', ['auth' => null]); + $this->assertFalse($request->getConfig()->hasKey('auth')); + } + + /** + * @expectedException \PHPUnit_Framework_Error_Deprecated + */ + public function testHasDeprecatedGetEmitter() + { + $client = new Client(); + $client->getEventDispatcher(); + } + + public function testUsesProxyEnvironmentVariables() + { + $http = isset($_SERVER['HTTP_PROXY']) ? $_SERVER['HTTP_PROXY'] : null; + $https = isset($_SERVER['HTTPS_PROXY']) ? $_SERVER['HTTPS_PROXY'] : null; + unset($_SERVER['HTTP_PROXY']); + unset($_SERVER['HTTPS_PROXY']); + + $client = new Client(); + $this->assertNull($client->getDefaultOption('proxy')); + + $_SERVER['HTTP_PROXY'] = '127.0.0.1'; + $client = new Client(); + $this->assertEquals( + ['http' => '127.0.0.1'], + $client->getDefaultOption('proxy') + ); + + $_SERVER['HTTPS_PROXY'] = '127.0.0.2'; + $client = new Client(); + $this->assertEquals( + ['http' => '127.0.0.1', 'https' => '127.0.0.2'], + $client->getDefaultOption('proxy') + ); + + $_SERVER['HTTP_PROXY'] = $http; + $_SERVER['HTTPS_PROXY'] = $https; + } +} diff --git a/core/vendor/guzzlehttp/guzzle/tests/CollectionTest.php b/core/vendor/guzzlehttp/guzzle/tests/CollectionTest.php new file mode 100644 index 00000000000..9e6155f7b39 --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/tests/CollectionTest.php @@ -0,0 +1,419 @@ +coll = new Collection(); + } + + public function testConstructorCanBeCalledWithNoParams() + { + $this->coll = new Collection(); + $p = $this->coll->toArray(); + $this->assertEmpty($p, '-> Collection must be empty when no data is passed'); + } + + public function testConstructorCanBeCalledWithParams() + { + $testData = array( + 'test' => 'value', + 'test_2' => 'value2' + ); + $this->coll = new Collection($testData); + $this->assertEquals($this->coll->toArray(), $testData); + $this->assertEquals($this->coll->toArray(), $this->coll->toArray()); + } + + public function testImplementsIteratorAggregate() + { + $this->coll->set('key', 'value'); + $this->assertInstanceOf('ArrayIterator', $this->coll->getIterator()); + $this->assertEquals(1, count($this->coll)); + $total = 0; + foreach ($this->coll as $key => $value) { + $this->assertEquals('key', $key); + $this->assertEquals('value', $value); + $total++; + } + $this->assertEquals(1, $total); + } + + public function testCanAddValuesToExistingKeysByUsingArray() + { + $this->coll->add('test', 'value1'); + $this->assertEquals($this->coll->toArray(), array('test' => 'value1')); + $this->coll->add('test', 'value2'); + $this->assertEquals($this->coll->toArray(), array('test' => array('value1', 'value2'))); + $this->coll->add('test', 'value3'); + $this->assertEquals($this->coll->toArray(), array('test' => array('value1', 'value2', 'value3'))); + } + + public function testHandlesMergingInDisparateDataSources() + { + $params = array( + 'test' => 'value1', + 'test2' => 'value2', + 'test3' => array('value3', 'value4') + ); + $this->coll->merge($params); + $this->assertEquals($this->coll->toArray(), $params); + + // Pass the same object to itself + $this->assertEquals($this->coll->merge($this->coll), $this->coll); + } + + public function testCanClearAllDataOrSpecificKeys() + { + $this->coll->merge(array( + 'test' => 'value1', + 'test2' => 'value2' + )); + + // Clear a specific parameter by name + $this->coll->remove('test'); + + $this->assertEquals($this->coll->toArray(), array( + 'test2' => 'value2' + )); + + // Clear all parameters + $this->coll->clear(); + + $this->assertEquals($this->coll->toArray(), array()); + } + + public function testProvidesKeys() + { + $this->assertEquals(array(), $this->coll->getKeys()); + $this->coll->merge(array( + 'test1' => 'value1', + 'test2' => 'value2' + )); + $this->assertEquals(array('test1', 'test2'), $this->coll->getKeys()); + // Returns the cached array previously returned + $this->assertEquals(array('test1', 'test2'), $this->coll->getKeys()); + $this->coll->remove('test1'); + $this->assertEquals(array('test2'), $this->coll->getKeys()); + $this->coll->add('test3', 'value3'); + $this->assertEquals(array('test2', 'test3'), $this->coll->getKeys()); + } + + public function testChecksIfHasKey() + { + $this->assertFalse($this->coll->hasKey('test')); + $this->coll->add('test', 'value'); + $this->assertEquals(true, $this->coll->hasKey('test')); + $this->coll->add('test2', 'value2'); + $this->assertEquals(true, $this->coll->hasKey('test')); + $this->assertEquals(true, $this->coll->hasKey('test2')); + $this->assertFalse($this->coll->hasKey('testing')); + $this->assertEquals(false, $this->coll->hasKey('AB-C', 'junk')); + } + + public function testChecksIfHasValue() + { + $this->assertFalse($this->coll->hasValue('value')); + $this->coll->add('test', 'value'); + $this->assertEquals('test', $this->coll->hasValue('value')); + $this->coll->add('test2', 'value2'); + $this->assertEquals('test', $this->coll->hasValue('value')); + $this->assertEquals('test2', $this->coll->hasValue('value2')); + $this->assertFalse($this->coll->hasValue('val')); + } + + public function testImplementsCount() + { + $data = new Collection(); + $this->assertEquals(0, $data->count()); + $data->add('key', 'value'); + $this->assertEquals(1, count($data)); + $data->add('key', 'value2'); + $this->assertEquals(1, count($data)); + $data->add('key_2', 'value3'); + $this->assertEquals(2, count($data)); + } + + public function testAddParamsByMerging() + { + $params = array( + 'test' => 'value1', + 'test2' => 'value2', + 'test3' => array('value3', 'value4') + ); + + // Add some parameters + $this->coll->merge($params); + + // Add more parameters by merging them in + $this->coll->merge(array( + 'test' => 'another', + 'different_key' => 'new value' + )); + + $this->assertEquals(array( + 'test' => array('value1', 'another'), + 'test2' => 'value2', + 'test3' => array('value3', 'value4'), + 'different_key' => 'new value' + ), $this->coll->toArray()); + } + + public function testAllowsFunctionalFilter() + { + $this->coll->merge(array( + 'fruit' => 'apple', + 'number' => 'ten', + 'prepositions' => array('about', 'above', 'across', 'after'), + 'same_number' => 'ten' + )); + + $filtered = $this->coll->filter(function($key, $value) { + return $value == 'ten'; + }); + + $this->assertNotSame($filtered, $this->coll); + + $this->assertEquals(array( + 'number' => 'ten', + 'same_number' => 'ten' + ), $filtered->toArray()); + } + + public function testAllowsFunctionalMapping() + { + $this->coll->merge(array( + 'number_1' => 1, + 'number_2' => 2, + 'number_3' => 3 + )); + + $mapped = $this->coll->map(function($key, $value) { + return $value * $value; + }); + + $this->assertNotSame($mapped, $this->coll); + + $this->assertEquals(array( + 'number_1' => 1, + 'number_2' => 4, + 'number_3' => 9 + ), $mapped->toArray()); + } + + public function testImplementsArrayAccess() + { + $this->coll->merge(array( + 'k1' => 'v1', + 'k2' => 'v2' + )); + + $this->assertTrue($this->coll->offsetExists('k1')); + $this->assertFalse($this->coll->offsetExists('Krull')); + + $this->coll->offsetSet('k3', 'v3'); + $this->assertEquals('v3', $this->coll->offsetGet('k3')); + $this->assertEquals('v3', $this->coll->get('k3')); + + $this->coll->offsetUnset('k1'); + $this->assertFalse($this->coll->offsetExists('k1')); + } + + public function testCanReplaceAllData() + { + $this->assertSame($this->coll, $this->coll->replace(array( + 'a' => '123' + ))); + + $this->assertEquals(array( + 'a' => '123' + ), $this->coll->toArray()); + } + + public function testPreparesFromConfig() + { + $c = Collection::fromConfig(array( + 'a' => '123', + 'base_url' => 'http://www.test.com/' + ), array( + 'a' => 'xyz', + 'b' => 'lol' + ), array('a')); + + $this->assertInstanceOf('GuzzleHttp\Collection', $c); + $this->assertEquals(array( + 'a' => '123', + 'b' => 'lol', + 'base_url' => 'http://www.test.com/' + ), $c->toArray()); + + try { + $c = Collection::fromConfig(array(), array(), array('a')); + $this->fail('Exception not throw when missing config'); + } catch (\InvalidArgumentException $e) { + } + } + + function falseyDataProvider() + { + return array( + array(false, false), + array(null, null), + array('', ''), + array(array(), array()), + array(0, 0), + ); + } + + /** + * @dataProvider falseyDataProvider + */ + public function testReturnsCorrectData($a, $b) + { + $c = new Collection(array('value' => $a)); + $this->assertSame($b, $c->get('value')); + } + + public function testRetrievesNestedKeysUsingPath() + { + $data = array( + 'foo' => 'bar', + 'baz' => array( + 'mesa' => array( + 'jar' => 'jar' + ) + ) + ); + $collection = new Collection($data); + $this->assertEquals('bar', $collection->getPath('foo')); + $this->assertEquals('jar', $collection->getPath('baz/mesa/jar')); + $this->assertNull($collection->getPath('wewewf')); + $this->assertNull($collection->getPath('baz/mesa/jar/jar')); + } + + public function testFalseyKeysStillDescend() + { + $collection = new Collection(array( + '0' => array( + 'a' => 'jar' + ), + 1 => 'other' + )); + $this->assertEquals('jar', $collection->getPath('0/a')); + $this->assertEquals('other', $collection->getPath('1')); + } + + public function getPathProvider() + { + $data = array( + 'foo' => 'bar', + 'baz' => array( + 'mesa' => array( + 'jar' => 'jar', + 'array' => array('a', 'b', 'c') + ), + 'bar' => array( + 'baz' => 'bam', + 'array' => array('d', 'e', 'f') + ) + ), + 'bam' => array( + array('foo' => 1), + array('foo' => 2), + array('array' => array('h', 'i')) + ) + ); + $c = new Collection($data); + + return array( + // Simple path selectors + array($c, 'foo', 'bar'), + array($c, 'baz', $data['baz']), + array($c, 'bam', $data['bam']), + array($c, 'baz/mesa', $data['baz']['mesa']), + array($c, 'baz/mesa/jar', 'jar'), + // Does not barf on missing keys + array($c, 'fefwfw', null), + array($c, 'baz/mesa/array', $data['baz']['mesa']['array']) + ); + } + + /** + * @dataProvider getPathProvider + */ + public function testGetPath(Collection $c, $path, $expected, $separator = '/') + { + $this->assertEquals($expected, $c->getPath($path, $separator)); + } + + public function testOverridesSettings() + { + $c = new Collection(array('foo' => 1, 'baz' => 2, 'bar' => 3)); + $c->overwriteWith(array('foo' => 10, 'bar' => 300)); + $this->assertEquals(array('foo' => 10, 'baz' => 2, 'bar' => 300), $c->toArray()); + } + + public function testOverwriteWithCollection() + { + $c = new Collection(array('foo' => 1, 'baz' => 2, 'bar' => 3)); + $b = new Collection(array('foo' => 10, 'bar' => 300)); + $c->overwriteWith($b); + $this->assertEquals(array('foo' => 10, 'baz' => 2, 'bar' => 300), $c->toArray()); + } + + public function testOverwriteWithTraversable() + { + $c = new Collection(array('foo' => 1, 'baz' => 2, 'bar' => 3)); + $b = new Collection(array('foo' => 10, 'bar' => 300)); + $c->overwriteWith($b->getIterator()); + $this->assertEquals(array('foo' => 10, 'baz' => 2, 'bar' => 300), $c->toArray()); + } + + public function testCanSetNestedPathValueThatDoesNotExist() + { + $c = new Collection(array()); + $c->setPath('foo/bar/baz/123', 'hi'); + $this->assertEquals('hi', $c['foo']['bar']['baz']['123']); + } + + public function testCanSetNestedPathValueThatExists() + { + $c = new Collection(array('foo' => array('bar' => 'test'))); + $c->setPath('foo/bar', 'hi'); + $this->assertEquals('hi', $c['foo']['bar']); + } + + /** + * @expectedException \RuntimeException + */ + public function testVerifiesNestedPathIsValidAtExactLevel() + { + $c = new Collection(array('foo' => 'bar')); + $c->setPath('foo/bar', 'hi'); + $this->assertEquals('hi', $c['foo']['bar']); + } + + /** + * @expectedException \RuntimeException + */ + public function testVerifiesThatNestedPathIsValidAtAnyLevel() + { + $c = new Collection(array('foo' => 'bar')); + $c->setPath('foo/bar/baz', 'test'); + } + + public function testCanAppendToNestedPathValues() + { + $c = new Collection(); + $c->setPath('foo/bar/[]', 'a'); + $c->setPath('foo/bar/[]', 'b'); + $this->assertEquals(['a', 'b'], $c['foo']['bar']); + } +} diff --git a/core/vendor/guzzlehttp/guzzle/tests/Cookie/CookieJarTest.php b/core/vendor/guzzlehttp/guzzle/tests/Cookie/CookieJarTest.php new file mode 100644 index 00000000000..795194636bb --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/tests/Cookie/CookieJarTest.php @@ -0,0 +1,325 @@ +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 testQuotesBadCookieValues() + { + $this->assertEquals('foo', CookieJar::getCookieValue('foo')); + $this->assertEquals('"foo,bar"', CookieJar::getCookieValue('foo,bar')); + } + + public function testCreatesFromArray() + { + $jar = CookieJar::fromArray([ + 'foo' => 'bar', + 'baz' => 'bam' + ], 'example.com'); + $this->assertCount(2, $jar); + } + + /** + * 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) { + $this->assertTrue($this->jar->setCookie($cookie)); + } + + $this->assertEquals(3, count($this->jar)); + $this->assertEquals(3, count($this->jar->getIterator())); + $this->assertEquals($cookies, $this->jar->getIterator()->getArrayCopy()); + } + + public function testRemovesTemporaryCookies() + { + $cookies = $this->getTestCookies(); + foreach ($this->getTestCookies() as $cookie) { + $this->jar->setCookie($cookie); + } + $this->jar->clearSessionCookies(); + $this->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'); + $this->assertEquals(2, count($this->jar)); + // Try again, removing no further cookies + $this->jar->clear('foo.com'); + $this->assertEquals(2, count($this->jar)); + + // Remove bar.com cookies with path of /boo + $this->jar->clear('bar.com', '/boo'); + $this->assertEquals(1, count($this->jar)); + + // Remove cookie by name + $this->jar->clear(null, null, 'test'); + $this->assertEquals(0, count($this->jar)); + } + + public function testDoesNotAddIncompleteCookies() + { + $this->assertEquals(false, $this->jar->setCookie(new SetCookie())); + $this->assertFalse($this->jar->setCookie(new SetCookie(array( + 'Name' => 'foo' + )))); + $this->assertFalse($this->jar->setCookie(new SetCookie(array( + 'Name' => false + )))); + $this->assertFalse($this->jar->setCookie(new SetCookie(array( + 'Name' => true + )))); + $this->assertFalse($this->jar->setCookie(new SetCookie(array( + 'Name' => 'foo', + 'Domain' => 'foo.com' + )))); + } + + public function testDoesAddValidCookies() + { + $this->assertTrue($this->jar->setCookie(new SetCookie(array( + 'Name' => 'foo', + 'Domain' => 'foo.com', + 'Value' => 0 + )))); + $this->assertTrue($this->jar->setCookie(new SetCookie(array( + 'Name' => 'foo', + 'Domain' => 'foo.com', + 'Value' => 0.0 + )))); + $this->assertTrue($this->jar->setCookie(new SetCookie(array( + 'Name' => 'foo', + 'Domain' => 'foo.com', + 'Value' => '0' + )))); + } + + public function testOverwritesCookiesThatAreOlderOrDiscardable() + { + $t = time() + 1000; + $data = array( + '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 + $this->assertTrue($this->jar->setCookie(new SetCookie($data))); + $this->assertEquals(1, count($this->jar)); + + $data['Discard'] = false; + $this->assertTrue($this->jar->setCookie(new SetCookie($data))); + $this->assertEquals(1, count($this->jar)); + + $c = $this->jar->getIterator()->getArrayCopy(); + $this->assertEquals(false, $c[0]->getDiscard()); + + // Make sure it doesn't duplicate the cookie + $this->jar->setCookie(new SetCookie($data)); + $this->assertEquals(1, count($this->jar)); + + // Make sure the more future-ful expiration date supersede the other + $data['Expires'] = time() + 2000; + $this->assertTrue($this->jar->setCookie(new SetCookie($data))); + $this->assertEquals(1, count($this->jar)); + $c = $this->jar->getIterator()->getArrayCopy(); + $this->assertNotEquals($t, $c[0]->getExpires()); + } + + public function testOverwritesCookiesThatHaveChanged() + { + $t = time() + 1000; + $data = array( + '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 + $this->assertTrue($this->jar->setCookie(new SetCookie($data))); + + $data['Value'] = 'boo'; + $this->assertTrue($this->jar->setCookie(new SetCookie($data))); + $this->assertEquals(1, count($this->jar)); + + // Changing the value plus a parameter also must overwrite the existing one + $data['Value'] = 'zoo'; + $data['Secure'] = false; + $this->assertTrue($this->jar->setCookie(new SetCookie($data))); + $this->assertEquals(1, count($this->jar)); + + $c = $this->jar->getIterator()->getArrayCopy(); + $this->assertEquals('zoo', $c[0]->getValue()); + } + + public function testAddsCookiesFromResponseWithRequest() + { + $response = new Response(200, array( + '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); + $this->assertEquals(1, count($this->jar)); + } + + public function getMatchingCookiesDataProvider() + { + return array( + array('https://example.com', 'foo=bar;baz=foobar'), + array('http://example.com', ''), + array('https://example.com:8912', 'foo=bar;baz=foobar'), + array('https://foo.example.com', 'foo=bar;baz=foobar'), + array('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); + $this->jar->addCookieHeader($request); + $this->assertEquals($cookies, $request->getHeader('Cookie')); + } + + /** + * @expectedException \RuntimeException + * @expectedExceptionMessage Invalid cookie: Cookie name must not cannot invalid 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); + } + $this->assertCount(4, $jar); + $jar->clear('bar.com', '/boo', 'other'); + $this->assertCount(3, $jar); + $names = array_map(function (SetCookie $c) { + return $c->getName(); + }, $jar->getIterator()->getArrayCopy()); + $this->assertEquals(['foo', 'test', 'you'], $names); + } +} diff --git a/core/vendor/guzzlehttp/guzzle/tests/Cookie/FileCookieJarTest.php b/core/vendor/guzzlehttp/guzzle/tests/Cookie/FileCookieJarTest.php new file mode 100644 index 00000000000..40431c40b5a --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/tests/Cookie/FileCookieJarTest.php @@ -0,0 +1,72 @@ +file = tempnam('/tmp', 'file-cookies'); + } + + /** + * @expectedException \RuntimeException + */ + public function testValidatesCookieFile() + { + file_put_contents($this->file, 'true'); + new FileCookieJar($this->file); + } + + public function testLoadsFromFileFile() + { + $jar = new FileCookieJar($this->file); + $this->assertEquals([], $jar->getIterator()->getArrayCopy()); + unlink($this->file); + } + + public function testPersistsToFileFile() + { + $jar = new FileCookieJar($this->file); + $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', + ])); + + $this->assertEquals(3, count($jar)); + unset($jar); + + // Make sure it wrote to the file + $contents = file_get_contents($this->file); + $this->assertNotEmpty($contents); + + // Load the cookieJar from the file + $jar = new FileCookieJar($this->file); + + // Weeds out temporary and session cookies + $this->assertEquals(2, count($jar)); + unset($jar); + unlink($this->file); + } +} diff --git a/core/vendor/guzzlehttp/guzzle/tests/Cookie/SetCookieTest.php b/core/vendor/guzzlehttp/guzzle/tests/Cookie/SetCookieTest.php new file mode 100644 index 00000000000..20cb23b7422 --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/tests/Cookie/SetCookieTest.php @@ -0,0 +1,364 @@ +assertEquals('/', $cookie->getPath()); + } + + public function testConvertsDateTimeMaxAgeToUnixTimestamp() + { + $cookie = new SetCookie(['Expires' => 'November 20, 1984']); + $this->assertInternalType('integer', $cookie->getExpires()); + } + + public function testAddsExpiresBasedOnMaxAge() + { + $t = time(); + $cookie = new SetCookie(['Max-Age' => 100]); + $this->assertEquals($t + 100, $cookie->getExpires()); + } + + public function testHoldsValues() + { + $t = time(); + $data = array( + '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); + $this->assertEquals($data, $cookie->toArray()); + + $this->assertEquals('foo', $cookie->getName()); + $this->assertEquals('baz', $cookie->getValue()); + $this->assertEquals('baz.com', $cookie->getDomain()); + $this->assertEquals('/bar', $cookie->getPath()); + $this->assertEquals($t, $cookie->getExpires()); + $this->assertEquals(100, $cookie->getMaxAge()); + $this->assertTrue($cookie->getSecure()); + $this->assertTrue($cookie->getDiscard()); + $this->assertTrue($cookie->getHttpOnly()); + $this->assertEquals('baz', $cookie->toArray()['foo']); + $this->assertEquals('bam', $cookie->toArray()['bar']); + + $cookie->setName('a') + ->setValue('b') + ->setPath('c') + ->setDomain('bar.com') + ->setExpires(10) + ->setMaxAge(200) + ->setSecure(false) + ->setHttpOnly(false) + ->setDiscard(false); + + $this->assertEquals('a', $cookie->getName()); + $this->assertEquals('b', $cookie->getValue()); + $this->assertEquals('c', $cookie->getPath()); + $this->assertEquals('bar.com', $cookie->getDomain()); + $this->assertEquals(10, $cookie->getExpires()); + $this->assertEquals(200, $cookie->getMaxAge()); + $this->assertFalse($cookie->getSecure()); + $this->assertFalse($cookie->getDiscard()); + $this->assertFalse($cookie->getHttpOnly()); + } + + public function testDeterminesIfExpired() + { + $c = new SetCookie(); + $c->setExpires(10); + $this->assertTrue($c->isExpired()); + $c->setExpires(time() + 10000); + $this->assertFalse($c->isExpired()); + } + + public function testMatchesDomain() + { + $cookie = new SetCookie(); + $this->assertTrue($cookie->matchesDomain('baz.com')); + + $cookie->setDomain('baz.com'); + $this->assertTrue($cookie->matchesDomain('baz.com')); + $this->assertFalse($cookie->matchesDomain('bar.com')); + + $cookie->setDomain('.baz.com'); + $this->assertTrue($cookie->matchesDomain('.baz.com')); + $this->assertTrue($cookie->matchesDomain('foo.baz.com')); + $this->assertFalse($cookie->matchesDomain('baz.bar.com')); + $this->assertTrue($cookie->matchesDomain('baz.com')); + + $cookie->setDomain('.127.0.0.1'); + $this->assertTrue($cookie->matchesDomain('127.0.0.1')); + + $cookie->setDomain('127.0.0.1'); + $this->assertTrue($cookie->matchesDomain('127.0.0.1')); + + $cookie->setDomain('.com.'); + $this->assertFalse($cookie->matchesDomain('baz.com')); + + $cookie->setDomain('.local'); + $this->assertTrue($cookie->matchesDomain('example.local')); + } + + public function testMatchesPath() + { + $cookie = new SetCookie(); + $this->assertTrue($cookie->matchesPath('/foo')); + + $cookie->setPath('/foo'); + $this->assertTrue($cookie->matchesPath('/foo')); + $this->assertTrue($cookie->matchesPath('/foo/bar')); + $this->assertFalse($cookie->matchesPath('/bar')); + } + + public function cookieValidateProvider() + { + return array( + array('foo', 'baz', 'bar', true), + array('0', '0', '0', true), + array('', 'baz', 'bar', 'The cookie name must not be empty'), + array('foo', '', 'bar', 'The cookie value must not be empty'), + array('foo', 'baz', '', 'The cookie domain must not be empty'), + array("foo\r", 'baz', '0', 'Cookie name must not cannot invalid characters: =,; \t\r\n\013\014'), + ); + } + + /** + * @dataProvider cookieValidateProvider + */ + public function testValidatesCookies($name, $value, $domain, $result) + { + $cookie = new SetCookie(array( + 'Name' => $name, + 'Value' => $value, + 'Domain' => $domain + )); + $this->assertSame($result, $cookie->validate()); + } + + public function testDoesNotMatchIp() + { + $cookie = new SetCookie(['Domain' => '192.168.16.']); + $this->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 + ]); + $this->assertEquals( + '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 array( + array( + 'ASIHTTPRequestTestCookie=This+is+the+value; expires=Sat, 26-Jul-2008 17:00:42 GMT; path=/tests; domain=allseeing-i.com; PHPSESSID=6c951590e7a9359bcedde25cda73e43c; path=/";', + array( + '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 + ) + ), + array('', []), + array('foo', []), + // Test setting a blank value for a cookie + array(array( + 'foo=', 'foo =', 'foo =;', 'foo= ;', 'foo =', 'foo= '), + array( + 'Name' => 'foo', + 'Value' => '', + 'Discard' => null, + 'Domain' => null, + 'Expires' => null, + 'Max-Age' => null, + 'Path' => '/', + 'Secure' => null, + 'HttpOnly' => false + ) + ), + // Test setting a value and removing quotes + array(array( + 'foo=1', 'foo =1', 'foo =1;', 'foo=1 ;', 'foo =1', 'foo= 1', 'foo = 1 ;', 'foo="1"', 'foo="1";', 'foo= "1";'), + array( + '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 + array( + 'justacookie=foo; domain=example.com', + array( + 'Name' => 'justacookie', + 'Value' => 'foo', + 'Domain' => 'example.com', + 'Discard' => null, + 'Expires' => null, + 'Max-Age' => null, + 'Path' => '/', + 'Secure' => null, + 'HttpOnly' => false + ) + ), + array( + 'expires=tomorrow; secure; path=/Space Out/; expires=Tue, 21-Nov-2006 08:33:44 GMT; domain=.example.com', + array( + '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 + ) + ), + array( + 'domain=unittests; expires=Tue, 21-Nov-2006 08:33:44 GMT; domain=example.com; path=/some value/', + array( + '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 + ) + ), + array( + 'path=indexAction; path=/; domain=.foo.com; expires=Tue, 21-Nov-2006 08:33:44 GMT', + array( + '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 + ) + ), + array( + 'secure=sha1; secure; SECURE; domain=some.really.deep.domain.com; version=1; Max-Age=86400', + array( + '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' + ) + ), + array( + 'PHPSESSID=123456789+abcd%2Cef; secure; discard; domain=.localdomain; path=/foo/baz; expires=Tue, 21-Nov-2006 08:33:44 GMT;', + array( + '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) { + $this->assertEquals($parsed[$key], $p[$key], 'Comparing ' . $key . ' ' . var_export($value, true) . ' : ' . var_export($parsed, true) . ' | ' . var_export($p, true)); + } + foreach ($p as $key => $value) { + $this->assertEquals($p[$key], $parsed[$key], 'Comparing ' . $key . ' ' . var_export($value, true) . ' : ' . var_export($parsed, true) . ' | ' . var_export($p, true)); + } + } else { + $this->assertEquals([ + 'Name' => null, + 'Value' => null, + 'Domain' => null, + 'Path' => '/', + 'Max-Age' => null, + 'Expires' => null, + 'Secure' => false, + 'Discard' => false, + 'HttpOnly' => false, + ], $p); + } + } + } +} diff --git a/core/vendor/guzzlehttp/guzzle/tests/Event/AbstractEventTest.php b/core/vendor/guzzlehttp/guzzle/tests/Event/AbstractEventTest.php new file mode 100644 index 00000000000..357a6a6f552 --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/tests/Event/AbstractEventTest.php @@ -0,0 +1,15 @@ +getMockBuilder('GuzzleHttp\Event\AbstractEvent') + ->getMockForAbstractClass(); + $this->assertFalse($e->isPropagationStopped()); + $e->stopPropagation(); + $this->assertTrue($e->isPropagationStopped()); + } +} diff --git a/core/vendor/guzzlehttp/guzzle/tests/Event/AbstractRequestEventTest.php b/core/vendor/guzzlehttp/guzzle/tests/Event/AbstractRequestEventTest.php new file mode 100644 index 00000000000..eeda4e4ffa4 --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/tests/Event/AbstractRequestEventTest.php @@ -0,0 +1,34 @@ +getMockBuilder('GuzzleHttp\Event\AbstractRequestEvent') + ->setConstructorArgs([$t]) + ->getMockForAbstractClass(); + $this->assertSame($t->getClient(), $e->getClient()); + $this->assertSame($t->getRequest(), $e->getRequest()); + } + + public function testHasTransaction() + { + $t = new Transaction(new Client(), new Request('GET', '/')); + $e = $this->getMockBuilder('GuzzleHttp\Event\AbstractRequestEvent') + ->setConstructorArgs([$t]) + ->getMockForAbstractClass(); + $r = new \ReflectionMethod($e, 'getTransaction'); + $r->setAccessible(true); + $this->assertSame($t, $r->invoke($e)); + } +} diff --git a/core/vendor/guzzlehttp/guzzle/tests/Event/AbstractTransferEventTest.php b/core/vendor/guzzlehttp/guzzle/tests/Event/AbstractTransferEventTest.php new file mode 100644 index 00000000000..418e555adab --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/tests/Event/AbstractTransferEventTest.php @@ -0,0 +1,25 @@ + 'bar']; + $t = new Transaction(new Client(), new Request('GET', '/')); + $e = $this->getMockBuilder('GuzzleHttp\Event\AbstractTransferEvent') + ->setConstructorArgs([$t, $s]) + ->getMockForAbstractClass(); + $this->assertNull($e->getTransferInfo('baz')); + $this->assertEquals('bar', $e->getTransferInfo('foo')); + $this->assertEquals($s, $e->getTransferInfo()); + } +} diff --git a/core/vendor/guzzlehttp/guzzle/tests/Event/EmitterTest.php b/core/vendor/guzzlehttp/guzzle/tests/Event/EmitterTest.php new file mode 100644 index 00000000000..431b60b1eb6 --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/tests/Event/EmitterTest.php @@ -0,0 +1,345 @@ +emitter = new Emitter(); + $this->listener = new TestEventListener(); + } + + protected function tearDown() + { + $this->emitter = null; + $this->listener = null; + } + + public function testInitialState() + { + $this->assertEquals(array(), $this->emitter->listeners()); + } + + public function testAddListener() + { + $this->emitter->on('pre.foo', array($this->listener, 'preFoo')); + $this->emitter->on('post.foo', array($this->listener, 'postFoo')); + $this->assertCount(1, $this->emitter->listeners(self::preFoo)); + $this->assertCount(1, $this->emitter->listeners(self::postFoo)); + $this->assertCount(2, $this->emitter->listeners()); + } + + public function testGetListenersSortsByPriority() + { + $listener1 = new TestEventListener(); + $listener2 = new TestEventListener(); + $listener3 = new TestEventListener(); + $listener1->name = '1'; + $listener2->name = '2'; + $listener3->name = '3'; + + $this->emitter->on('pre.foo', array($listener1, 'preFoo'), -10); + $this->emitter->on('pre.foo', array($listener2, 'preFoo'), 10); + $this->emitter->on('pre.foo', array($listener3, 'preFoo')); + + $expected = array( + array($listener2, 'preFoo'), + array($listener3, 'preFoo'), + array($listener1, 'preFoo'), + ); + + $this->assertSame($expected, $this->emitter->listeners('pre.foo')); + } + + public function testGetAllListenersSortsByPriority() + { + $listener1 = new TestEventListener(); + $listener2 = new TestEventListener(); + $listener3 = new TestEventListener(); + $listener4 = new TestEventListener(); + $listener5 = new TestEventListener(); + $listener6 = new TestEventListener(); + + $this->emitter->on('pre.foo', [$listener1, 'preFoo'], -10); + $this->emitter->on('pre.foo', [$listener2, 'preFoo']); + $this->emitter->on('pre.foo', [$listener3, 'preFoo'], 10); + $this->emitter->on('post.foo', [$listener4, 'preFoo'], -10); + $this->emitter->on('post.foo', [$listener5, 'preFoo']); + $this->emitter->on('post.foo', [$listener6, 'preFoo'], 10); + + $expected = [ + 'pre.foo' => [[$listener3, 'preFoo'], [$listener2, 'preFoo'], [$listener1, 'preFoo']], + 'post.foo' => [[$listener6, 'preFoo'], [$listener5, 'preFoo'], [$listener4, 'preFoo']], + ]; + + $this->assertSame($expected, $this->emitter->listeners()); + } + + public function testDispatch() + { + $this->emitter->on('pre.foo', array($this->listener, 'preFoo')); + $this->emitter->on('post.foo', array($this->listener, 'postFoo')); + $this->emitter->emit(self::preFoo, $this->getEvent()); + $this->assertTrue($this->listener->preFooInvoked); + $this->assertFalse($this->listener->postFooInvoked); + $this->assertInstanceOf('GuzzleHttp\Event\EventInterface', $this->emitter->emit(self::preFoo, $this->getEvent())); + $event = $this->getEvent(); + $return = $this->emitter->emit(self::preFoo, $event); + $this->assertSame($event, $return); + } + + public function testDispatchForClosure() + { + $invoked = 0; + $listener = function () use (&$invoked) { + $invoked++; + }; + $this->emitter->on('pre.foo', $listener); + $this->emitter->on('post.foo', $listener); + $this->emitter->emit(self::preFoo, $this->getEvent()); + $this->assertEquals(1, $invoked); + } + + public function testStopEventPropagation() + { + $otherListener = new TestEventListener(); + + // postFoo() stops the propagation, so only one listener should + // be executed + // Manually set priority to enforce $this->listener to be called first + $this->emitter->on('post.foo', array($this->listener, 'postFoo'), 10); + $this->emitter->on('post.foo', array($otherListener, 'preFoo')); + $this->emitter->emit(self::postFoo, $this->getEvent()); + $this->assertTrue($this->listener->postFooInvoked); + $this->assertFalse($otherListener->postFooInvoked); + } + + public function testDispatchByPriority() + { + $invoked = array(); + $listener1 = function () use (&$invoked) { + $invoked[] = '1'; + }; + $listener2 = function () use (&$invoked) { + $invoked[] = '2'; + }; + $listener3 = function () use (&$invoked) { + $invoked[] = '3'; + }; + $this->emitter->on('pre.foo', $listener1, -10); + $this->emitter->on('pre.foo', $listener2); + $this->emitter->on('pre.foo', $listener3, 10); + $this->emitter->emit(self::preFoo, $this->getEvent()); + $this->assertEquals(array('3', '2', '1'), $invoked); + } + + public function testRemoveListener() + { + $this->emitter->on('pre.bar', [$this->listener, 'preFoo']); + $this->assertNotEmpty($this->emitter->listeners(self::preBar)); + $this->emitter->removeListener('pre.bar', [$this->listener, 'preFoo']); + $this->assertEmpty($this->emitter->listeners(self::preBar)); + $this->emitter->removeListener('notExists', [$this->listener, 'preFoo']); + } + + public function testAddSubscriber() + { + $eventSubscriber = new TestEventSubscriber(); + $this->emitter->attach($eventSubscriber); + $this->assertNotEmpty($this->emitter->listeners(self::preFoo)); + $this->assertNotEmpty($this->emitter->listeners(self::postFoo)); + } + + public function testAddSubscriberWithPriorities() + { + $eventSubscriber = new TestEventSubscriber(); + $this->emitter->attach($eventSubscriber); + + $eventSubscriber = new TestEventSubscriberWithPriorities(); + $this->emitter->attach($eventSubscriber); + + $listeners = $this->emitter->listeners('pre.foo'); + $this->assertNotEmpty($this->emitter->listeners(self::preFoo)); + $this->assertCount(2, $listeners); + $this->assertInstanceOf('GuzzleHttp\Tests\Event\TestEventSubscriberWithPriorities', $listeners[0][0]); + } + + public function testdetach() + { + $eventSubscriber = new TestEventSubscriber(); + $this->emitter->attach($eventSubscriber); + $this->assertNotEmpty($this->emitter->listeners(self::preFoo)); + $this->assertNotEmpty($this->emitter->listeners(self::postFoo)); + $this->emitter->detach($eventSubscriber); + $this->assertEmpty($this->emitter->listeners(self::preFoo)); + $this->assertEmpty($this->emitter->listeners(self::postFoo)); + } + + public function testdetachWithPriorities() + { + $eventSubscriber = new TestEventSubscriberWithPriorities(); + $this->emitter->attach($eventSubscriber); + $this->assertNotEmpty($this->emitter->listeners(self::preFoo)); + $this->assertNotEmpty($this->emitter->listeners(self::postFoo)); + $this->emitter->detach($eventSubscriber); + $this->assertEmpty($this->emitter->listeners(self::preFoo)); + $this->assertEmpty($this->emitter->listeners(self::postFoo)); + } + + public function testEventReceivesEventNameAsArgument() + { + $listener = new TestWithDispatcher(); + $this->emitter->on('test', array($listener, 'foo')); + $this->assertNull($listener->name); + $this->emitter->emit('test', $this->getEvent()); + $this->assertEquals('test', $listener->name); + } + + /** + * @see https://bugs.php.net/bug.php?id=62976 + * + * This bug affects: + * - The PHP 5.3 branch for versions < 5.3.18 + * - The PHP 5.4 branch for versions < 5.4.8 + * - The PHP 5.5 branch is not affected + */ + public function testWorkaroundForPhpBug62976() + { + $dispatcher = new Emitter(); + $dispatcher->on('bug.62976', new CallableClass()); + $dispatcher->removeListener('bug.62976', function () {}); + $this->assertNotEmpty($dispatcher->listeners('bug.62976')); + } + + public function testRegistersEventsOnce() + { + $this->emitter->once('pre.foo', array($this->listener, 'preFoo')); + $this->emitter->on('pre.foo', array($this->listener, 'preFoo')); + $this->assertCount(2, $this->emitter->listeners(self::preFoo)); + $this->emitter->emit(self::preFoo, $this->getEvent()); + $this->assertTrue($this->listener->preFooInvoked); + $this->assertCount(1, $this->emitter->listeners(self::preFoo)); + } + + public function testReturnsEmptyArrayForNonExistentEvent() + { + $this->assertEquals([], $this->emitter->listeners('doesnotexist')); + } + + public function testCanAddFirstAndLastListeners() + { + $b = ''; + $this->emitter->on('foo', function() use (&$b) { $b .= 'a'; }, 'first'); // 1 + $this->emitter->on('foo', function() use (&$b) { $b .= 'b'; }, 'last'); // 0 + $this->emitter->on('foo', function() use (&$b) { $b .= 'c'; }, 'first'); // 2 + $this->emitter->on('foo', function() use (&$b) { $b .= 'd'; }, 'first'); // 3 + $this->emitter->on('foo', function() use (&$b) { $b .= 'e'; }, 'first'); // 4 + $this->emitter->on('foo', function() use (&$b) { $b .= 'f'; }); // 0 + $this->emitter->emit('foo', $this->getEvent()); + $this->assertEquals('edcabf', $b); + } + + /** + * @return \GuzzleHttp\Event\EventInterface + */ + private function getEvent() + { + return $this->getMockBuilder('GuzzleHttp\Event\AbstractEvent') + ->getMockForAbstractClass(); + } +} + +class CallableClass +{ + public function __invoke() + { + } +} + +class TestEventListener +{ + public $preFooInvoked = false; + public $postFooInvoked = false; + + /* Listener methods */ + + public function preFoo(EventInterface $e) + { + $this->preFooInvoked = true; + } + + public function postFoo(EventInterface $e) + { + $this->postFooInvoked = true; + + $e->stopPropagation(); + } + + /** + * @expectedException \PHPUnit_Framework_Error_Deprecated + */ + public function testHasDeprecatedAddListener() + { + $emitter = new Emitter(); + $emitter->addListener('foo', function () {}); + } + + /** + * @expectedException \PHPUnit_Framework_Error_Deprecated + */ + public function testHasDeprecatedAddSubscriber() + { + $emitter = new Emitter(); + $emitter->addSubscriber('foo', new TestEventSubscriber()); + } +} + +class TestWithDispatcher +{ + public $name; + + public function foo(EventInterface $e, $name) + { + $this->name = $name; + } +} + +class TestEventSubscriber extends TestEventListener implements SubscriberInterface +{ + public function getEvents() + { + return [ + 'pre.foo' => ['preFoo'], + 'post.foo' => ['postFoo'] + ]; + } +} + +class TestEventSubscriberWithPriorities extends TestEventListener implements SubscriberInterface +{ + public function getEvents() + { + return [ + 'pre.foo' => ['preFoo', 10], + 'post.foo' => ['postFoo'] + ]; + } +} diff --git a/core/vendor/guzzlehttp/guzzle/tests/Event/HasEmitterTraitTest.php b/core/vendor/guzzlehttp/guzzle/tests/Event/HasEmitterTraitTest.php new file mode 100644 index 00000000000..bfd0870e773 --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/tests/Event/HasEmitterTraitTest.php @@ -0,0 +1,28 @@ +getMockBuilder('GuzzleHttp\Tests\Event\AbstractHasEmitter') + ->getMockForAbstractClass(); + + $result = $mock->getEmitter(); + $this->assertInstanceOf('GuzzleHttp\Event\EmitterInterface', $result); + $result2 = $mock->getEmitter(); + $this->assertSame($result, $result2); + } +} diff --git a/core/vendor/guzzlehttp/guzzle/tests/Event/HeadersEventTest.php b/core/vendor/guzzlehttp/guzzle/tests/Event/HeadersEventTest.php new file mode 100644 index 00000000000..02db4dce3d3 --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/tests/Event/HeadersEventTest.php @@ -0,0 +1,39 @@ +setResponse($response); + $e = new HeadersEvent($t); + $this->assertSame($c, $e->getClient()); + $this->assertSame($r, $e->getRequest()); + $this->assertSame($response, $e->getResponse()); + } + + /** + * @expectedException \RuntimeException + */ + public function testEnsuresResponseIsSet() + { + $c = new Client(); + $r = new Request('GET', '/'); + $t = new Transaction($c, $r); + new HeadersEvent($t); + } +} diff --git a/core/vendor/guzzlehttp/guzzle/tests/Event/RequestAfterSendEventTest.php b/core/vendor/guzzlehttp/guzzle/tests/Event/RequestAfterSendEventTest.php new file mode 100644 index 00000000000..5b56a625764 --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/tests/Event/RequestAfterSendEventTest.php @@ -0,0 +1,27 @@ +intercept($res); + $this->assertTrue($e->isPropagationStopped()); + $this->assertSame($res, $e->getResponse()); + } +} diff --git a/core/vendor/guzzlehttp/guzzle/tests/Event/RequestBeforeSendEventTest.php b/core/vendor/guzzlehttp/guzzle/tests/Event/RequestBeforeSendEventTest.php new file mode 100644 index 00000000000..91590c8263b --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/tests/Event/RequestBeforeSendEventTest.php @@ -0,0 +1,29 @@ +getRequest()->getEmitter()->on('complete', function ($e) use (&$res) { + $res = $e; + }); + $e = new BeforeEvent($t); + $e->intercept($response); + $this->assertTrue($e->isPropagationStopped()); + $this->assertSame($res->getClient(), $e->getClient()); + } +} diff --git a/core/vendor/guzzlehttp/guzzle/tests/Event/RequestErrorEventTest.php b/core/vendor/guzzlehttp/guzzle/tests/Event/RequestErrorEventTest.php new file mode 100644 index 00000000000..14a27e7d873 --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/tests/Event/RequestErrorEventTest.php @@ -0,0 +1,41 @@ +assertSame($except, $event->getException()); + $this->assertSame($response, $event->getResponse()); + $this->assertSame($request, $event->getRequest()); + + $res = null; + $request->getEmitter()->on('complete', function ($e) use (&$res) { + $res = $e; + }); + + $good = new Response(200); + $event->intercept($good); + $this->assertTrue($event->isPropagationStopped()); + $this->assertSame($res->getClient(), $event->getClient()); + $this->assertSame($good, $res->getResponse()); + } +} diff --git a/core/vendor/guzzlehttp/guzzle/tests/Event/RequestEventsTest.php b/core/vendor/guzzlehttp/guzzle/tests/Event/RequestEventsTest.php new file mode 100644 index 00000000000..64c52dc92cf --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/tests/Event/RequestEventsTest.php @@ -0,0 +1,156 @@ +setResponse(new Response(200)); + $t->getRequest()->getEmitter()->on('complete', function ($e) use (&$res) { + $res = $e; + }); + RequestEvents::emitComplete($t); + $this->assertSame($res->getClient(), $t->getClient()); + $this->assertSame($res->getRequest(), $t->getRequest()); + $this->assertEquals('/', $t->getResponse()->getEffectiveUrl()); + } + + public function testEmitsAfterSendEventAndEmitsErrorIfNeeded() + { + $ex2 = $res = null; + $request = new Request('GET', '/'); + $t = new Transaction(new Client(), $request); + $t->setResponse(new Response(200)); + $ex = new RequestException('foo', $request); + $t->getRequest()->getEmitter()->on('complete', function ($e) use ($ex) { + $ex->e = $e; + throw $ex; + }); + $t->getRequest()->getEmitter()->on('error', function ($e) use (&$ex2) { + $ex2 = $e->getException(); + $e->stopPropagation(); + }); + RequestEvents::emitComplete($t); + $this->assertSame($ex, $ex2); + } + + public function testBeforeSendEmitsErrorEvent() + { + $ex = new \Exception('Foo'); + $client = new Client(); + $request = new Request('GET', '/'); + $response = new Response(200); + $t = new Transaction($client, $request); + $beforeCalled = $errCalled = 0; + + $request->getEmitter()->on( + 'before', + function (BeforeEvent $e) use ($request, $client, &$beforeCalled, $ex) { + $this->assertSame($request, $e->getRequest()); + $this->assertSame($client, $e->getClient()); + $beforeCalled++; + throw $ex; + } + ); + + $request->getEmitter()->on( + 'error', + function (ErrorEvent $e) use (&$errCalled, $response, $ex) { + $errCalled++; + $this->assertInstanceOf('GuzzleHttp\Exception\RequestException', $e->getException()); + $this->assertSame($ex, $e->getException()->getPrevious()); + $e->intercept($response); + } + ); + + RequestEvents::emitBefore($t); + $this->assertEquals(1, $beforeCalled); + $this->assertEquals(1, $errCalled); + $this->assertSame($response, $t->getResponse()); + } + + public function testThrowsUnInterceptedErrors() + { + $ex = new \Exception('Foo'); + $client = new Client(); + $request = new Request('GET', '/'); + $t = new Transaction($client, $request); + $errCalled = 0; + + $request->getEmitter()->on('before', function (BeforeEvent $e) use ($ex) { + throw $ex; + }); + + $request->getEmitter()->on('error', function (ErrorEvent $e) use (&$errCalled) { + $errCalled++; + }); + + try { + RequestEvents::emitBefore($t); + $this->fail('Did not throw'); + } catch (RequestException $e) { + $this->assertEquals(1, $errCalled); + } + } + + public function testDoesNotEmitErrorEventTwice() + { + $client = new Client(); + $mock = new Mock([new Response(500)]); + $client->getEmitter()->attach($mock); + + $r = []; + $client->getEmitter()->on('error', function (ErrorEvent $event) use (&$r) { + $r[] = $event->getRequest(); + }); + + try { + $client->get('http://foo.com'); + $this->fail('Did not throw'); + } catch (RequestException $e) { + $this->assertCount(1, $r); + } + } + + /** + * Note: Longest test name ever. + */ + public function testEmitsErrorEventForRequestExceptionsThrownDuringBeforeThatHaveNotEmittedAnErrorEvent() + { + $request = new Request('GET', '/'); + $ex = new RequestException('foo', $request); + + $client = new Client(); + $client->getEmitter()->on('before', function (BeforeEvent $event) use ($ex) { + throw $ex; + }); + $called = false; + $client->getEmitter()->on('error', function (ErrorEvent $event) use ($ex, &$called) { + $called = true; + $this->assertSame($ex, $event->getException()); + }); + + try { + $client->get('http://foo.com'); + $this->fail('Did not throw'); + } catch (RequestException $e) { + $this->assertTrue($called); + } + } +} diff --git a/core/vendor/guzzlehttp/guzzle/tests/Exception/ParseExceptionTest.php b/core/vendor/guzzlehttp/guzzle/tests/Exception/ParseExceptionTest.php new file mode 100644 index 00000000000..4ff9bfb6cec --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/tests/Exception/ParseExceptionTest.php @@ -0,0 +1,20 @@ +assertSame($res, $e->getResponse()); + $this->assertEquals('foo', $e->getMessage()); + } +} diff --git a/core/vendor/guzzlehttp/guzzle/tests/Exception/RequestExceptionTest.php b/core/vendor/guzzlehttp/guzzle/tests/Exception/RequestExceptionTest.php new file mode 100644 index 00000000000..cfa72696139 --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/tests/Exception/RequestExceptionTest.php @@ -0,0 +1,79 @@ +assertSame($req, $e->getRequest()); + $this->assertSame($res, $e->getResponse()); + $this->assertTrue($e->hasResponse()); + $this->assertEquals('foo', $e->getMessage()); + } + + public function testCreatesGenerateException() + { + $e = RequestException::create(new Request('GET', '/')); + $this->assertEquals('Error completing request', $e->getMessage()); + $this->assertInstanceOf('GuzzleHttp\Exception\RequestException', $e); + } + + public function testCreatesClientErrorResponseException() + { + $e = RequestException::create(new Request('GET', '/'), new Response(400)); + $this->assertEquals( + 'Client error response [url] / [status code] 400 [reason phrase] Bad Request', + $e->getMessage() + ); + $this->assertInstanceOf('GuzzleHttp\Exception\ClientException', $e); + } + + public function testCreatesServerErrorResponseException() + { + $e = RequestException::create(new Request('GET', '/'), new Response(500)); + $this->assertEquals( + 'Server error response [url] / [status code] 500 [reason phrase] Internal Server Error', + $e->getMessage() + ); + $this->assertInstanceOf('GuzzleHttp\Exception\ServerException', $e); + } + + public function testCreatesGenericErrorResponseException() + { + $e = RequestException::create(new Request('GET', '/'), new Response(600)); + $this->assertEquals( + 'Unsuccessful response [url] / [status code] 600 [reason phrase] ', + $e->getMessage() + ); + $this->assertInstanceOf('GuzzleHttp\Exception\RequestException', $e); + } + + public function testCanSetAndRetrieveErrorEmitted() + { + $e = RequestException::create(new Request('GET', '/'), new Response(600)); + $this->assertFalse($e->emittedError()); + $e->emittedError(true); + $this->assertTrue($e->emittedError()); + } + + /** + * @expectedException \InvalidArgumentException + */ + public function testCannotSetEmittedErrorToFalse() + { + $e = RequestException::create(new Request('GET', '/'), new Response(600)); + $e->emittedError(true); + $e->emittedError(false); + } +} diff --git a/core/vendor/guzzlehttp/guzzle/tests/FunctionsTest.php b/core/vendor/guzzlehttp/guzzle/tests/FunctionsTest.php new file mode 100644 index 00000000000..6e47b0cb8ff --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/tests/FunctionsTest.php @@ -0,0 +1,159 @@ +assertEquals('foo/123', \GuzzleHttp\uri_template('foo/{bar}', ['bar' => '123'])); + } + + public function noBodyProvider() + { + return [['get'], ['head'], ['delete']]; + } + + /** + * @dataProvider noBodyProvider + */ + public function testSendsNoBody($method) + { + Server::flush(); + Server::enqueue([new Response(200)]); + call_user_func("GuzzleHttp\\{$method}", Server::$url, [ + 'headers' => ['foo' => 'bar'], + 'query' => ['a' => '1'] + ]); + $sent = Server::received(true)[0]; + $this->assertEquals(strtoupper($method), $sent->getMethod()); + $this->assertEquals('/?a=1', $sent->getResource()); + $this->assertEquals('bar', $sent->getHeader('foo')); + } + + public function testSendsOptionsRequest() + { + Server::flush(); + Server::enqueue([new Response(200)]); + \GuzzleHttp\options(Server::$url, ['headers' => ['foo' => 'bar']]); + $sent = Server::received(true)[0]; + $this->assertEquals('OPTIONS', $sent->getMethod()); + $this->assertEquals('/', $sent->getResource()); + $this->assertEquals('bar', $sent->getHeader('foo')); + } + + public function hasBodyProvider() + { + return [['put'], ['post'], ['patch']]; + } + + /** + * @dataProvider hasBodyProvider + */ + public function testSendsWithBody($method) + { + Server::flush(); + Server::enqueue([new Response(200)]); + call_user_func("GuzzleHttp\\{$method}", Server::$url, [ + 'headers' => ['foo' => 'bar'], + 'body' => 'test', + 'query' => ['a' => '1'] + ]); + $sent = Server::received(true)[0]; + $this->assertEquals(strtoupper($method), $sent->getMethod()); + $this->assertEquals('/?a=1', $sent->getResource()); + $this->assertEquals('bar', $sent->getHeader('foo')); + $this->assertEquals('test', $sent->getBody()); + } + + /** + * @expectedException \PHPUnit_Framework_Error_Deprecated + * @expectedExceptionMessage GuzzleHttp\Tests\HasDeprecations::baz() is deprecated and will be removed in a future version. Update your code to use the equivalent GuzzleHttp\Tests\HasDeprecations::foo() method instead to avoid breaking changes when this shim is removed. + */ + public function testManagesDeprecatedMethods() + { + $d = new HasDeprecations(); + $d->baz(); + } + + /** + * @expectedException \BadMethodCallException + */ + public function testManagesDeprecatedMethodsAndHandlesMissingMethods() + { + $d = new HasDeprecations(); + $d->doesNotExist(); + } + + public function testBatchesRequests() + { + $client = new Client(); + $responses = [ + new Response(301, ['Location' => 'http://foo.com/bar']), + new Response(200), + new Response(200), + new Response(404) + ]; + $client->getEmitter()->attach(new Mock($responses)); + $requests = [ + $client->createRequest('GET', 'http://foo.com/baz'), + $client->createRequest('HEAD', 'http://httpbin.org/get'), + $client->createRequest('PUT', 'http://httpbin.org/put'), + ]; + + $a = $b = $c = 0; + $result = \GuzzleHttp\batch($client, $requests, [ + 'before' => function (BeforeEvent $e) use (&$a) { $a++; }, + 'complete' => function (CompleteEvent $e) use (&$b) { $b++; }, + 'error' => function (ErrorEvent $e) use (&$c) { $c++; }, + ]); + + $this->assertEquals(4, $a); + $this->assertEquals(2, $b); + $this->assertEquals(1, $c); + $this->assertCount(3, $result); + + foreach ($result as $i => $request) { + $this->assertSame($requests[$i], $request); + } + + // The first result is actually the second (redirect) response. + $this->assertSame($responses[1], $result[$requests[0]]); + // The second result is a 1:1 request:response map + $this->assertSame($responses[2], $result[$requests[1]]); + // The third entry is the 404 RequestException + $this->assertSame($responses[3], $result[$requests[2]]->getResponse()); + } + + /** + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage Invalid event format + */ + public function testBatchValidatesTheEventFormat() + { + $client = new Client(); + $requests = [$client->createRequest('GET', 'http://foo.com/baz')]; + \GuzzleHttp\batch($client, $requests, ['complete' => 'foo']); + } +} + +class HasDeprecations +{ + function foo() + { + return 'abc'; + } + function __call($name, $arguments) + { + return \GuzzleHttp\deprecation_proxy($this, $name, $arguments, [ + 'baz' => 'foo' + ]); + } +} diff --git a/core/vendor/guzzlehttp/guzzle/tests/Message/AbstractMessageTest.php b/core/vendor/guzzlehttp/guzzle/tests/Message/AbstractMessageTest.php new file mode 100644 index 00000000000..9ed91ee9a5f --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/tests/Message/AbstractMessageTest.php @@ -0,0 +1,273 @@ +assertEquals(1.1, $m->getProtocolVersion()); + } + + public function testHasHeaders() + { + $m = new Message(); + $this->assertFalse($m->hasHeader('foo')); + $m->addHeader('foo', 'bar'); + $this->assertTrue($m->hasHeader('foo')); + } + + public function testInitializesMessageWithProtocolVersionOption() + { + $m = new Request('GET', '/', [], null, [ + 'protocol_version' => '10' + ]); + $this->assertEquals(10, $m->getProtocolVersion()); + } + + public function testHasBody() + { + $m = new Message(); + $this->assertNull($m->getBody()); + $s = Stream::factory('test'); + $m->setBody($s); + $this->assertSame($s, $m->getBody()); + $this->assertFalse($m->hasHeader('Content-Length')); + } + + public function testCanRemoveBodyBySettingToNullAndRemovesCommonBodyHeaders() + { + $m = new Message(); + $m->setBody(Stream::factory('foo')); + $m->setHeader('Content-Length', 3)->setHeader('Transfer-Encoding', 'chunked'); + $m->setBody(null); + $this->assertNull($m->getBody()); + $this->assertFalse($m->hasHeader('Content-Length')); + $this->assertFalse($m->hasHeader('Transfer-Encoding')); + } + + public function testCastsToString() + { + $m = new Message(); + $m->setHeader('foo', 'bar'); + $m->setBody(Stream::factory('baz')); + $this->assertEquals("Foo!\r\nfoo: bar\r\n\r\nbaz", (string) $m); + } + + public function parseParamsProvider() + { + $res1 = array( + array( + '', + 'rel' => 'front', + 'type' => 'image/jpeg', + ), + array( + '', + 'rel' => 'back', + 'type' => 'image/jpeg', + ), + ); + + return array( + array( + '; rel="front"; type="image/jpeg", ; rel=back; type="image/jpeg"', + $res1 + ), + array( + '; rel="front"; type="image/jpeg",; rel=back; type="image/jpeg"', + $res1 + ), + array( + 'foo="baz"; bar=123, boo, test="123", foobar="foo;bar"', + array( + array('foo' => 'baz', 'bar' => '123'), + array('boo'), + array('test' => '123'), + array('foobar' => 'foo;bar') + ) + ), + array( + '; rel="side"; type="image/jpeg",; rel=side; type="image/jpeg"', + array( + array('', 'rel' => 'side', 'type' => 'image/jpeg'), + array('', 'rel' => 'side', 'type' => 'image/jpeg') + ) + ), + array( + '', + array() + ) + ); + } + + /** + * @dataProvider parseParamsProvider + */ + public function testParseParams($header, $result) + { + $request = new Request('GET', '/', ['foo' => $header]); + $this->assertEquals($result, Message::parseHeader($request, 'foo')); + } + + public function testAddsHeadersWhenNotPresent() + { + $h = new Message(); + $h->addHeader('foo', 'bar'); + $this->assertInternalType('string', $h->getHeader('foo')); + $this->assertEquals('bar', $h->getHeader('foo')); + } + + public function testAddsHeadersWhenPresentSameCase() + { + $h = new Message(); + $h->addHeader('foo', 'bar')->addHeader('foo', 'baz'); + $this->assertEquals('bar, baz', $h->getHeader('foo')); + $this->assertEquals(['bar', 'baz'], $h->getHeader('foo', true)); + } + + public function testAddsMultipleHeaders() + { + $h = new Message(); + $h->addHeaders([ + 'foo' => ' bar', + 'baz' => [' bam ', 'boo'] + ]); + $this->assertEquals([ + 'foo' => ['bar'], + 'baz' => ['bam', 'boo'] + ], $h->getHeaders()); + } + + public function testAddsHeadersWhenPresentDifferentCase() + { + $h = new Message(); + $h->addHeader('Foo', 'bar')->addHeader('fOO', 'baz'); + $this->assertEquals('bar, baz', $h->getHeader('foo')); + } + + public function testAddsHeadersWithArray() + { + $h = new Message(); + $h->addHeader('Foo', ['bar', 'baz']); + $this->assertEquals('bar, baz', $h->getHeader('foo')); + } + + /** + * @expectedException \InvalidArgumentException + */ + public function testThrowsExceptionWhenInvalidValueProvidedToAddHeader() + { + (new Message())->addHeader('foo', false); + } + + public function testGetHeadersReturnsAnArrayOfOverTheWireHeaderValues() + { + $h = new Message(); + $h->addHeader('foo', 'bar'); + $h->addHeader('Foo', 'baz'); + $h->addHeader('boO', 'test'); + $result = $h->getHeaders(); + $this->assertInternalType('array', $result); + $this->assertArrayHasKey('Foo', $result); + $this->assertArrayNotHasKey('foo', $result); + $this->assertArrayHasKey('boO', $result); + $this->assertEquals(['bar', 'baz'], $result['Foo']); + $this->assertEquals(['test'], $result['boO']); + } + + public function testSetHeaderOverwritesExistingValues() + { + $h = new Message(); + $h->setHeader('foo', 'bar'); + $this->assertEquals('bar', $h->getHeader('foo')); + $h->setHeader('Foo', 'baz'); + $this->assertEquals('baz', $h->getHeader('foo')); + $this->assertArrayHasKey('Foo', $h->getHeaders()); + } + + public function testSetHeaderOverwritesExistingValuesUsingHeaderArray() + { + $h = new Message(); + $h->setHeader('foo', ['bar']); + $this->assertEquals('bar', $h->getHeader('foo')); + } + + public function testSetHeaderOverwritesExistingValuesUsingArray() + { + $h = new Message(); + $h->setHeader('foo', ['bar']); + $this->assertEquals('bar', $h->getHeader('foo')); + } + + /** + * @expectedException \InvalidArgumentException + */ + public function testThrowsExceptionWhenInvalidValueProvidedToSetHeader() + { + (new Message())->setHeader('foo', false); + } + + public function testSetHeadersOverwritesAllHeaders() + { + $h = new Message(); + $h->setHeader('foo', 'bar'); + $h->setHeaders(['foo' => 'a', 'boo' => 'b']); + $this->assertEquals(['foo' => ['a'], 'boo' => ['b']], $h->getHeaders()); + } + + public function testChecksIfCaseInsensitiveHeaderIsPresent() + { + $h = new Message(); + $h->setHeader('foo', 'bar'); + $this->assertTrue($h->hasHeader('foo')); + $this->assertTrue($h->hasHeader('Foo')); + $h->setHeader('fOo', 'bar'); + $this->assertTrue($h->hasHeader('Foo')); + } + + public function testRemovesHeaders() + { + $h = new Message(); + $h->setHeader('foo', 'bar'); + $h->removeHeader('foo'); + $this->assertFalse($h->hasHeader('foo')); + $h->setHeader('Foo', 'bar'); + $h->removeHeader('FOO'); + $this->assertFalse($h->hasHeader('foo')); + } + + public function testReturnsCorrectTypeWhenMissing() + { + $h = new Message(); + $this->assertInternalType('string', $h->getHeader('foo')); + $this->assertInternalType('array', $h->getHeader('foo', true)); + } + + public function testSetsIntegersAndFloatsAsHeaders() + { + $h = new Message(); + $h->setHeader('foo', 10); + $h->setHeader('bar', 10.5); + $h->addHeader('foo', 10); + $h->addHeader('bar', 10.5); + $this->assertSame('10, 10', $h->getHeader('foo')); + $this->assertSame('10.5, 10.5', $h->getHeader('bar')); + } +} + +class Message extends AbstractMessage +{ + protected function getStartLine() + { + return 'Foo!'; + } +} diff --git a/core/vendor/guzzlehttp/guzzle/tests/Message/MessageFactoryTest.php b/core/vendor/guzzlehttp/guzzle/tests/Message/MessageFactoryTest.php new file mode 100644 index 00000000000..78cef277093 --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/tests/Message/MessageFactoryTest.php @@ -0,0 +1,458 @@ +createResponse(200, ['foo' => 'bar'], 'test', [ + 'protocol_version' => 1.0 + ]); + $this->assertEquals(200, $response->getStatusCode()); + $this->assertEquals(['foo' => ['bar']], $response->getHeaders()); + $this->assertEquals('test', $response->getBody()); + $this->assertEquals(1.0, $response->getProtocolVersion()); + } + + public function testCreatesRequestFromMessage() + { + $f = new MessageFactory(); + $req = $f->fromMessage("GET / HTTP/1.1\r\nBaz: foo\r\n\r\n"); + $this->assertEquals('GET', $req->getMethod()); + $this->assertEquals('/', $req->getPath()); + $this->assertEquals('foo', $req->getHeader('Baz')); + $this->assertNull($req->getBody()); + } + + public function testCreatesRequestFromMessageWithBody() + { + $req = (new MessageFactory())->fromMessage("GET / HTTP/1.1\r\nBaz: foo\r\n\r\ntest"); + $this->assertEquals('test', $req->getBody()); + } + + public function testCreatesRequestWithPostBody() + { + $req = (new MessageFactory())->createRequest('GET', 'http://www.foo.com', ['body' => ['abc' => '123']]); + $this->assertEquals('abc=123', $req->getBody()); + } + + public function testCreatesRequestWithPostBodyAndPostFiles() + { + $pf = fopen(__FILE__, 'r'); + $pfi = new PostFile('ghi', 'abc', __FILE__); + $req = (new MessageFactory())->createRequest('GET', 'http://www.foo.com', [ + 'body' => [ + 'abc' => '123', + 'def' => $pf, + 'ghi' => $pfi + ] + ]); + $this->assertInstanceOf('GuzzleHttp\Post\PostBody', $req->getBody()); + $s = (string) $req; + $this->assertContains('testCreatesRequestWithPostBodyAndPostFiles', $s); + $this->assertContains('multipart/form-data', $s); + $this->assertTrue(in_array($pfi, $req->getBody()->getFiles(), true)); + } + + public function testCreatesResponseFromMessage() + { + $response = (new MessageFactory)->fromMessage("HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\ntest"); + $this->assertEquals(200, $response->getStatusCode()); + $this->assertEquals('OK', $response->getReasonPhrase()); + $this->assertEquals('4', $response->getHeader('Content-Length')); + $this->assertEquals('test', $response->getBody(true)); + } + + public function testCanCreateHeadResponses() + { + $response = (new MessageFactory)->fromMessage("HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\n"); + $this->assertEquals(200, $response->getStatusCode()); + $this->assertEquals('OK', $response->getReasonPhrase()); + $this->assertEquals(null, $response->getBody()); + $this->assertEquals('4', $response->getHeader('Content-Length')); + } + + /** + * @expectedException \InvalidArgumentException + */ + public function testFactoryRequiresMessageForRequest() + { + (new MessageFactory)->fromMessage(''); + } + + /** + * @expectedException \InvalidArgumentException + * @expectedExceptionMessage foo + */ + public function testValidatesOptionsAreImplemented() + { + (new MessageFactory)->createRequest('GET', 'http://test.com', ['foo' => 'bar']); + } + + public function testOptionsAddsRequestOptions() + { + $request = (new MessageFactory)->createRequest( + 'GET', 'http://test.com', ['config' => ['baz' => 'bar']] + ); + $this->assertEquals('bar', $request->getConfig()->get('baz')); + } + + public function testCanDisableRedirects() + { + $request = (new MessageFactory)->createRequest('GET', '/', ['allow_redirects' => false]); + $this->assertEmpty($request->getEmitter()->listeners('complete')); + } + + /** + * @expectedException \InvalidArgumentException + */ + public function testValidatesRedirects() + { + (new MessageFactory)->createRequest('GET', '/', ['allow_redirects' => []]); + } + + public function testCanEnableStrictRedirectsAndSpecifyMax() + { + $request = (new MessageFactory)->createRequest('GET', '/', [ + 'allow_redirects' => ['max' => 10, 'strict' => true] + ]); + $this->assertTrue($request->getConfig()['redirect']['strict']); + $this->assertEquals(10, $request->getConfig()['redirect']['max']); + } + + public function testCanAddCookiesFromHash() + { + $request = (new MessageFactory)->createRequest('GET', 'http://www.test.com/', [ + 'cookies' => ['Foo' => 'Bar'] + ]); + $cookies = null; + foreach ($request->getEmitter()->listeners('before') as $l) { + if ($l[0] instanceof Cookie) { + $cookies = $l[0]; + break; + } + } + if (!$cookies) { + $this->fail('Did not add cookie listener'); + } else { + $this->assertCount(1, $cookies->getCookieJar()); + } + } + + public function testAddsCookieUsingTrue() + { + $factory = new MessageFactory(); + $request1 = $factory->createRequest('GET', '/', ['cookies' => true]); + $request2 = $factory->createRequest('GET', '/', ['cookies' => true]); + $listeners = function ($r) { + return array_filter($r->getEmitter()->listeners('before'), function ($l) { + return $l[0] instanceof Cookie; + }); + }; + $this->assertSame($listeners($request1), $listeners($request2)); + } + + public function testAddsCookieFromCookieJar() + { + $jar = new CookieJar(); + $request = (new MessageFactory)->createRequest('GET', '/', ['cookies' => $jar]); + foreach ($request->getEmitter()->listeners('before') as $l) { + if ($l[0] instanceof Cookie) { + $this->assertSame($jar, $l[0]->getCookieJar()); + } + } + } + + /** + * @expectedException \InvalidArgumentException + */ + public function testValidatesCookies() + { + (new MessageFactory)->createRequest('GET', '/', ['cookies' => 'baz']); + } + + public function testCanAddQuery() + { + $request = (new MessageFactory)->createRequest('GET', 'http://foo.com', [ + 'query' => ['Foo' => 'Bar'] + ]); + $this->assertEquals('Bar', $request->getQuery()->get('Foo')); + } + + /** + * @expectedException \InvalidArgumentException + */ + public function testValidatesQuery() + { + (new MessageFactory)->createRequest('GET', 'http://foo.com', [ + 'query' => 'foo' + ]); + } + + public function testCanSetDefaultQuery() + { + $request = (new MessageFactory)->createRequest('GET', 'http://foo.com?test=abc', [ + 'query' => ['Foo' => 'Bar', 'test' => 'def'] + ]); + $this->assertEquals('Bar', $request->getQuery()->get('Foo')); + $this->assertEquals('abc', $request->getQuery()->get('test')); + } + + public function testCanSetDefaultQueryWithObject() + { + $request = (new MessageFactory)->createRequest('GET', 'http://foo.com?test=abc', [ + 'query' => new Query(['Foo' => 'Bar', 'test' => 'def']) + ]); + $this->assertEquals('Bar', $request->getQuery()->get('Foo')); + $this->assertEquals('abc', $request->getQuery()->get('test')); + } + + public function testCanAddBasicAuth() + { + $request = (new MessageFactory)->createRequest('GET', 'http://foo.com', [ + 'auth' => ['michael', 'test'] + ]); + $this->assertTrue($request->hasHeader('Authorization')); + } + + public function testCanAddDigestAuth() + { + $request = (new MessageFactory)->createRequest('GET', 'http://foo.com', [ + 'auth' => ['michael', 'test', 'digest'] + ]); + $this->assertEquals('michael:test', $request->getConfig()->getPath('curl/' . CURLOPT_USERPWD)); + $this->assertEquals(CURLAUTH_DIGEST, $request->getConfig()->getPath('curl/' . CURLOPT_HTTPAUTH)); + } + + public function testCanDisableAuth() + { + $request = (new MessageFactory)->createRequest('GET', 'http://foo.com', [ + 'auth' => false + ]); + $this->assertFalse($request->hasHeader('Authorization')); + } + + public function testCanSetCustomAuth() + { + $request = (new MessageFactory)->createRequest('GET', 'http://foo.com', [ + 'auth' => 'foo' + ]); + $this->assertEquals('foo', $request->getConfig()['auth']); + } + + public function testCanAddEvents() + { + $foo = null; + $client = new Client(); + $client->getEmitter()->attach(new Mock([new Response(200)])); + $client->get('http://test.com', [ + 'events' => [ + 'before' => function () use (&$foo) { $foo = true; } + ] + ]); + $this->assertTrue($foo); + } + + public function testCanAddEventsWithPriority() + { + $foo = null; + $client = new Client(); + $client->getEmitter()->attach(new Mock(array(new Response(200)))); + $request = $client->createRequest('GET', 'http://test.com', [ + 'events' => [ + 'before' => [ + 'fn' => function () use (&$foo) { $foo = true; }, + 'priority' => 123 + ] + ] + ]); + $client->send($request); + $this->assertTrue($foo); + $l = $this->readAttribute($request->getEmitter(), 'listeners'); + $this->assertArrayHasKey(123, $l['before']); + } + + public function testCanAddEventsOnce() + { + $foo = 0; + $client = new Client(); + $client->getEmitter()->attach(new Mock([ + new Response(200), + new Response(200), + ])); + $fn = function () use (&$foo) { ++$foo; }; + $request = $client->createRequest('GET', 'http://test.com', [ + 'events' => ['before' => ['fn' => $fn, 'once' => true]] + ]); + $client->send($request); + $this->assertEquals(1, $foo); + $client->send($request); + $this->assertEquals(1, $foo); + } + + /** + * @expectedException \InvalidArgumentException + */ + public function testValidatesEventContainsFn() + { + $client = new Client(['base_url' => 'http://test.com']); + $client->createRequest('GET', '/', ['events' => ['before' => ['foo' => 'bar']]]); + } + + /** + * @expectedException \InvalidArgumentException + */ + public function testValidatesEventIsArray() + { + $client = new Client(['base_url' => 'http://test.com']); + $client->createRequest('GET', '/', ['events' => ['before' => '123']]); + } + + public function testCanAddSubscribers() + { + $mock = new Mock([new Response(200)]); + $client = new Client(); + $client->getEmitter()->attach($mock); + $request = $client->get('http://test.com', ['subscribers' => [$mock]]); + } + + public function testCanDisableExceptions() + { + $client = new Client(); + $this->assertEquals(500, $client->get('http://test.com', [ + 'subscribers' => [new Mock([new Response(500)])], + 'exceptions' => false + ])->getStatusCode()); + } + + public function testCanChangeSaveToLocation() + { + $saveTo = Stream::factory(); + $request = (new MessageFactory)->createRequest('GET', '/', ['save_to' => $saveTo]); + $this->assertSame($saveTo, $request->getConfig()->get('save_to')); + } + + public function testCanSetProxy() + { + $request = (new MessageFactory)->createRequest('GET', '/', ['proxy' => '192.168.16.121']); + $this->assertEquals('192.168.16.121', $request->getConfig()->get('proxy')); + } + + public function testCanSetHeadersOption() + { + $request = (new MessageFactory)->createRequest('GET', '/', ['headers' => ['Foo' => 'Bar']]); + $this->assertEquals('Bar', (string) $request->getHeader('Foo')); + } + + public function testCanSetHeaders() + { + $request = (new MessageFactory())->createRequest('GET', '/', [ + 'headers' => ['Foo' => ['Baz', 'Bar'], 'Test' => '123'] + ]); + $this->assertEquals('Baz, Bar', $request->getHeader('Foo')); + $this->assertEquals('123', $request->getHeader('Test')); + } + + public function testCanSetTimeoutOption() + { + $request = (new MessageFactory())->createRequest('GET', '/', ['timeout' => 1.5]); + $this->assertEquals(1.5, $request->getConfig()->get('timeout')); + } + + public function testCanSetConnectTimeoutOption() + { + $request = (new MessageFactory())->createRequest('GET', '/', ['connect_timeout' => 1.5]); + $this->assertEquals(1.5, $request->getConfig()->get('connect_timeout')); + } + + public function testCanSetDebug() + { + $request = (new MessageFactory())->createRequest('GET', '/', ['debug' => true]); + $this->assertTrue($request->getConfig()->get('debug')); + } + + public function testCanSetVerifyToOff() + { + $request = (new MessageFactory())->createRequest('GET', '/', ['verify' => false]); + $this->assertFalse($request->getConfig()->get('verify')); + } + + public function testCanSetVerifyToOn() + { + $request = (new MessageFactory())->createRequest('GET', '/', ['verify' => true]); + $this->assertTrue($request->getConfig()->get('verify')); + } + + public function testCanSetVerifyToPath() + { + $request = (new MessageFactory())->createRequest('GET', '/', ['verify' => '/foo.pem']); + $this->assertEquals('/foo.pem', $request->getConfig()->get('verify')); + } + + public function inputValidation() + { + return array_map(function ($option) { return array($option); }, array( + 'headers', 'events', 'subscribers', 'params' + )); + } + + /** + * @dataProvider inputValidation + * @expectedException \InvalidArgumentException + */ + public function testValidatesInput($option) + { + (new MessageFactory())->createRequest('GET', '/', [$option => 'foo']); + } + + public function testCanAddSslKey() + { + $request = (new MessageFactory())->createRequest('GET', '/', ['ssl_key' => '/foo.pem']); + $this->assertEquals('/foo.pem', $request->getConfig()->get('ssl_key')); + } + + public function testCanAddSslKeyPassword() + { + $request = (new MessageFactory())->createRequest('GET', '/', ['ssl_key' => ['/foo.pem', 'bar']]); + $this->assertEquals(['/foo.pem', 'bar'], $request->getConfig()->get('ssl_key')); + } + + public function testCanAddSslCert() + { + $request = (new MessageFactory())->createRequest('GET', '/', ['cert' => '/foo.pem']); + $this->assertEquals('/foo.pem', $request->getConfig()->get('cert')); + } + + public function testCanAddSslCertPassword() + { + $request = (new MessageFactory())->createRequest('GET', '/', ['cert' => ['/foo.pem', 'bar']]); + $this->assertEquals(['/foo.pem', 'bar'], $request->getConfig()->get('cert')); + } + + public function testCreatesBodyWithoutZeroString() + { + $request = (new MessageFactory())->createRequest('PUT', 'http://test.com', ['body' => '0']); + $this->assertSame('0', (string) $request->getBody()); + } + + public function testCanSetProtocolVersion() + { + $request = (new MessageFactory())->createRequest('GET', 'http://test.com', ['version' => 1.0]); + $this->assertEquals(1.0, $request->getProtocolVersion()); + } +} diff --git a/core/vendor/guzzlehttp/guzzle/tests/Message/MessageParserTest.php b/core/vendor/guzzlehttp/guzzle/tests/Message/MessageParserTest.php new file mode 100644 index 00000000000..0bcc9430f29 --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/tests/Message/MessageParserTest.php @@ -0,0 +1,276 @@ +compareRequestResults($parts, $parser->parseRequest($message)); + } + + /** + * @dataProvider responseProvider + */ + public function testParsesResponses($message, $parts) + { + $parser = new MessageParser(); + $this->compareResponseResults($parts, $parser->parseResponse($message)); + } + + public function testParsesRequestsWithMissingProtocol() + { + $parser = new MessageParser(); + $parts = $parser->parseRequest("GET /\r\nHost: Foo.com\r\n\r\n"); + $this->assertEquals('GET', $parts['method']); + $this->assertEquals('HTTP', $parts['protocol']); + $this->assertEquals('1.1', $parts['protocol_version']); + } + + public function testParsesRequestsWithMissingVersion() + { + $parser = new MessageParser(); + $parts = $parser->parseRequest("GET / HTTP\r\nHost: Foo.com\r\n\r\n"); + $this->assertEquals('GET', $parts['method']); + $this->assertEquals('HTTP', $parts['protocol']); + $this->assertEquals('1.1', $parts['protocol_version']); + } + + public function testParsesResponsesWithMissingReasonPhrase() + { + $parser = new MessageParser(); + $parts = $parser->parseResponse("HTTP/1.1 200\r\n\r\n"); + $this->assertEquals('200', $parts['code']); + $this->assertEquals('', $parts['reason_phrase']); + $this->assertEquals('HTTP', $parts['protocol']); + $this->assertEquals('1.1', $parts['protocol_version']); + } + + public function requestProvider() + { + $auth = base64_encode('michael:foo'); + + return array( + + // Empty request + array('', false), + + // Converts casing of request. Does not require host header. + array("GET / HTTP/1.1\r\n\r\n", array( + 'method' => 'GET', + 'protocol' => 'HTTP', + 'protocol_version' => '1.1', + 'request_url' => array( + 'scheme' => 'http', + 'host' => '', + 'port' => '', + 'path' => '/', + 'query' => '' + ), + 'headers' => array(), + 'body' => '' + )), + // Path and query string, multiple header values per header and case sensitive storage + array("HEAD /path?query=foo HTTP/1.0\r\nHost: example.com\r\nX-Foo: foo\r\nx-foo: Bar\r\nX-Foo: foo\r\nX-Foo: Baz\r\n\r\n", array( + 'method' => 'HEAD', + 'protocol' => 'HTTP', + 'protocol_version' => '1.0', + 'request_url' => array( + 'scheme' => 'http', + 'host' => 'example.com', + 'port' => '', + 'path' => '/path', + 'query' => 'query=foo' + ), + 'headers' => array( + 'Host' => 'example.com', + 'X-Foo' => array('foo', 'foo', 'Baz'), + 'x-foo' => 'Bar' + ), + 'body' => '' + )), + // Includes a body + array("PUT / HTTP/1.0\r\nhost: example.com:443\r\nContent-Length: 4\r\n\r\ntest", array( + 'method' => 'PUT', + 'protocol' => 'HTTP', + 'protocol_version' => '1.0', + 'request_url' => array( + 'scheme' => 'https', + 'host' => 'example.com', + 'port' => '443', + 'path' => '/', + 'query' => '' + ), + 'headers' => array( + 'host' => 'example.com:443', + 'Content-Length' => '4' + ), + 'body' => 'test' + )), + // Includes Authorization headers + array("GET / HTTP/1.1\r\nHost: example.com:8080\r\nAuthorization: Basic {$auth}\r\n\r\n", array( + 'method' => 'GET', + 'protocol' => 'HTTP', + 'protocol_version' => '1.1', + 'request_url' => array( + 'scheme' => 'http', + 'host' => 'example.com', + 'port' => '8080', + 'path' => '/', + 'query' => '' + ), + 'headers' => array( + 'Host' => 'example.com:8080', + 'Authorization' => "Basic {$auth}" + ), + 'body' => '' + )), + // Include authorization header + array("GET / HTTP/1.1\r\nHost: example.com:8080\r\nauthorization: Basic {$auth}\r\n\r\n", array( + 'method' => 'GET', + 'protocol' => 'HTTP', + 'protocol_version' => '1.1', + 'request_url' => array( + 'scheme' => 'http', + 'host' => 'example.com', + 'port' => '8080', + 'path' => '/', + 'query' => '' + ), + 'headers' => array( + 'Host' => 'example.com:8080', + 'authorization' => "Basic {$auth}" + ), + 'body' => '' + )), + ); + } + + public function responseProvider() + { + return array( + // Empty request + array('', false), + + array("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n", array( + 'protocol' => 'HTTP', + 'protocol_version' => '1.1', + 'code' => '200', + 'reason_phrase' => 'OK', + 'headers' => array( + 'Content-Length' => 0 + ), + 'body' => '' + )), + array("HTTP/1.0 400 Bad Request\r\nContent-Length: 0\r\n\r\n", array( + 'protocol' => 'HTTP', + 'protocol_version' => '1.0', + 'code' => '400', + 'reason_phrase' => 'Bad Request', + 'headers' => array( + 'Content-Length' => 0 + ), + 'body' => '' + )), + array("HTTP/1.0 100 Continue\r\n\r\n", array( + 'protocol' => 'HTTP', + 'protocol_version' => '1.0', + 'code' => '100', + 'reason_phrase' => 'Continue', + 'headers' => array(), + 'body' => '' + )), + array("HTTP/1.1 204 No Content\r\nX-Foo: foo\r\nx-foo: Bar\r\nX-Foo: foo\r\n\r\n", array( + 'protocol' => 'HTTP', + 'protocol_version' => '1.1', + 'code' => '204', + 'reason_phrase' => 'No Content', + 'headers' => array( + 'X-Foo' => array('foo', 'foo'), + 'x-foo' => 'Bar' + ), + 'body' => '' + )), + array("HTTP/1.1 200 Ok that is great!\r\nContent-Length: 4\r\n\r\nTest", array( + 'protocol' => 'HTTP', + 'protocol_version' => '1.1', + 'code' => '200', + 'reason_phrase' => 'Ok that is great!', + 'headers' => array( + 'Content-Length' => 4 + ), + 'body' => 'Test' + )), + ); + } + + public function compareRequestResults($result, $expected) + { + if (!$result) { + $this->assertFalse($expected); + return; + } + + $this->assertEquals($result['method'], $expected['method']); + $this->assertEquals($result['protocol'], $expected['protocol']); + $this->assertEquals($result['protocol_version'], $expected['protocol_version']); + $this->assertEquals($result['request_url'], $expected['request_url']); + $this->assertEquals($result['body'], $expected['body']); + $this->compareHttpHeaders($result['headers'], $expected['headers']); + } + + public function compareResponseResults($result, $expected) + { + if (!$result) { + $this->assertFalse($expected); + return; + } + + $this->assertEquals($result['protocol'], $expected['protocol']); + $this->assertEquals($result['protocol_version'], $expected['protocol_version']); + $this->assertEquals($result['code'], $expected['code']); + $this->assertEquals($result['reason_phrase'], $expected['reason_phrase']); + $this->assertEquals($result['body'], $expected['body']); + $this->compareHttpHeaders($result['headers'], $expected['headers']); + } + + protected function normalizeHeaders($headers) + { + $normalized = array(); + foreach ($headers as $key => $value) { + $key = strtolower($key); + if (!isset($normalized[$key])) { + $normalized[$key] = $value; + } elseif (!is_array($normalized[$key])) { + $normalized[$key] = array($value); + } else { + $normalized[$key][] = $value; + } + } + + foreach ($normalized as $key => &$value) { + if (is_array($value)) { + sort($value); + } + } + + return $normalized; + } + + public function compareHttpHeaders($result, $expected) + { + // Aggregate all headers case-insensitively + $result = $this->normalizeHeaders($result); + $expected = $this->normalizeHeaders($expected); + $this->assertEquals($result, $expected); + } +} diff --git a/core/vendor/guzzlehttp/guzzle/tests/Message/RequestTest.php b/core/vendor/guzzlehttp/guzzle/tests/Message/RequestTest.php new file mode 100644 index 00000000000..a117ef2a3d1 --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/tests/Message/RequestTest.php @@ -0,0 +1,120 @@ + '123'], Stream::factory('foo')); + $this->assertEquals('PUT', $r->getMethod()); + $this->assertEquals('/test', $r->getUrl()); + $this->assertEquals('123', $r->getHeader('test')); + $this->assertEquals('foo', $r->getBody()); + } + + public function testConstructorInitializesMessageWithProtocolVersion() + { + $r = new Request('GET', '', [], null, ['protocol_version' => 10]); + $this->assertEquals(10, $r->getProtocolVersion()); + } + + public function testConstructorInitializesMessageWithEmitter() + { + $e = new Emitter(); + $r = new Request('GET', '', [], null, ['emitter' => $e]); + $this->assertSame($r->getEmitter(), $e); + } + + public function testCloneIsDeep() + { + $r = new Request('GET', '/test', ['foo' => 'baz'], Stream::factory('foo')); + $r2 = clone $r; + + $this->assertNotSame($r->getEmitter(), $r2->getEmitter()); + $this->assertEquals('foo', $r2->getBody()); + + $r->getConfig()->set('test', 123); + $this->assertFalse($r2->getConfig()->hasKey('test')); + + $r->setPath('/abc'); + $this->assertEquals('/test', $r2->getPath()); + } + + public function testCastsToString() + { + $r = new Request('GET', 'http://test.com/test', ['foo' => 'baz'], Stream::factory('body')); + $s = explode("\r\n", (string) $r); + $this->assertEquals("GET /test HTTP/1.1", $s[0]); + $this->assertContains('Host: test.com', $s); + $this->assertContains('foo: baz', $s); + $this->assertContains('', $s); + $this->assertContains('body', $s); + } + + public function testSettingUrlOverridesHostHeaders() + { + $r = new Request('GET', 'http://test.com/test'); + $r->setUrl('https://baz.com/bar'); + $this->assertEquals('baz.com', $r->getHost()); + $this->assertEquals('baz.com', $r->getHeader('Host')); + $this->assertEquals('/bar', $r->getPath()); + $this->assertEquals('https', $r->getScheme()); + } + + public function testQueryIsMutable() + { + $r = new Request('GET', 'http://www.foo.com?baz=bar'); + $this->assertEquals('baz=bar', $r->getQuery()); + $this->assertInstanceOf('GuzzleHttp\Query', $r->getQuery()); + $r->getQuery()->set('hi', 'there'); + $this->assertEquals('/?baz=bar&hi=there', $r->getResource()); + } + + public function testQueryCanChange() + { + $r = new Request('GET', 'http://www.foo.com?baz=bar'); + $r->setQuery(new Query(['foo' => 'bar'])); + $this->assertEquals('foo=bar', $r->getQuery()); + } + + public function testCanChangeMethod() + { + $r = new Request('GET', 'http://www.foo.com'); + $r->setMethod('put'); + $this->assertEquals('PUT', $r->getMethod()); + } + + public function testCanChangeSchemeWithPort() + { + $r = new Request('GET', 'http://www.foo.com:80'); + $r->setScheme('https'); + $this->assertEquals('https://www.foo.com', $r->getUrl()); + } + + public function testCanChangeScheme() + { + $r = new Request('GET', 'http://www.foo.com'); + $r->setScheme('https'); + $this->assertEquals('https://www.foo.com', $r->getUrl()); + } + + public function testCanChangeHost() + { + $r = new Request('GET', 'http://www.foo.com:222'); + $r->setHost('goo'); + $this->assertEquals('http://goo:222', $r->getUrl()); + $this->assertEquals('goo:222', $r->getHeader('host')); + $r->setHost('goo:80'); + $this->assertEquals('http://goo', $r->getUrl()); + $this->assertEquals('goo', $r->getHeader('host')); + } +} diff --git a/core/vendor/guzzlehttp/guzzle/tests/Message/ResponseTest.php b/core/vendor/guzzlehttp/guzzle/tests/Message/ResponseTest.php new file mode 100644 index 00000000000..6dd0a70a930 --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/tests/Message/ResponseTest.php @@ -0,0 +1,103 @@ + 'hi!']); + $this->assertEquals(999, $response->getStatusCode()); + $this->assertEquals('hi!', $response->getReasonPhrase()); + } + + public function testConvertsToString() + { + $response = new Response(200); + $this->assertEquals("HTTP/1.1 200 OK\r\n\r\n", (string) $response); + // Add another header + $response = new Response(200, ['X-Test' => 'Guzzle']); + $this->assertEquals("HTTP/1.1 200 OK\r\nX-Test: Guzzle\r\n\r\n", (string) $response); + $response = new Response(200, ['Content-Length' => 4], Stream::factory('test')); + $this->assertEquals("HTTP/1.1 200 OK\r\nContent-Length: 4\r\n\r\ntest", (string) $response); + } + + public function testConvertsToStringAndSeeksToByteZero() + { + $response = new Response(200); + $s = Stream::factory('foo'); + $s->read(1); + $response->setBody($s); + $this->assertEquals("HTTP/1.1 200 OK\r\n\r\nfoo", (string) $response); + } + + public function testParsesJsonResponses() + { + $json = '{"foo": "bar"}'; + $response = new Response(200, [], Stream::factory($json)); + $this->assertEquals(['foo' => 'bar'], $response->json()); + $this->assertEquals(json_decode($json), $response->json(['object' => true])); + + $response = new Response(200); + $this->assertEquals(null, $response->json()); + } + + /** + * @expectedException \RuntimeException + * @expectedExceptionMessage Unable to parse response body into JSON: 4 + */ + public function testThrowsExceptionWhenFailsToParseJsonResponse() + { + $response = new Response(200, [], Stream::factory('{"foo": "')); + $response->json(); + } + + public function testParsesXmlResponses() + { + $response = new Response(200, [], Stream::factory('bar')); + $this->assertEquals('bar', (string) $response->xml()->foo); + // Always return a SimpleXMLElement from the xml method + $response = new Response(200); + $this->assertEmpty((string) $response->xml()->foo); + } + + /** + * @expectedException \GuzzleHttp\Exception\ParseException + * @expectedExceptionMessage Unable to parse response body into XML: String could not be parsed as XML + */ + public function testThrowsExceptionWhenFailsToParseXmlResponse() + { + $response = new Response(200, [], Stream::factory('xml(); + } + + public function testHasEffectiveUrl() + { + $r = new Response(200); + $this->assertNull($r->getEffectiveUrl()); + $r->setEffectiveUrl('http://www.test.com'); + $this->assertEquals('http://www.test.com', $r->getEffectiveUrl()); + } + + public function testPreventsComplexExternalEntities() + { + $xml = ']>&test;'; + $response = new Response(200, array(), Stream::factory($xml)); + + $oldCwd = getcwd(); + chdir(__DIR__); + try { + $xml = $response->xml(); + chdir($oldCwd); + $this->markTestIncomplete('Did not throw the expected exception! XML resolved as: ' . $xml->asXML()); + } catch (\Exception $e) { + chdir($oldCwd); + } + } +} diff --git a/core/vendor/guzzlehttp/guzzle/tests/MimetypesTest.php b/core/vendor/guzzlehttp/guzzle/tests/MimetypesTest.php new file mode 100644 index 00000000000..a18ec38136e --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/tests/MimetypesTest.php @@ -0,0 +1,31 @@ +assertEquals('text/x-php', Mimetypes::getInstance()->fromExtension('php')); + } + + public function testGetsFromFilename() + { + $this->assertEquals('text/x-php', Mimetypes::getInstance()->fromFilename(__FILE__)); + } + + public function testGetsFromCaseInsensitiveFilename() + { + $this->assertEquals('text/x-php', Mimetypes::getInstance()->fromFilename(strtoupper(__FILE__))); + } + + public function testReturnsNullWhenNoMatchFound() + { + $this->assertNull(Mimetypes::getInstance()->fromExtension('foobar')); + } +} diff --git a/core/vendor/guzzlehttp/guzzle/tests/Post/MultipartBodyTest.php b/core/vendor/guzzlehttp/guzzle/tests/Post/MultipartBodyTest.php new file mode 100644 index 00000000000..32ce7d18e14 --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/tests/Post/MultipartBodyTest.php @@ -0,0 +1,136 @@ + 'bar'], [ + new PostFile('foo', 'abc', 'foo.txt') + ], 'abcdef'); + } + + public function testConstructorAddsFieldsAndFiles() + { + $b = $this->getTestBody(); + $this->assertEquals('abcdef', $b->getBoundary()); + $c = (string) $b; + $this->assertContains("--abcdef\r\nContent-Disposition: form-data; name=\"foo\"\r\n\r\nbar\r\n", $c); + $this->assertContains("--abcdef\r\nContent-Disposition: form-data; filename=\"foo.txt\"; name=\"foo\"\r\n" + . "Content-Type: text/plain\r\n\r\nabc\r\n--abcdef--", $c); + } + + /** + * @expectedException \InvalidArgumentException + */ + public function testConstructorValidatesFiles() + { + new MultipartBody([], ['bar']); + } + + public function testConstructorCanCreateBoundary() + { + $b = new MultipartBody(); + $this->assertNotNull($b->getBoundary()); + } + + public function testWrapsStreamMethods() + { + $b = $this->getTestBody(); + $this->assertFalse($b->write('foo')); + $this->assertFalse($b->isWritable()); + $this->assertTrue($b->isReadable()); + $this->assertTrue($b->isSeekable()); + $this->assertEquals(0, $b->tell()); + } + + public function testCanDetachFieldsAndFiles() + { + $b = $this->getTestBody(); + $b->detach(); + $b->close(); + $this->assertEquals('', (string) $b); + } + + public function testCanOnlySeekTo0() + { + $b = new MultipartBody(); + $this->assertFalse($b->seek(10)); + } + + public function testIsSeekableReturnsTrueIfAllAreSeekable() + { + $s = $this->getMockBuilder('GuzzleHttp\Stream\StreamInterface') + ->setMethods(['isSeekable']) + ->getMockForAbstractClass(); + $s->expects($this->once()) + ->method('isSeekable') + ->will($this->returnValue(false)); + $p = new PostFile('foo', $s, 'foo.php'); + $b = new MultipartBody([], [$p]); + $this->assertFalse($b->isSeekable()); + $this->assertFalse($b->seek(10)); + } + + /** + * @expectedException \RuntimeException + */ + public function testThrowsExceptionWhenStreamFailsToRewind() + { + $s = $this->getMockBuilder('GuzzleHttp\Stream\StreamInterface') + ->setMethods(['seek', 'isSeekable']) + ->getMockForAbstractClass(); + $s->expects($this->once()) + ->method('isSeekable') + ->will($this->returnValue(true)); + $s->expects($this->once()) + ->method('seek') + ->will($this->returnValue(false)); + $b = new MultipartBody([], [new PostFile('foo', $s, 'foo.php')]); + $b->seek(0); + } + + public function testGetContentsCanCap() + { + $b = $this->getTestBody(); + $c = (string) $b; + $b->seek(0); + $this->assertSame(substr($c, 0, 10), $b->getContents(10)); + } + + public function testReadsFromBuffer() + { + $b = $this->getTestBody(); + $c = $b->read(1); + $c .= $b->read(1); + $c .= $b->read(1); + $c .= $b->read(1); + $c .= $b->read(1); + $this->assertEquals('--abc', $c); + } + + public function testCalculatesSize() + { + $b = $this->getTestBody(); + $this->assertEquals(strlen($b), $b->getSize()); + } + + public function testCalculatesSizeAndReturnsNullForUnknown() + { + $s = $this->getMockBuilder('GuzzleHttp\Stream\StreamInterface') + ->setMethods(['getSize']) + ->getMockForAbstractClass(); + $s->expects($this->once()) + ->method('getSize') + ->will($this->returnValue(null)); + $b = new MultipartBody([], [new PostFile('foo', $s, 'foo.php')]); + $this->assertNull($b->getSize()); + } +} diff --git a/core/vendor/guzzlehttp/guzzle/tests/Post/PostBodyTest.php b/core/vendor/guzzlehttp/guzzle/tests/Post/PostBodyTest.php new file mode 100644 index 00000000000..bbbd6d0196f --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/tests/Post/PostBodyTest.php @@ -0,0 +1,140 @@ +assertTrue($b->isSeekable()); + $this->assertTrue($b->isReadable()); + $this->assertFalse($b->isWritable()); + $this->assertFalse($b->write('foo')); + } + + public function testApplyingWithNothingDoesNothing() + { + $b = new PostBody(); + $m = new Request('POST', '/'); + $b->applyRequestHeaders($m); + $this->assertFalse($m->hasHeader('Content-Length')); + $this->assertFalse($m->hasHeader('Content-Type')); + } + + public function testCanForceMultipartUploadsWhenApplying() + { + $b = new PostBody(); + $b->forceMultipartUpload(true); + $m = new Request('POST', '/'); + $b->applyRequestHeaders($m); + $this->assertContains('multipart/form-data', (string) $m->getHeader('Content-Type')); + } + + public function testApplyingWithFilesAddsMultipartUpload() + { + $b = new PostBody(); + $p = new PostFile('foo', fopen(__FILE__, 'r')); + $b->addFile($p); + $this->assertEquals([$p], $b->getFiles()); + $this->assertNull($b->getFile('missing')); + $this->assertSame($p, $b->getFile('foo')); + $m = new Request('POST', '/'); + $b->applyRequestHeaders($m); + $this->assertContains('multipart/form-data', (string) $m->getHeader('Content-Type')); + $this->assertTrue($m->hasHeader('Content-Length')); + } + + public function testApplyingWithFieldsAddsMultipartUpload() + { + $b = new PostBody(); + $b->setField('foo', 'bar'); + $this->assertEquals(['foo' => 'bar'], $b->getFields()); + $m = new Request('POST', '/'); + $b->applyRequestHeaders($m); + $this->assertContains('application/x-www-form', (string) $m->getHeader('Content-Type')); + $this->assertTrue($m->hasHeader('Content-Length')); + } + + public function testCountProvidesFieldsAndFiles() + { + $b = new PostBody(); + $b->setField('foo', 'bar'); + $b->addFile(new PostFile('foo', fopen(__FILE__, 'r'))); + $this->assertEquals(2, count($b)); + $b->clearFiles(); + $b->removeField('foo'); + $this->assertEquals(0, count($b)); + $this->assertEquals([], $b->getFiles()); + $this->assertEquals([], $b->getFields()); + } + + public function testHasFields() + { + $b = new PostBody(); + $b->setField('foo', 'bar'); + $b->setField('baz', '123'); + $this->assertEquals('bar', $b->getField('foo')); + $this->assertEquals('123', $b->getField('baz')); + $this->assertNull($b->getField('ahh')); + $this->assertTrue($b->hasField('foo')); + $this->assertFalse($b->hasField('test')); + $b->replaceFields(['abc' => '123']); + $this->assertFalse($b->hasField('foo')); + $this->assertTrue($b->hasField('abc')); + } + + public function testConvertsFieldsToQueryStyleBody() + { + $b = new PostBody(); + $b->setField('foo', 'bar'); + $b->setField('baz', '123'); + $this->assertEquals('foo=bar&baz=123', $b); + $this->assertEquals(15, $b->getSize()); + $b->seek(0); + $this->assertEquals('foo=bar&baz=123', $b->getContents()); + $b->seek(0); + $this->assertEquals('foo=bar&baz=123', $b->read(1000)); + $this->assertEquals(15, $b->tell()); + $this->assertTrue($b->eof()); + } + + public function testCanSpecifyQueryAggregator() + { + $b = new PostBody(); + $b->setField('foo', ['baz', 'bar']); + $this->assertEquals('foo%5B0%5D=baz&foo%5B1%5D=bar', (string) $b); + $b = new PostBody(); + $b->setField('foo', ['baz', 'bar']); + $agg = Query::duplicateAggregator(); + $b->setAggregator($agg); + $this->assertEquals('foo=baz&foo=bar', (string) $b); + } + + public function testDetachesAndCloses() + { + $b = new PostBody(); + $b->setField('foo', 'bar'); + $b->detach(); + $this->assertTrue($b->close()); + $this->assertEquals('', $b->read(10)); + } + + public function testCreatesMultipartUploadWithMultiFields() + { + $b = new PostBody(); + $b->setField('testing', ['baz', 'bar']); + $b->addFile(new PostFile('foo', fopen(__FILE__, 'r'))); + $s = (string) $b; + $this->assertContains(file_get_contents(__FILE__), $s); + $this->assertContains('testing=bar', $s); + } +} diff --git a/core/vendor/guzzlehttp/guzzle/tests/Post/PostFileTest.php b/core/vendor/guzzlehttp/guzzle/tests/Post/PostFileTest.php new file mode 100644 index 00000000000..a233b3084d7 --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/tests/Post/PostFileTest.php @@ -0,0 +1,68 @@ +assertInstanceOf('GuzzleHttp\Post\PostFileInterface', $p); + $this->assertEquals('hi', $p->getContent()); + $this->assertEquals('foo', $p->getName()); + $this->assertEquals('/path/to/test.php', $p->getFilename()); + $this->assertEquals( + 'form-data; filename="test.php"; name="foo"', + $p->getHeaders()['Content-Disposition'] + ); + } + + public function testGetsFilenameFromMetadata() + { + $p = new PostFile('foo', fopen(__FILE__, 'r')); + $this->assertEquals(__FILE__, $p->getFilename()); + } + + public function testDefaultsToNameWhenNoFilenameExists() + { + $p = new PostFile('foo', 'bar'); + $this->assertEquals('foo', $p->getFilename()); + } + + public function testCreatesFromMultipartFormData() + { + $mp = $this->getMockBuilder('GuzzleHttp\Post\MultipartBody') + ->setMethods(['getBoundary']) + ->disableOriginalConstructor() + ->getMock(); + $mp->expects($this->once()) + ->method('getBoundary') + ->will($this->returnValue('baz')); + + $p = new PostFile('foo', $mp); + $this->assertEquals( + 'form-data; name="foo"', + $p->getHeaders()['Content-Disposition'] + ); + $this->assertEquals( + 'multipart/form-data; boundary=baz', + $p->getHeaders()['Content-Type'] + ); + } + + public function testCanAddHeaders() + { + $p = new PostFile('foo', Stream::factory('hi'), 'test.php', [ + 'X-Foo' => '123', + 'Content-Disposition' => 'bar' + ]); + $this->assertEquals('bar', $p->getHeaders()['Content-Disposition']); + $this->assertEquals('123', $p->getHeaders()['X-Foo']); + } +} diff --git a/core/vendor/guzzlehttp/guzzle/tests/QueryTest.php b/core/vendor/guzzlehttp/guzzle/tests/QueryTest.php new file mode 100644 index 00000000000..6d0dde948d2 --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/tests/QueryTest.php @@ -0,0 +1,225 @@ + 'baz', 'bar' => 'bam boozle']); + $this->assertEquals('foo=baz&bar=bam%20boozle', (string) $q); + } + + public function testCanDisableUrlEncoding() + { + $q = new Query(['bar' => 'bam boozle']); + $q->setEncodingType(false); + $this->assertEquals('bar=bam boozle', (string) $q); + } + + public function testCanSpecifyRfc1783UrlEncodingType() + { + $q = new Query(['bar abc' => 'bam boozle']); + $q->setEncodingType(Query::RFC1738); + $this->assertEquals('bar+abc=bam+boozle', (string) $q); + } + + public function testCanSpecifyRfc3986UrlEncodingType() + { + $q = new Query(['bar abc' => 'bam boozle', 'ሴ' => 'hi']); + $q->setEncodingType(Query::RFC3986); + $this->assertEquals('bar%20abc=bam%20boozle&%E1%88%B4=hi', (string) $q); + } + + /** + * @expectedException \InvalidArgumentException + */ + public function testValidatesEncodingType() + { + (new Query(['bar' => 'bam boozle']))->setEncodingType('foo'); + } + + public function testAggregatesMultipleValues() + { + $q = new Query(['foo' => ['bar', 'baz']]); + $this->assertEquals('foo%5B0%5D=bar&foo%5B1%5D=baz', (string) $q); + } + + public function testCanSetAggregator() + { + $q = new Query(['foo' => ['bar', 'baz']]); + $q->setAggregator(function (array $data) { + return ['foo' => ['barANDbaz']]; + }); + $this->assertEquals('foo=barANDbaz', (string) $q); + } + + public function testAllowsMultipleValuesPerKey() + { + $q = new Query(); + $q->add('facet', 'size'); + $q->add('facet', 'width'); + $q->add('facet.field', 'foo'); + // Use the duplicate aggregator + $q->setAggregator($q::duplicateAggregator()); + $this->assertEquals('facet=size&facet=width&facet.field=foo', (string) $q); + } + + public function parseQueryProvider() + { + return array( + // Ensure that multiple query string values are allowed per value + array('q=a&q=b', array('q' => array('a', 'b'))), + // Ensure that PHP array style query string values are parsed + array('q[]=a&q[]=b', array('q' => array('a', 'b'))), + // Ensure that a single PHP array style query string value is parsed into an array + array('q[]=a', array('q' => array('a'))), + // Ensure that decimals are allowed in query strings + array('q.a=a&q.b=b', array( + 'q.a' => 'a', + 'q.b' => 'b' + )), + // Ensure that query string values are percent decoded + array('q%20a=a%20b', array('q a' => 'a b')), + // Ensure null values can be added + array('q&a', array('q' => null, 'a' => null)), + ); + } + + /** + * @dataProvider parseQueryProvider + */ + public function testParsesQueries($query, $data) + { + $query = Query::fromString($query); + $this->assertEquals($data, $query->toArray()); + } + + public function testProperlyDealsWithDuplicateQueryValues() + { + $query = Query::fromString('foo=a&foo=b&?µ=c'); + $this->assertEquals(array('a', 'b'), $query->get('foo')); + $this->assertEquals('c', $query->get('?µ')); + } + + public function testAllowsNullQueryValues() + { + $query = Query::fromString('foo'); + $this->assertEquals('foo', (string) $query); + $query->set('foo', null); + $this->assertEquals('foo', (string) $query); + } + + public function testAllowsFalsyQueryValues() + { + $query = Query::fromString('0'); + $this->assertEquals('0', (string) $query); + $query->set('0', ''); + $this->assertSame('0=', (string) $query); + } + + public function testConvertsPlusSymbolsToSpaces() + { + $query = Query::fromString('var=foo+bar'); + $this->assertEquals('foo bar', $query->get('var')); + } + + public function testFromStringDoesntMangleZeroes() + { + $query = Query::fromString('var=0'); + $this->assertSame('0', $query->get('var')); + } + + public function testAllowsZeroValues() + { + $query = new Query(array( + 'foo' => 0, + 'baz' => '0', + 'bar' => null, + 'boo' => false + )); + $this->assertEquals('foo=0&baz=0&bar&boo=', (string) $query); + } + + public function testFromStringDoesntStripTrailingEquals() + { + $query = Query::fromString('data=mF0b3IiLCJUZWFtIERldiJdfX0='); + $this->assertEquals('mF0b3IiLCJUZWFtIERldiJdfX0=', $query->get('data')); + } + + public function testGuessesIfDuplicateAggregatorShouldBeUsed() + { + $query = Query::fromString('test=a&test=b'); + $this->assertEquals('test=a&test=b', (string) $query); + } + + public function testGuessesIfDuplicateAggregatorShouldBeUsedAndChecksForPhpStyle() + { + $query = Query::fromString('test[]=a&test[]=b'); + $this->assertEquals('test%5B0%5D=a&test%5B1%5D=b', (string) $query); + } + + public function testCastingToAndCreatingFromStringWithEmptyValuesIsFast() + { + $this->assertEquals('', (string) Query::fromString('')); + } + + private $encodeData = [ + 't' => [ + 'v1' => ['a', '1'], + 'v2' => 'b', + 'v3' => ['v4' => 'c', 'v5' => 'd'] + ] + ]; + + public function testEncodesDuplicateAggregator() + { + $agg = Query::duplicateAggregator(); + $result = $agg($this->encodeData); + $this->assertEquals(array( + 't[v1]' => ['a', '1'], + 't[v2]' => ['b'], + 't[v3][v4]' => ['c'], + 't[v3][v5]' => ['d'], + ), $result); + } + + public function testDuplicateEncodesNoNumericIndices() + { + $agg = Query::duplicateAggregator(); + $result = $agg($this->encodeData); + $this->assertEquals(array( + 't[v1]' => ['a', '1'], + 't[v2]' => ['b'], + 't[v3][v4]' => ['c'], + 't[v3][v5]' => ['d'], + ), $result); + } + + public function testEncodesPhpAggregator() + { + $agg = Query::phpAggregator(); + $result = $agg($this->encodeData); + $this->assertEquals(array( + 't[v1][0]' => ['a'], + 't[v1][1]' => ['1'], + 't[v2]' => ['b'], + 't[v3][v4]' => ['c'], + 't[v3][v5]' => ['d'], + ), $result); + } + + public function testPhpEncodesNoNumericIndices() + { + $agg = Query::phpAggregator(false); + $result = $agg($this->encodeData); + $this->assertEquals(array( + 't[v1][]' => ['a', '1'], + 't[v2]' => ['b'], + 't[v3][v4]' => ['c'], + 't[v3][v5]' => ['d'], + ), $result); + } +} diff --git a/core/vendor/guzzlehttp/guzzle/tests/Server.php b/core/vendor/guzzlehttp/guzzle/tests/Server.php new file mode 100644 index 00000000000..6b33dadb1f6 --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/tests/Server.php @@ -0,0 +1,177 @@ +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) + { + static $factory; + if (!$factory) { + $factory = new MessageFactory(); + } + + self::start(); + + $data = []; + foreach ((array) $responses as $response) { + + // Create the response object from a string + if (is_string($response)) { + $response = $factory->fromMessage($response); + } elseif (!($response instanceof ResponseInterface)) { + throw new \Exception('Responses must be strings or Responses'); + } + + $headers = array_map(function ($h) { + return implode(' ,', $h); + }, $response->getHeaders()); + + $data[] = [ + 'statusCode' => $response->getStatusCode(), + 'reasonPhrase' => $response->getReasonPhrase(), + 'headers' => $headers, + 'body' => (string) $response->getBody() + ]; + } + + self::getClient()->put('guzzle-server/responses', [ + 'body' => json_encode($data) + ]); + } + + /** + * Get all of the received requests + * + * @param bool $hydrate Set to TRUE to turn the messages into + * actual {@see RequestInterface} objects. If $hydrate is FALSE, + * requests will be returned as strings. + * + * @return array + * @throws \RuntimeException + */ + public static function received($hydrate = false) + { + if (!self::$started) { + return []; + } + + $response = self::getClient()->get('guzzle-server/requests'); + $data = array_filter(explode(self::REQUEST_DELIMITER, (string) $response->getBody())); + if ($hydrate) { + $factory = new MessageFactory(); + $data = array_map(function($message) use ($factory) { + return $factory->fromMessage($message); + }, $data); + } + + return $data; + } + + /** + * Stop running the node.js server + */ + public static function stop() + { + if (self::$started) { + self::getClient()->delete('guzzle-server'); + } + + self::$started = false; + } + + public static function wait($maxTries = 3) + { + $tries = 0; + while (!self::isListening() && ++$tries < $maxTries) { + usleep(100000); + } + + if (!self::isListening()) { + throw new \RuntimeException('Unable to contact node.js server'); + } + } + + private static function start() + { + if (self::$started){ + return; + } + + if (!self::isListening()) { + exec('node ' . __DIR__ . \DIRECTORY_SEPARATOR . 'server.js ' + . self::$port . ' >> /tmp/server.log 2>&1 &'); + self::wait(); + } + + self::$started = true; + } + + private static function isListening() + { + try { + self::getClient()->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_url' => self::$url]); + } + + return self::$client; + } +} diff --git a/core/vendor/guzzlehttp/guzzle/tests/Subscriber/CookieTest.php b/core/vendor/guzzlehttp/guzzle/tests/Subscriber/CookieTest.php new file mode 100644 index 00000000000..e1897424e8f --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/tests/Subscriber/CookieTest.php @@ -0,0 +1,75 @@ +getMockBuilder('GuzzleHttp\Cookie\CookieJar') + ->setMethods(array('extractCookies')) + ->getMock(); + + $mock->expects($this->exactly(1)) + ->method('extractCookies') + ->with($request, $response); + + $plugin = new Cookie($mock); + $t = new Transaction(new Client(), $request); + $t->setResponse($response); + $plugin->onComplete(new CompleteEvent($t)); + } + + public function testProvidesCookieJar() + { + $jar = new CookieJar(); + $plugin = new Cookie($jar); + $this->assertSame($jar, $plugin->getCookieJar()); + } + + public function testCookiesAreExtractedFromRedirectResponses() + { + $jar = new CookieJar(); + $cookie = new Cookie($jar); + $history = new History(); + $mock = new Mock([ + "HTTP/1.1 302 Moved Temporarily\r\n" . + "Set-Cookie: test=583551; Domain=www.foo.com; Expires=Wednesday, 23-Mar-2050 19:49:45 GMT; Path=/\r\n" . + "Location: /redirect\r\n\r\n", + "HTTP/1.1 200 OK\r\n" . + "Content-Length: 0\r\n\r\n", + "HTTP/1.1 200 OK\r\n" . + "Content-Length: 0\r\n\r\n" + ]); + $client = new Client(['base_url' => 'http://www.foo.com']); + $client->getEmitter()->attach($cookie); + $client->getEmitter()->attach($mock); + $client->getEmitter()->attach($history); + + $client->get(); + $request = $client->createRequest('GET', '/'); + $client->send($request); + + $this->assertEquals('test=583551', $request->getHeader('Cookie')); + $requests = $history->getRequests(); + // Confirm subsequent requests have the cookie. + $this->assertEquals('test=583551', $requests[2]->getHeader('Cookie')); + // Confirm the redirected request has the cookie. + $this->assertEquals('test=583551', $requests[1]->getHeader('Cookie')); + } +} diff --git a/core/vendor/guzzlehttp/guzzle/tests/Subscriber/HistoryTest.php b/core/vendor/guzzlehttp/guzzle/tests/Subscriber/HistoryTest.php new file mode 100644 index 00000000000..d5f1dc84c5a --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/tests/Subscriber/HistoryTest.php @@ -0,0 +1,88 @@ +setResponse($response); + $e = new RequestException('foo', $request, $response); + $ev = new ErrorEvent($t, $e); + $h = new History(2); + $h->onError($ev); + $this->assertEquals([$request], $h->getRequests()); + } + + public function testMaintainsLimitValue() + { + $request = new Request('GET', '/'); + $response = new Response(200); + $t = new Transaction(new Client(), $request); + $t->setResponse($response); + $ev = new CompleteEvent($t); + $h = new History(2); + $h->onComplete($ev); + $h->onComplete($ev); + $h->onComplete($ev); + $this->assertEquals(2, count($h)); + $this->assertSame($request, $h->getLastRequest()); + $this->assertSame($response, $h->getLastResponse()); + foreach ($h as $trans) { + $this->assertInstanceOf('GuzzleHttp\Message\RequestInterface', $trans['request']); + $this->assertInstanceOf('GuzzleHttp\Message\ResponseInterface', $trans['response']); + } + return $h; + } + + /** + * @depends testMaintainsLimitValue + */ + public function testClearsHistory($h) + { + $this->assertEquals(2, count($h)); + $h->clear(); + $this->assertEquals(0, count($h)); + } + + public function testCanCastToString() + { + $client = new Client(['base_url' => 'http://localhost/']); + $h = new History(); + $client->getEmitter()->attach($h); + + $mock = new Mock(array( + new Response(301, array('Location' => '/redirect1', 'Content-Length' => 0)), + new Response(307, array('Location' => '/redirect2', 'Content-Length' => 0)), + new Response(200, array('Content-Length' => '2'), Stream::factory('HI')) + )); + + $client->getEmitter()->attach($mock); + $request = $client->createRequest('GET', '/'); + $client->send($request); + $this->assertEquals(3, count($h)); + + $h = str_replace("\r", '', $h); + $this->assertContains("> GET / HTTP/1.1\nHost: localhost\nUser-Agent:", $h); + $this->assertContains("< HTTP/1.1 301 Moved Permanently\nLocation: /redirect1", $h); + $this->assertContains("< HTTP/1.1 307 Temporary Redirect\nLocation: /redirect2", $h); + $this->assertContains("< HTTP/1.1 200 OK\nContent-Length: 2\n\nHI", $h); + } +} diff --git a/core/vendor/guzzlehttp/guzzle/tests/Subscriber/HttpErrorTest.php b/core/vendor/guzzlehttp/guzzle/tests/Subscriber/HttpErrorTest.php new file mode 100644 index 00000000000..12a1aef41e0 --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/tests/Subscriber/HttpErrorTest.php @@ -0,0 +1,61 @@ +getEvent(); + $event->intercept(new Response(200)); + (new HttpError())->onComplete($event); + } + + /** + * @expectedException \GuzzleHttp\Exception\ClientException + */ + public function testThrowsClientExceptionOnFailure() + { + $event = $this->getEvent(); + $event->intercept(new Response(403)); + (new HttpError())->onComplete($event); + } + + /** + * @expectedException \GuzzleHttp\Exception\ServerException + */ + public function testThrowsServerExceptionOnFailure() + { + $event = $this->getEvent(); + $event->intercept(new Response(500)); + (new HttpError())->onComplete($event); + } + + private function getEvent() + { + return new CompleteEvent(new Transaction(new Client(), new Request('PUT', '/'))); + } + + /** + * @expectedException \GuzzleHttp\Exception\ClientException + */ + public function testFullTransaction() + { + $client = new Client(); + $client->getEmitter()->attach(new Mock([ + new Response(403) + ])); + $client->get('http://httpbin.org'); + } +} diff --git a/core/vendor/guzzlehttp/guzzle/tests/Subscriber/MockTest.php b/core/vendor/guzzlehttp/guzzle/tests/Subscriber/MockTest.php new file mode 100644 index 00000000000..c4d51aff766 --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/tests/Subscriber/MockTest.php @@ -0,0 +1,108 @@ +assertInternalType('array', $mock->getEvents()); + } + + public function testIsCountable() + { + $plugin = new Mock(); + $plugin->addResponse((new MessageFactory())->fromMessage("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n")); + $this->assertEquals(1, count($plugin)); + } + + public function testCanClearQueue() + { + $plugin = new Mock(); + $plugin->addResponse((new MessageFactory())->fromMessage("HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n")); + $plugin->clearQueue(); + $this->assertEquals(0, count($plugin)); + } + + public function testRetrievesResponsesFromFiles() + { + $tmp = tempnam('/tmp', 'tfile'); + file_put_contents($tmp, "HTTP/1.1 201 OK\r\nContent-Length: 0\r\n\r\n"); + $plugin = new Mock(); + $plugin->addResponse($tmp); + unlink($tmp); + $this->assertEquals(1, count($plugin)); + $q = $this->readAttribute($plugin, 'queue'); + $this->assertEquals(201, $q[0]->getStatusCode()); + } + + /** + * @expectedException \InvalidArgumentException + */ + public function testThrowsExceptionWhenInvalidResponse() + { + (new Mock())->addResponse(false); + } + + public function testAddsMockResponseToRequestFromClient() + { + $response = new Response(200); + $t = new Transaction(new Client(), new Request('GET', '/')); + $m = new Mock([$response]); + $ev = new BeforeEvent($t); + $m->onBefore($ev); + $this->assertSame($response, $t->getResponse()); + } + + /** + * @expectedException \OutOfBoundsException + */ + public function testUpdateThrowsExceptionWhenEmpty() + { + $p = new Mock(); + $ev = new BeforeEvent(new Transaction(new Client(), new Request('GET', '/'))); + $p->onBefore($ev); + } + + public function testReadsBodiesFromMockedRequests() + { + $m = new Mock([new Response(200)]); + $client = new Client(['base_url' => 'http://test.com']); + $client->getEmitter()->attach($m); + $body = Stream::factory('foo'); + $client->put('/', ['body' => $body]); + $this->assertEquals(3, $body->tell()); + } + + public function testCanMockBadRequestExceptions() + { + $client = new Client(['base_url' => 'http://test.com']); + $request = $client->createRequest('GET', '/'); + $ex = new RequestException('foo', $request); + $mock = new Mock([$ex]); + $this->assertCount(1, $mock); + $request->getEmitter()->attach($mock); + + try { + $client->send($request); + $this->fail('Did not dequeue an exception'); + } catch (RequestException $e) { + $this->assertSame($e, $ex); + $this->assertSame($request, $ex->getRequest()); + } + } +} diff --git a/core/vendor/guzzlehttp/guzzle/tests/Subscriber/PrepareTest.php b/core/vendor/guzzlehttp/guzzle/tests/Subscriber/PrepareTest.php new file mode 100644 index 00000000000..bce7d53cdc2 --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/tests/Subscriber/PrepareTest.php @@ -0,0 +1,198 @@ +getTrans(); + $s->onBefore(new BeforeEvent($t)); + $this->assertFalse($t->getRequest()->hasHeader('Expect')); + } + + public function testAppliesPostBody() + { + $s = new Prepare(); + $t = $this->getTrans(); + $p = $this->getMockBuilder('GuzzleHttp\Post\PostBody') + ->setMethods(['applyRequestHeaders']) + ->getMockForAbstractClass(); + $p->expects($this->once()) + ->method('applyRequestHeaders'); + $t->getRequest()->setBody($p); + $s->onBefore(new BeforeEvent($t)); + } + + public function testAddsExpectHeaderWithTrue() + { + $s = new Prepare(); + $t = $this->getTrans(); + $t->getRequest()->getConfig()->set('expect', true); + $t->getRequest()->setBody(Stream::factory('foo')); + $s->onBefore(new BeforeEvent($t)); + $this->assertEquals('100-Continue', $t->getRequest()->getHeader('Expect')); + } + + public function testAddsExpectHeaderBySize() + { + $s = new Prepare(); + $t = $this->getTrans(); + $t->getRequest()->getConfig()->set('expect', 2); + $t->getRequest()->setBody(Stream::factory('foo')); + $s->onBefore(new BeforeEvent($t)); + $this->assertTrue($t->getRequest()->hasHeader('Expect')); + } + + public function testDoesNotModifyExpectHeaderIfPresent() + { + $s = new Prepare(); + $t = $this->getTrans(); + $t->getRequest()->setHeader('Expect', 'foo'); + $t->getRequest()->setBody(Stream::factory('foo')); + $s->onBefore(new BeforeEvent($t)); + $this->assertEquals('foo', $t->getRequest()->getHeader('Expect')); + } + + public function testDoesAddExpectHeaderWhenSetToFalse() + { + $s = new Prepare(); + $t = $this->getTrans(); + $t->getRequest()->getConfig()->set('expect', false); + $t->getRequest()->setBody(Stream::factory('foo')); + $s->onBefore(new BeforeEvent($t)); + $this->assertFalse($t->getRequest()->hasHeader('Expect')); + } + + public function testDoesNotAddExpectHeaderBySize() + { + $s = new Prepare(); + $t = $this->getTrans(); + $t->getRequest()->getConfig()->set('expect', 10); + $t->getRequest()->setBody(Stream::factory('foo')); + $s->onBefore(new BeforeEvent($t)); + $this->assertFalse($t->getRequest()->hasHeader('Expect')); + } + + public function testAddsExpectHeaderForNonSeekable() + { + $s = new Prepare(); + $t = $this->getTrans(); + $t->getRequest()->setBody(new NoSeekStream(Stream::factory('foo'))); + $s->onBefore(new BeforeEvent($t)); + $this->assertTrue($t->getRequest()->hasHeader('Expect')); + } + + public function testRemovesContentLengthWhenSendingWithChunked() + { + $s = new Prepare(); + $t = $this->getTrans(); + $t->getRequest()->setBody(Stream::factory('foo')); + $t->getRequest()->setHeader('Transfer-Encoding', 'chunked'); + $s->onBefore(new BeforeEvent($t)); + $this->assertFalse($t->getRequest()->hasHeader('Content-Length')); + } + + public function testUsesProvidedContentLengthAndRemovesXferEncoding() + { + $s = new Prepare(); + $t = $this->getTrans(); + $t->getRequest()->setBody(Stream::factory('foo')); + $t->getRequest()->setHeader('Content-Length', '3'); + $t->getRequest()->setHeader('Transfer-Encoding', 'chunked'); + $s->onBefore(new BeforeEvent($t)); + $this->assertEquals(3, $t->getRequest()->getHeader('Content-Length')); + $this->assertFalse($t->getRequest()->hasHeader('Transfer-Encoding')); + } + + public function testSetsContentTypeIfPossibleFromStream() + { + $body = $this->getMockBody(); + $sub = new Prepare(); + $t = $this->getTrans(); + $t->getRequest()->setBody($body); + $sub->onBefore(new BeforeEvent($t)); + $this->assertEquals( + 'image/jpeg', + $t->getRequest()->getHeader('Content-Type') + ); + $this->assertEquals(4, $t->getRequest()->getHeader('Content-Length')); + } + + public function testDoesNotOverwriteExistingContentType() + { + $s = new Prepare(); + $t = $this->getTrans(); + $t->getRequest()->setBody($this->getMockBody()); + $t->getRequest()->setHeader('Content-Type', 'foo/baz'); + $s->onBefore(new BeforeEvent($t)); + $this->assertEquals( + 'foo/baz', + $t->getRequest()->getHeader('Content-Type') + ); + } + + public function testSetsContentLengthIfPossible() + { + $s = new Prepare(); + $t = $this->getTrans(); + $t->getRequest()->setBody($this->getMockBody()); + $s->onBefore(new BeforeEvent($t)); + $this->assertEquals(4, $t->getRequest()->getHeader('Content-Length')); + } + + public function testSetsTransferEncodingChunkedIfNeeded() + { + $r = new Request('PUT', '/'); + $s = $this->getMockBuilder('GuzzleHttp\Stream\StreamInterface') + ->setMethods(['getSize']) + ->getMockForAbstractClass(); + $s->expects($this->exactly(2)) + ->method('getSize') + ->will($this->returnValue(null)); + $r->setBody($s); + $t = $this->getTrans($r); + $s = new Prepare(); + $s->onBefore(new BeforeEvent($t)); + $this->assertEquals('chunked', $r->getHeader('Transfer-Encoding')); + } + + private function getTrans($request = null) + { + return new Transaction( + new Client(), + $request ?: new Request('PUT', '/') + ); + } + + /** + * @return \GuzzleHttp\Stream\StreamInterface + */ + private function getMockBody() + { + $s = $this->getMockBuilder('GuzzleHttp\Stream\MetadataStreamInterface') + ->setMethods(['getMetadata', 'getSize']) + ->getMockForAbstractClass(); + $s->expects($this->any()) + ->method('getMetadata') + ->with('uri') + ->will($this->returnValue('/foo/baz/bar.jpg')); + $s->expects($this->exactly(2)) + ->method('getSize') + ->will($this->returnValue(4)); + + return $s; + } +} diff --git a/core/vendor/guzzlehttp/guzzle/tests/Subscriber/RedirectTest.php b/core/vendor/guzzlehttp/guzzle/tests/Subscriber/RedirectTest.php new file mode 100644 index 00000000000..cf4487e57aa --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/tests/Subscriber/RedirectTest.php @@ -0,0 +1,230 @@ +addMultiple([ + "HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect1\r\nContent-Length: 0\r\n\r\n", + "HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect2\r\nContent-Length: 0\r\n\r\n", + "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n", + ]); + + $client = new Client(['base_url' => 'http://test.com']); + $client->getEmitter()->attach($history); + $client->getEmitter()->attach($mock); + + $response = $client->get('/foo'); + $this->assertEquals(200, $response->getStatusCode()); + $this->assertContains('/redirect2', $response->getEffectiveUrl()); + + // Ensure that two requests were sent + $requests = $history->getRequests(); + + $this->assertEquals('/foo', $requests[0]->getPath()); + $this->assertEquals('GET', $requests[0]->getMethod()); + $this->assertEquals('/redirect1', $requests[1]->getPath()); + $this->assertEquals('GET', $requests[1]->getMethod()); + $this->assertEquals('/redirect2', $requests[2]->getPath()); + $this->assertEquals('GET', $requests[2]->getMethod()); + } + + /** + * @expectedException \GuzzleHttp\Exception\TooManyRedirectsException + * @expectedExceptionMessage Will not follow more than + */ + public function testCanLimitNumberOfRedirects() + { + $mock = new Mock([ + "HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect1\r\nContent-Length: 0\r\n\r\n", + "HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect2\r\nContent-Length: 0\r\n\r\n", + "HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect3\r\nContent-Length: 0\r\n\r\n", + "HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect4\r\nContent-Length: 0\r\n\r\n", + "HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect5\r\nContent-Length: 0\r\n\r\n", + "HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect6\r\nContent-Length: 0\r\n\r\n" + ]); + $client = new Client(); + $client->getEmitter()->attach($mock); + $client->get('http://www.example.com/foo'); + } + + public function testDefaultBehaviorIsToRedirectWithGetForEntityEnclosingRequests() + { + $h = new History(); + $mock = new Mock([ + "HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect\r\nContent-Length: 0\r\n\r\n", + "HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect\r\nContent-Length: 0\r\n\r\n", + "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n", + ]); + $client = new Client(); + $client->getEmitter()->attach($mock); + $client->getEmitter()->attach($h); + $client->post('http://test.com/foo', [ + 'headers' => ['X-Baz' => 'bar'], + 'body' => 'testing' + ]); + + $requests = $h->getRequests(); + $this->assertEquals('POST', $requests[0]->getMethod()); + $this->assertEquals('GET', $requests[1]->getMethod()); + $this->assertEquals('bar', (string) $requests[1]->getHeader('X-Baz')); + $this->assertEquals('GET', $requests[2]->getMethod()); + } + + public function testCanRedirectWithStrictRfcCompliance() + { + $h = new History(); + $mock = new Mock([ + "HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect\r\nContent-Length: 0\r\n\r\n", + "HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect\r\nContent-Length: 0\r\n\r\n", + "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n", + ]); + $client = new Client(['base_url' => 'http://test.com']); + $client->getEmitter()->attach($mock); + $client->getEmitter()->attach($h); + $client->post('/foo', [ + 'headers' => ['X-Baz' => 'bar'], + 'body' => 'testing', + 'allow_redirects' => ['max' => 10, 'strict' => true] + ]); + + $requests = $h->getRequests(); + $this->assertEquals('POST', $requests[0]->getMethod()); + $this->assertEquals('POST', $requests[1]->getMethod()); + $this->assertEquals('bar', (string) $requests[1]->getHeader('X-Baz')); + $this->assertEquals('POST', $requests[2]->getMethod()); + } + + public function testRewindsStreamWhenRedirectingIfNeeded() + { + $h = new History(); + $mock = new Mock([ + "HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect\r\nContent-Length: 0\r\n\r\n", + "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n", + ]); + $client = new Client(['base_url' => 'http://test.com']); + $client->getEmitter()->attach($mock); + $client->getEmitter()->attach($h); + + $body = $this->getMockBuilder('GuzzleHttp\Stream\StreamInterface') + ->setMethods(['seek', 'read', 'eof', 'tell']) + ->getMockForAbstractClass(); + $body->expects($this->once())->method('tell')->will($this->returnValue(1)); + $body->expects($this->once())->method('seek')->will($this->returnValue(true)); + $body->expects($this->any())->method('eof')->will($this->returnValue(true)); + $body->expects($this->any())->method('read')->will($this->returnValue('foo')); + $client->post('/foo', [ + 'body' => $body, + 'allow_redirects' => ['max' => 5, 'strict' => true] + ]); + } + + /** + * @expectedException \GuzzleHttp\Exception\CouldNotRewindStreamException + * @expectedExceptionMessage Unable to rewind the non-seekable request body after redirecting + */ + public function testThrowsExceptionWhenStreamCannotBeRewound() + { + $h = new History(); + $mock = new Mock([ + "HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect\r\nContent-Length: 0\r\n\r\n", + "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n", + ]); + $client = new Client(); + $client->getEmitter()->attach($mock); + $client->getEmitter()->attach($h); + + $body = $this->getMockBuilder('GuzzleHttp\Stream\StreamInterface') + ->setMethods(['seek', 'read', 'eof', 'tell']) + ->getMockForAbstractClass(); + $body->expects($this->once())->method('tell')->will($this->returnValue(1)); + $body->expects($this->once())->method('seek')->will($this->returnValue(false)); + $body->expects($this->any())->method('eof')->will($this->returnValue(true)); + $body->expects($this->any())->method('read')->will($this->returnValue('foo')); + $client->post('http://example.com/foo', [ + 'body' => $body, + 'allow_redirects' => ['max' => 10, 'strict' => true] + ]); + } + + public function testRedirectsCanBeDisabledPerRequest() + { + $client = new Client(['base_url' => 'http://test.com']); + $client->getEmitter()->attach(new Mock([ + "HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect\r\nContent-Length: 0\r\n\r\n", + "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n", + ])); + $response = $client->put('/', ['body' => 'test', 'allow_redirects' => false]); + $this->assertEquals(301, $response->getStatusCode()); + } + + public function testCanRedirectWithNoLeadingSlashAndQuery() + { + $h = new History(); + $client = new Client(['base_url' => 'http://www.foo.com']); + $client->getEmitter()->attach(new Mock([ + "HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect?foo=bar\r\nContent-Length: 0\r\n\r\n", + "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n", + ])); + $client->getEmitter()->attach($h); + $client->get('?foo=bar'); + $requests = $h->getRequests(); + $this->assertEquals('http://www.foo.com?foo=bar', $requests[0]->getUrl()); + $this->assertEquals('http://www.foo.com/redirect?foo=bar', $requests[1]->getUrl()); + } + + public function testHandlesRedirectsWithSpacesProperly() + { + $client = new Client(['base_url' => 'http://www.foo.com']); + $client->getEmitter()->attach(new Mock([ + "HTTP/1.1 301 Moved Permanently\r\nLocation: /redirect 1\r\nContent-Length: 0\r\n\r\n", + "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n" + ])); + $h = new History(); + $client->getEmitter()->attach($h); + $client->get('/foo'); + $reqs = $h->getRequests(); + $this->assertEquals('/redirect%201', $reqs[1]->getResource()); + } + + public function testAddsRefererWhenPossible() + { + $client = new Client(['base_url' => 'http://www.foo.com']); + $client->getEmitter()->attach(new Mock([ + "HTTP/1.1 301 Moved Permanently\r\nLocation: /bar\r\nContent-Length: 0\r\n\r\n", + "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n" + ])); + $h = new History(); + $client->getEmitter()->attach($h); + $client->get('/foo', ['allow_redirects' => ['max' => 5, 'referer' => true]]); + $reqs = $h->getRequests(); + $this->assertEquals('http://www.foo.com/foo', $reqs[1]->getHeader('Referer')); + } + + public function testDoesNotAddRefererWhenChangingProtocols() + { + $client = new Client(['base_url' => 'https://www.foo.com']); + $client->getEmitter()->attach(new Mock([ + "HTTP/1.1 301 Moved Permanently\r\n" + . "Location: http://www.foo.com/foo\r\n" + . "Content-Length: 0\r\n\r\n", + "HTTP/1.1 200 OK\r\nContent-Length: 0\r\n\r\n" + ])); + $h = new History(); + $client->getEmitter()->attach($h); + $client->get('/foo', ['allow_redirects' => ['max' => 5, 'referer' => true]]); + $reqs = $h->getRequests(); + $this->assertFalse($reqs[1]->hasHeader('Referer')); + } +} diff --git a/core/vendor/guzzlehttp/guzzle/tests/UriTemplateTest.php b/core/vendor/guzzlehttp/guzzle/tests/UriTemplateTest.php new file mode 100644 index 00000000000..b65ec1893d9 --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/tests/UriTemplateTest.php @@ -0,0 +1,202 @@ + 'value', + 'hello' => 'Hello World!', + 'empty' => '', + 'path' => '/foo/bar', + 'x' => '1024', + 'y' => '768', + 'null' => null, + 'list' => array('red', 'green', 'blue'), + 'keys' => array( + "semi" => ';', + "dot" => '.', + "comma" => ',' + ), + 'empty_keys' => array(), + ); + + return array_map(function($t) use ($params) { + $t[] = $params; + return $t; + }, array( + array('foo', 'foo'), + array('{var}', 'value'), + array('{hello}', 'Hello%20World%21'), + array('{+var}', 'value'), + array('{+hello}', 'Hello%20World!'), + array('{+path}/here', '/foo/bar/here'), + array('here?ref={+path}', 'here?ref=/foo/bar'), + array('X{#var}', 'X#value'), + array('X{#hello}', 'X#Hello%20World!'), + array('map?{x,y}', 'map?1024,768'), + array('{x,hello,y}', '1024,Hello%20World%21,768'), + array('{+x,hello,y}', '1024,Hello%20World!,768'), + array('{+path,x}/here', '/foo/bar,1024/here'), + array('{#x,hello,y}', '#1024,Hello%20World!,768'), + array('{#path,x}/here', '#/foo/bar,1024/here'), + array('X{.var}', 'X.value'), + array('X{.x,y}', 'X.1024.768'), + array('{/var}', '/value'), + array('{/var,x}/here', '/value/1024/here'), + array('{;x,y}', ';x=1024;y=768'), + array('{;x,y,empty}', ';x=1024;y=768;empty'), + array('{?x,y}', '?x=1024&y=768'), + array('{?x,y,empty}', '?x=1024&y=768&empty='), + array('?fixed=yes{&x}', '?fixed=yes&x=1024'), + array('{&x,y,empty}', '&x=1024&y=768&empty='), + array('{var:3}', 'val'), + array('{var:30}', 'value'), + array('{list}', 'red,green,blue'), + array('{list*}', 'red,green,blue'), + array('{keys}', 'semi,%3B,dot,.,comma,%2C'), + array('{keys*}', 'semi=%3B,dot=.,comma=%2C'), + array('{+path:6}/here', '/foo/b/here'), + array('{+list}', 'red,green,blue'), + array('{+list*}', 'red,green,blue'), + array('{+keys}', 'semi,;,dot,.,comma,,'), + array('{+keys*}', 'semi=;,dot=.,comma=,'), + array('{#path:6}/here', '#/foo/b/here'), + array('{#list}', '#red,green,blue'), + array('{#list*}', '#red,green,blue'), + array('{#keys}', '#semi,;,dot,.,comma,,'), + array('{#keys*}', '#semi=;,dot=.,comma=,'), + array('X{.var:3}', 'X.val'), + array('X{.list}', 'X.red,green,blue'), + array('X{.list*}', 'X.red.green.blue'), + array('X{.keys}', 'X.semi,%3B,dot,.,comma,%2C'), + array('X{.keys*}', 'X.semi=%3B.dot=..comma=%2C'), + array('{/var:1,var}', '/v/value'), + array('{/list}', '/red,green,blue'), + array('{/list*}', '/red/green/blue'), + array('{/list*,path:4}', '/red/green/blue/%2Ffoo'), + array('{/keys}', '/semi,%3B,dot,.,comma,%2C'), + array('{/keys*}', '/semi=%3B/dot=./comma=%2C'), + array('{;hello:5}', ';hello=Hello'), + array('{;list}', ';list=red,green,blue'), + array('{;list*}', ';list=red;list=green;list=blue'), + array('{;keys}', ';keys=semi,%3B,dot,.,comma,%2C'), + array('{;keys*}', ';semi=%3B;dot=.;comma=%2C'), + array('{?var:3}', '?var=val'), + array('{?list}', '?list=red,green,blue'), + array('{?list*}', '?list=red&list=green&list=blue'), + array('{?keys}', '?keys=semi,%3B,dot,.,comma,%2C'), + array('{?keys*}', '?semi=%3B&dot=.&comma=%2C'), + array('{&var:3}', '&var=val'), + array('{&list}', '&list=red,green,blue'), + array('{&list*}', '&list=red&list=green&list=blue'), + array('{&keys}', '&keys=semi,%3B,dot,.,comma,%2C'), + array('{&keys*}', '&semi=%3B&dot=.&comma=%2C'), + array('{.null}', ''), + array('{.null,var}', '.value'), + array('X{.empty_keys*}', 'X'), + array('X{.empty_keys}', 'X'), + // Test that missing expansions are skipped + array('test{&missing*}', 'test'), + // Test that multiple expansions can be set + array('http://{var}/{var:2}{?keys*}', 'http://value/va?semi=%3B&dot=.&comma=%2C'), + // Test more complex query string stuff + array('http://www.test.com{+path}{?var,keys*}', 'http://www.test.com/foo/bar?var=value&semi=%3B&dot=.&comma=%2C') + )); + } + + /** + * @dataProvider templateProvider + */ + public function testExpandsUriTemplates($template, $expansion, $params) + { + $uri = new UriTemplate($template); + $this->assertEquals($expansion, $uri->expand($template, $params)); + } + + public function expressionProvider() + { + return array( + array( + '{+var*}', array( + 'operator' => '+', + 'values' => array( + array('value' => 'var', 'modifier' => '*') + ) + ), + ), + array( + '{?keys,var,val}', array( + 'operator' => '?', + 'values' => array( + array('value' => 'keys', 'modifier' => ''), + array('value' => 'var', 'modifier' => ''), + array('value' => 'val', 'modifier' => '') + ) + ), + ), + array( + '{+x,hello,y}', array( + 'operator' => '+', + 'values' => array( + array('value' => 'x', 'modifier' => ''), + array('value' => 'hello', 'modifier' => ''), + array('value' => 'y', 'modifier' => '') + ) + ) + ) + ); + } + + /** + * @dataProvider expressionProvider + */ + public function testParsesExpressions($exp, $data) + { + $template = new UriTemplate($exp); + + // Access the config object + $class = new \ReflectionClass($template); + $method = $class->getMethod('parseExpression'); + $method->setAccessible(true); + + $exp = substr($exp, 1, -1); + $this->assertEquals($data, $method->invokeArgs($template, array($exp))); + } + + /** + * @ticket https://github.com/guzzle/guzzle/issues/90 + */ + public function testAllowsNestedArrayExpansion() + { + $template = new UriTemplate(); + + $result = $template->expand('http://example.com{+path}{/segments}{?query,data*,foo*}', array( + 'path' => '/foo/bar', + 'segments' => array('one', 'two'), + 'query' => 'test', + 'data' => array( + 'more' => array('fun', 'ice cream') + ), + 'foo' => array( + 'baz' => array( + 'bar' => 'fizz', + 'test' => 'buzz' + ), + 'bam' => 'boo' + ) + )); + + $this->assertEquals('http://example.com/foo/bar/one,two?query=test&more%5B0%5D=fun&more%5B1%5D=ice%20cream&baz%5Bbar%5D=fizz&baz%5Btest%5D=buzz&bam=boo', $result); + } +} diff --git a/core/vendor/guzzlehttp/guzzle/tests/UrlTest.php b/core/vendor/guzzlehttp/guzzle/tests/UrlTest.php new file mode 100644 index 00000000000..ce2543d44f2 --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/tests/UrlTest.php @@ -0,0 +1,301 @@ +assertEquals('', (string) $url); + } + + public function testPortIsDeterminedFromScheme() + { + $this->assertEquals(80, Url::fromString('http://www.test.com/')->getPort()); + $this->assertEquals(443, Url::fromString('https://www.test.com/')->getPort()); + $this->assertEquals(21, Url::fromString('ftp://www.test.com/')->getPort()); + $this->assertEquals(8192, Url::fromString('http://www.test.com:8192/')->getPort()); + $this->assertEquals(null, Url::fromString('foo://www.test.com/')->getPort()); + } + + public function testRemovesDefaultPortWhenSettingScheme() + { + $url = Url::fromString('http://www.test.com/'); + $url->setPort(80); + $url->setScheme('https'); + $this->assertEquals(443, $url->getPort()); + } + + public function testCloneCreatesNewInternalObjects() + { + $u1 = Url::fromString('http://www.test.com/'); + $u2 = clone $u1; + $this->assertNotSame($u1->getQuery(), $u2->getQuery()); + } + + public function testValidatesUrlPartsInFactory() + { + $url = Url::fromString('/index.php'); + $this->assertEquals('/index.php', (string) $url); + $this->assertFalse($url->isAbsolute()); + + $url = 'http://michael:test@test.com:80/path/123?q=abc#test'; + $u = Url::fromString($url); + $this->assertEquals('http://michael:test@test.com/path/123?q=abc#test', (string) $u); + $this->assertTrue($u->isAbsolute()); + } + + public function testAllowsFalsyUrlParts() + { + $url = Url::fromString('http://a:50/0?0#0'); + $this->assertSame('a', $url->getHost()); + $this->assertEquals(50, $url->getPort()); + $this->assertSame('/0', $url->getPath()); + $this->assertEquals('0', (string) $url->getQuery()); + $this->assertSame('0', $url->getFragment()); + $this->assertEquals('http://a:50/0?0#0', (string) $url); + + $url = Url::fromString(''); + $this->assertSame('', (string) $url); + + $url = Url::fromString('0'); + $this->assertSame('0', (string) $url); + } + + public function testBuildsRelativeUrlsWithFalsyParts() + { + $url = Url::buildUrl(['path' => '/0']); + $this->assertSame('/0', $url); + + $url = Url::buildUrl(['path' => '0']); + $this->assertSame('0', $url); + } + + public function testUrlStoresParts() + { + $url = Url::fromString('http://test:pass@www.test.com:8081/path/path2/?a=1&b=2#fragment'); + $this->assertEquals('http', $url->getScheme()); + $this->assertEquals('test', $url->getUsername()); + $this->assertEquals('pass', $url->getPassword()); + $this->assertEquals('www.test.com', $url->getHost()); + $this->assertEquals(8081, $url->getPort()); + $this->assertEquals('/path/path2/', $url->getPath()); + $this->assertEquals('fragment', $url->getFragment()); + $this->assertEquals('a=1&b=2', (string) $url->getQuery()); + + $this->assertEquals(array( + 'fragment' => 'fragment', + 'host' => 'www.test.com', + 'pass' => 'pass', + 'path' => '/path/path2/', + 'port' => 8081, + 'query' => 'a=1&b=2', + 'scheme' => 'http', + 'user' => 'test' + ), $url->getParts()); + } + + public function testHandlesPathsCorrectly() + { + $url = Url::fromString('http://www.test.com'); + $this->assertEquals('', $url->getPath()); + $url->setPath('test'); + $this->assertEquals('test', $url->getPath()); + + $url->setPath('/test/123/abc'); + $this->assertEquals(array('', 'test', '123', 'abc'), $url->getPathSegments()); + + $parts = parse_url('http://www.test.com/test'); + $parts['path'] = ''; + $this->assertEquals('http://www.test.com', Url::buildUrl($parts)); + $parts['path'] = 'test'; + $this->assertEquals('http://www.test.com/test', Url::buildUrl($parts)); + } + + public function testAddsQueryIfPresent() + { + $this->assertEquals('?foo=bar', Url::buildUrl(array( + 'query' => 'foo=bar' + ))); + } + + public function testAddsToPath() + { + // Does nothing here + $this->assertEquals('http://e.com/base?a=1', (string) Url::fromString('http://e.com/base?a=1')->addPath(false)); + $this->assertEquals('http://e.com/base?a=1', (string) Url::fromString('http://e.com/base?a=1')->addPath('')); + $this->assertEquals('http://e.com/base?a=1', (string) Url::fromString('http://e.com/base?a=1')->addPath('/')); + $this->assertEquals('http://e.com/base/0', (string) Url::fromString('http://e.com/base')->addPath('0')); + + $this->assertEquals('http://e.com/base/relative?a=1', (string) Url::fromString('http://e.com/base?a=1')->addPath('relative')); + $this->assertEquals('http://e.com/base/relative?a=1', (string) Url::fromString('http://e.com/base?a=1')->addPath('/relative')); + } + + /** + * URL combination data provider + * + * @return array + */ + public function urlCombineDataProvider() + { + return [ + // Specific test cases + ['http://www.example.com/', 'http://www.example.com/', 'http://www.example.com/'], + ['http://www.example.com/path', '/absolute', 'http://www.example.com/absolute'], + ['http://www.example.com/path', '/absolute?q=2', 'http://www.example.com/absolute?q=2'], + ['http://www.example.com/', '?q=1', 'http://www.example.com/?q=1'], + ['http://www.example.com/path', 'http://test.com', 'http://test.com'], + ['http://www.example.com:8080/path', 'http://test.com', 'http://test.com'], + ['http://www.example.com:8080/path', '?q=2#abc', 'http://www.example.com:8080/path?q=2#abc'], + ['http://www.example.com/path', 'http://u:a@www.example.com/', 'http://u:a@www.example.com/'], + ['/path?q=2', 'http://www.test.com/', 'http://www.test.com/path?q=2'], + ['http://api.flickr.com/services/', 'http://www.flickr.com/services/oauth/access_token', 'http://www.flickr.com/services/oauth/access_token'], + ['https://www.example.com/path', '//foo.com/abc', 'https://foo.com/abc'], + // RFC 3986 test cases + [self::RFC3986_BASE, 'g:h', 'g:h'], + [self::RFC3986_BASE, 'g', 'http://a/b/c/g'], + [self::RFC3986_BASE, './g', 'http://a/b/c/g'], + [self::RFC3986_BASE, 'g/', 'http://a/b/c/g/'], + [self::RFC3986_BASE, '/g', 'http://a/g'], + [self::RFC3986_BASE, '//g', 'http://g'], + [self::RFC3986_BASE, '?y', 'http://a/b/c/d;p?y'], + [self::RFC3986_BASE, 'g?y', 'http://a/b/c/g?y'], + [self::RFC3986_BASE, '#s', 'http://a/b/c/d;p?q#s'], + [self::RFC3986_BASE, 'g#s', 'http://a/b/c/g#s'], + [self::RFC3986_BASE, 'g?y#s', 'http://a/b/c/g?y#s'], + [self::RFC3986_BASE, ';x', 'http://a/b/c/;x'], + [self::RFC3986_BASE, 'g;x', 'http://a/b/c/g;x'], + [self::RFC3986_BASE, 'g;x?y#s', 'http://a/b/c/g;x?y#s'], + [self::RFC3986_BASE, '', self::RFC3986_BASE], + [self::RFC3986_BASE, '.', 'http://a/b/c/'], + [self::RFC3986_BASE, './', 'http://a/b/c/'], + [self::RFC3986_BASE, '..', 'http://a/b/'], + [self::RFC3986_BASE, '../', 'http://a/b/'], + [self::RFC3986_BASE, '../g', 'http://a/b/g'], + [self::RFC3986_BASE, '../..', 'http://a/'], + [self::RFC3986_BASE, '../../', 'http://a/'], + [self::RFC3986_BASE, '../../g', 'http://a/g'], + [self::RFC3986_BASE, '../../../g', 'http://a/g'], + [self::RFC3986_BASE, '../../../../g', 'http://a/g'], + [self::RFC3986_BASE, '/./g', 'http://a/g'], + [self::RFC3986_BASE, '/../g', 'http://a/g'], + [self::RFC3986_BASE, 'g.', 'http://a/b/c/g.'], + [self::RFC3986_BASE, '.g', 'http://a/b/c/.g'], + [self::RFC3986_BASE, 'g..', 'http://a/b/c/g..'], + [self::RFC3986_BASE, '..g', 'http://a/b/c/..g'], + [self::RFC3986_BASE, './../g', 'http://a/b/g'], + [self::RFC3986_BASE, './g/.', 'http://a/b/c/g/'], + [self::RFC3986_BASE, 'g/./h', 'http://a/b/c/g/h'], + [self::RFC3986_BASE, 'g/../h', 'http://a/b/c/h'], + [self::RFC3986_BASE, 'g;x=1/./y', 'http://a/b/c/g;x=1/y'], + [self::RFC3986_BASE, 'g;x=1/../y', 'http://a/b/c/y'], + [self::RFC3986_BASE, 'http:g', 'http:g'], + ]; + } + + /** + * @dataProvider urlCombineDataProvider + */ + public function testCombinesUrls($a, $b, $c) + { + $this->assertEquals($c, (string) Url::fromString($a)->combine($b)); + } + + public function testHasGettersAndSetters() + { + $url = Url::fromString('http://www.test.com/'); + $this->assertEquals('example.com', $url->setHost('example.com')->getHost()); + $this->assertEquals('8080', $url->setPort(8080)->getPort()); + $this->assertEquals('/foo/bar', $url->setPath('/foo/bar')->getPath()); + $this->assertEquals('a', $url->setPassword('a')->getPassword()); + $this->assertEquals('b', $url->setUsername('b')->getUsername()); + $this->assertEquals('abc', $url->setFragment('abc')->getFragment()); + $this->assertEquals('https', $url->setScheme('https')->getScheme()); + $this->assertEquals('a=123', (string) $url->setQuery('a=123')->getQuery()); + $this->assertEquals('https://b:a@example.com:8080/foo/bar?a=123#abc', (string) $url); + $this->assertEquals('b=boo', (string) $url->setQuery(new Query(array( + 'b' => 'boo' + )))->getQuery()); + $this->assertEquals('https://b:a@example.com:8080/foo/bar?b=boo#abc', (string) $url); + } + + public function testSetQueryAcceptsArray() + { + $url = Url::fromString('http://www.test.com'); + $url->setQuery(array('a' => 'b')); + $this->assertEquals('http://www.test.com?a=b', (string) $url); + } + + /** + * @expectedException \InvalidArgumentException + */ + public function testQueryMustBeValid() + { + $url = Url::fromString('http://www.test.com'); + $url->setQuery(false); + } + + public function urlProvider() + { + return array( + array('/foo/..', '/'), + array('//foo//..', '/'), + array('/foo/../..', '/'), + array('/foo/../.', '/'), + array('/./foo/..', '/'), + array('/./foo', '/foo'), + array('/./foo/', '/foo/'), + array('*', '*'), + array('/foo', '/foo'), + array('/abc/123/../foo/', '/abc/foo/'), + array('/a/b/c/./../../g', '/a/g'), + array('/b/c/./../../g', '/g'), + array('/b/c/./../../g', '/g'), + array('/c/./../../g', '/g'), + array('/./../../g', '/g'), + array('foo', 'foo'), + ); + } + + /** + * @dataProvider urlProvider + */ + public function testRemoveDotSegments($path, $result) + { + $url = Url::fromString('http://www.example.com'); + $url->setPath($path)->removeDotSegments(); + $this->assertEquals($result, $url->getPath()); + } + + public function testSettingHostWithPortModifiesPort() + { + $url = Url::fromString('http://www.example.com'); + $url->setHost('foo:8983'); + $this->assertEquals('foo', $url->getHost()); + $this->assertEquals(8983, $url->getPort()); + } + + /** + * @expectedException \InvalidArgumentException + */ + public function testValidatesUrlCanBeParsed() + { + Url::fromString('foo:////'); + } + + public function testConvertsSpecialCharsInPathWhenCastingToString() + { + $url = Url::fromString('http://foo.com/baz bar?a=b'); + $url->addPath('?'); + $this->assertEquals('http://foo.com/baz%20bar/%3F?a=b', (string) $url); + } +} diff --git a/core/vendor/guzzlehttp/guzzle/tests/bootstrap.php b/core/vendor/guzzlehttp/guzzle/tests/bootstrap.php new file mode 100644 index 00000000000..6c3ded321d7 --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/tests/bootstrap.php @@ -0,0 +1,12 @@ + Server::$url]); + +$t = microtime(true); +for ($i = 0; $i < $total; $i++) { + $client->get('/guzzle-server/perf'); +} +$totalTime = microtime(true) - $t; +$perRequest = ($totalTime / $total) * 1000; +printf("Serial: %f (%f ms / request) %d total\n", + $totalTime, $perRequest, $total); + +// Create a generator used to yield batches of requests to sendAll +$reqs = function () use ($client, $total) { + for ($i = 0; $i < $total; $i++) { + yield $client->createRequest('GET', '/guzzle-server/perf'); + } +}; + +$t = microtime(true); +$client->sendAll($reqs(), ['parallel' => $parallel]); +$totalTime = microtime(true) - $t; +$perRequest = ($totalTime / $total) * 1000; +printf("Parallel: %f (%f ms / request) %d total with %d in parallel\n", + $totalTime, $perRequest, $total, $parallel); diff --git a/core/vendor/guzzlehttp/guzzle/tests/server.js b/core/vendor/guzzlehttp/guzzle/tests/server.js new file mode 100644 index 00000000000..4156f1aad78 --- /dev/null +++ b/core/vendor/guzzlehttp/guzzle/tests/server.js @@ -0,0 +1,146 @@ +/** + * Guzzle node.js test server to return queued responses to HTTP requests and + * expose a RESTful API for enqueueing responses and retrieving the requests + * that have been received. + * + * - Delete all requests that have been received: + * DELETE /guzzle-server/requests + * Host: 127.0.0.1:8124 + * + * - Enqueue responses + * PUT /guzzle-server/responses + * Host: 127.0.0.1:8124 + * + * [{ "statusCode": 200, "reasonPhrase": "OK", "headers": {}, "body": "" }] + * + * - Get the received requests + * GET /guzzle-server/requests + * Host: 127.0.0.1:8124 + * + * - Shutdown the server + * DELETE /guzzle-server + * Host: 127.0.0.1:8124 + * + * @package Guzzle PHP + * @license See the LICENSE file that was distributed with this source code. + */ + +var http = require("http"); + +/** + * Guzzle node.js server + * @class + */ +var GuzzleServer = function(port, log) { + + this.port = port; + this.log = log; + this.responses = []; + this.requests = []; + var that = this; + + var controlRequest = function(request, req, res) { + if (req.url == '/guzzle-server/perf') { + res.writeHead(200, "OK", {"Content-Length": 16}); + res.end("Body of response"); + } else if (req.method == "DELETE") { + if (req.url == "/guzzle-server/requests") { + // Clear the received requests + that.requests = []; + res.writeHead(200, "OK", { "Content-Length": 0 }); + res.end(); + if (this.log) { + console.log("Flushing requests"); + } + } else if (req.url == "/guzzle-server") { + // Shutdown the server + res.writeHead(200, "OK", { "Content-Length": 0, "Connection": "close" }); + res.end(); + if (this.log) { + console.log("Shutting down"); + } + that.server.close(); + } + } else if (req.method == "GET") { + if (req.url === "/guzzle-server/requests") { + // Get received requests + var data = that.requests.join("\n----[request]\n"); + res.writeHead(200, "OK", { "Content-Length": data.length }); + res.end(data); + if (that.log) { + console.log("Sending receiving requests"); + } + } + } else if (req.method == "PUT") { + if (req.url == "/guzzle-server/responses") { + if (that.log) { + console.log("Adding responses..."); + } + // Received response to queue + var data = request.split("\r\n\r\n")[1]; + if (!data) { + if (that.log) { + console.log("No response data was provided"); + } + res.writeHead(400, "NO RESPONSES IN REQUEST", { "Content-Length": 0 }); + } else { + that.responses = eval("(" + data + ")"); + if (that.log) { + console.log(that.responses); + } + res.writeHead(200, "OK", { "Content-Length": 0 }); + } + res.end(); + } + } + }; + + var receivedRequest = function(request, req, res) { + if (req.url.indexOf("/guzzle-server") === 0) { + controlRequest(request, req, res); + } else if (req.url.indexOf("/guzzle-server") == -1 && !that.responses.length) { + res.writeHead(500); + res.end("No responses in queue"); + } else { + var response = that.responses.shift(); + res.writeHead(response.statusCode, response.reasonPhrase, response.headers); + res.end(response.body); + that.requests.push(request); + } + }; + + this.start = function() { + + that.server = http.createServer(function(req, res) { + + var request = req.method + " " + req.url + " HTTP/" + req.httpVersion + "\r\n"; + for (var i in req.headers) { + request += i + ": " + req.headers[i] + "\r\n"; + } + request += "\r\n"; + + // Receive each chunk of the request body + req.addListener("data", function(chunk) { + request += chunk; + }); + + // Called when the request completes + req.addListener("end", function() { + receivedRequest(request, req, res); + }); + }); + that.server.listen(port, "127.0.0.1"); + + if (this.log) { + console.log("Server running at http://127.0.0.1:8124/"); + } + }; +}; + +// Get the port from the arguments +port = process.argv.length >= 3 ? process.argv[2] : 8124; +log = process.argv.length >= 4 ? process.argv[3] : false; + +// Start the server +server = new GuzzleServer(port, log); +server.start(); diff --git a/core/vendor/guzzlehttp/streams/.gitignore b/core/vendor/guzzlehttp/streams/.gitignore new file mode 100644 index 00000000000..c33d3965fdd --- /dev/null +++ b/core/vendor/guzzlehttp/streams/.gitignore @@ -0,0 +1,6 @@ +.idea +.DS_STORE +coverage +phpunit.xml +composer.lock +vendor/ diff --git a/core/vendor/guzzlehttp/streams/.travis.yml b/core/vendor/guzzlehttp/streams/.travis.yml new file mode 100644 index 00000000000..90df122be4d --- /dev/null +++ b/core/vendor/guzzlehttp/streams/.travis.yml @@ -0,0 +1,12 @@ +language: php + +php: + - 5.4 + - 5.5 + - 5.6 + - hhvm + +before_script: + - composer install + +script: vendor/bin/phpunit diff --git a/core/vendor/guzzlehttp/streams/LICENSE b/core/vendor/guzzlehttp/streams/LICENSE new file mode 100644 index 00000000000..71d3b783cb5 --- /dev/null +++ b/core/vendor/guzzlehttp/streams/LICENSE @@ -0,0 +1,19 @@ +Copyright (c) 2014 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. diff --git a/core/vendor/guzzlehttp/streams/Makefile b/core/vendor/guzzlehttp/streams/Makefile new file mode 100644 index 00000000000..c39ff76e72e --- /dev/null +++ b/core/vendor/guzzlehttp/streams/Makefile @@ -0,0 +1,13 @@ +all: clean coverage + +test: + vendor/bin/phpunit + +coverage: + vendor/bin/phpunit --coverage-html=artifacts/coverage + +view-coverage: + open artifacts/coverage/index.html + +clean: + rm -rf artifacts/* diff --git a/core/vendor/guzzlehttp/streams/README.rst b/core/vendor/guzzlehttp/streams/README.rst new file mode 100644 index 00000000000..3fe5dad0540 --- /dev/null +++ b/core/vendor/guzzlehttp/streams/README.rst @@ -0,0 +1,36 @@ +============== +Guzzle Streams +============== + +Provides a simple abstraction over streams of data. + +This library is used in `Guzzle 4 `_ and is +an implementation of the proposed `PSR-7 stream interface `_. + +Installation +============ + +This package can be installed easily using `Composer `_. +Simply add the following to the composer.json file at the root of your project: + +.. code-block:: javascript + + { + "require": { + "guzzlehttp/streams": "1.*" + } + } + +Then install your dependencies using ``composer.phar install``. + +Documentation +============= + +The documentation for this package can be found on the main Guzzle website at +http://docs.guzzlephp.org/en/guzzle4/streams.html. + +Testing +======= + +This library is tested using PHPUnit. You'll need to install the dependencies +using `Composer `_ then run ``make test``. diff --git a/core/vendor/guzzlehttp/streams/composer.json b/core/vendor/guzzlehttp/streams/composer.json new file mode 100644 index 00000000000..6cae568f603 --- /dev/null +++ b/core/vendor/guzzlehttp/streams/composer.json @@ -0,0 +1,29 @@ +{ + "name": "guzzlehttp/streams", + "description": "Provides a simple abstraction over streams of data (Guzzle 4+)", + "homepage": "http://guzzlephp.org/", + "keywords": ["stream", "guzzle"], + "license": "MIT", + "authors": [ + { + "name": "Michael Dowling", + "email": "mtdowling@gmail.com", + "homepage": "https://github.com/mtdowling" + } + ], + "require": { + "php": ">=5.4.0" + }, + "require-dev": { + "phpunit/phpunit": "4.*" + }, + "autoload": { + "psr-4": { "GuzzleHttp\\Stream\\": "src/" }, + "files": ["src/functions.php"] + }, + "extra": { + "branch-alias": { + "dev-master": "1.0.x-dev" + } + } +} diff --git a/core/vendor/guzzlehttp/streams/phpunit.xml.dist b/core/vendor/guzzlehttp/streams/phpunit.xml.dist new file mode 100644 index 00000000000..994e1584eac --- /dev/null +++ b/core/vendor/guzzlehttp/streams/phpunit.xml.dist @@ -0,0 +1,14 @@ + + + + + tests + + + + + src + + + diff --git a/core/vendor/guzzlehttp/streams/src/CachingStream.php b/core/vendor/guzzlehttp/streams/src/CachingStream.php new file mode 100644 index 00000000000..35419f1ed95 --- /dev/null +++ b/core/vendor/guzzlehttp/streams/src/CachingStream.php @@ -0,0 +1,119 @@ +remoteStream = $stream; + $this->stream = $target ?: new Stream(fopen('php://temp', 'r+')); + } + + public function getSize() + { + return max($this->stream->getSize(), $this->remoteStream->getSize()); + } + + /** + * {@inheritdoc} + * @throws \RuntimeException When seeking with SEEK_END or when seeking + * past the total size of the buffer stream + */ + public function seek($offset, $whence = SEEK_SET) + { + if ($whence == SEEK_SET) { + $byte = $offset; + } elseif ($whence == SEEK_CUR) { + $byte = $offset + $this->tell(); + } else { + throw new \RuntimeException(__CLASS__ . ' supports only SEEK_SET' + .' and SEEK_CUR seek operations'); + } + + // You cannot skip ahead past where you've read from the remote stream + if ($byte > $this->stream->getSize()) { + throw new \RuntimeException(sprintf('Cannot seek to byte %d when ' + . ' the buffered stream only contains %d bytes', + $byte, $this->stream->getSize())); + } + + return $this->stream->seek($byte); + } + + public function read($length) + { + // Perform a regular read on any previously read data from the buffer + $data = $this->stream->read($length); + $remaining = $length - strlen($data); + + // More data was requested so read from the remote stream + if ($remaining) { + // If data was written to the buffer in a position that would have + // been filled from the remote stream, then we must skip bytes on + // the remote stream to emulate overwriting bytes from that + // position. This mimics the behavior of other PHP stream wrappers. + $remoteData = $this->remoteStream->read( + $remaining + $this->skipReadBytes + ); + + if ($this->skipReadBytes) { + $len = strlen($remoteData); + $remoteData = substr($remoteData, $this->skipReadBytes); + $this->skipReadBytes = max(0, $this->skipReadBytes - $len); + } + + $data .= $remoteData; + $this->stream->write($remoteData); + } + + return $data; + } + + public function write($string) + { + // When appending to the end of the currently read stream, you'll want + // to skip bytes from being read from the remote stream to emulate + // other stream wrappers. Basically replacing bytes of data of a fixed + // length. + $overflow = (strlen($string) + $this->tell()) - $this->remoteStream->tell(); + if ($overflow > 0) { + $this->skipReadBytes += $overflow; + } + + return $this->stream->write($string); + } + + public function eof() + { + return $this->stream->eof() && $this->remoteStream->eof(); + } + + /** + * Close both the remote stream and buffer stream + */ + public function close() + { + $this->remoteStream->close() && $this->stream->close(); + } +} diff --git a/core/vendor/guzzlehttp/streams/src/LimitStream.php b/core/vendor/guzzlehttp/streams/src/LimitStream.php new file mode 100644 index 00000000000..8c481a42cd6 --- /dev/null +++ b/core/vendor/guzzlehttp/streams/src/LimitStream.php @@ -0,0 +1,149 @@ +stream = $stream; + $this->setLimit($limit); + $this->setOffset($offset); + } + + public function eof() + { + if ($this->limit == -1) { + return $this->stream->eof(); + } + + $tell = $this->stream->tell(); + + return $tell === false || (($this->offset + $this->limit) - $tell) <= 0; + } + + /** + * Returns the size of the limited subset of data + * {@inheritdoc} + */ + public function getSize() + { + if (null === ($length = $this->stream->getSize())) { + return null; + } elseif ($this->limit == -1) { + return $length - $this->offset; + } else { + return min($this->limit, $length - $this->offset); + } + } + + /** + * Allow for a bounded seek on the read limited stream + * {@inheritdoc} + */ + public function seek($offset, $whence = SEEK_SET) + { + if ($whence != SEEK_SET) { + return false; + } + + if ($offset < $this->offset) { + $offset = $this->offset; + } + + if ($this->limit !== -1 && $offset > ($this->offset + $this->limit)) { + $offset = $this->offset + $this->limit; + } + + return $this->stream->seek($offset); + } + + /** + * Give a relative tell() + * {@inheritdoc} + */ + public function tell() + { + return $this->stream->tell() - $this->offset; + } + + /** + * Set the offset to start limiting from + * + * @param int $offset Offset to seek to and begin byte limiting from + * + * @return self + * @throws \RuntimeException + */ + public function setOffset($offset) + { + $this->offset = $offset; + $current = $this->stream->tell(); + if ($current !== $offset) { + // If the stream cannot seek to the offset position, then read to it + if (!$this->stream->seek($offset)) { + if ($current > $offset) { + throw new \RuntimeException("Cannot seek to stream offset {$offset}"); + } else { + $this->stream->read($offset - $current); + } + } + } + + return $this; + } + + /** + * Set the limit of bytes that the decorator allows to be read from the + * stream. + * + * @param int $limit Number of bytes to allow to be read from the stream. + * Use -1 for no limit. + * @return self + */ + public function setLimit($limit) + { + $this->limit = $limit; + + return $this; + } + + public function read($length) + { + if ($this->limit == -1) { + return $this->stream->read($length); + } + + // Check if the current position is less than the total allowed + // bytes + original offset + $remaining = ($this->offset + $this->limit) - $this->stream->tell(); + if ($remaining > 0) { + // Only return the amount of requested data, ensuring that the byte + // limit is not exceeded + return $this->stream->read(min($remaining, $length)); + } else { + return false; + } + } +} diff --git a/core/vendor/guzzlehttp/streams/src/MetadataStreamInterface.php b/core/vendor/guzzlehttp/streams/src/MetadataStreamInterface.php new file mode 100644 index 00000000000..3cd96d68aa8 --- /dev/null +++ b/core/vendor/guzzlehttp/streams/src/MetadataStreamInterface.php @@ -0,0 +1,25 @@ + [ + 'r' => true, 'w+' => true, 'r+' => true, 'x+' => true, 'c+' => true, + 'rb' => true, 'w+b' => true, 'r+b' => true, 'x+b' => true, + 'c+b' => true, 'rt' => true, 'w+t' => true, 'r+t' => true, + 'x+t' => true, 'c+t' => true, 'a+' => true + ], + 'write' => [ + 'w' => true, 'w+' => true, 'rw' => true, 'r+' => true, 'x+' => true, + 'c+' => true, 'wb' => true, 'w+b' => true, 'r+b' => true, + 'x+b' => true, 'c+b' => true, 'w+t' => true, 'r+t' => true, + 'x+t' => true, 'c+t' => true, 'a' => true, 'a+' => true + ] + ]; + + /** + * Create a new stream based on the input type + * + * @param resource|string|StreamInterface $resource Entity body data + * @param int $size Size of the data contained in the resource + * + * @return StreamInterface + * @throws \InvalidArgumentException if the $resource arg is not valid. + */ + public static function factory($resource = '', $size = null) + { + return create($resource, $size); + } + + /** + * @param resource $stream Stream resource to wrap + * @param int $size Size of the stream in bytes. Only pass if the + * size cannot be obtained from the stream. + * + * @throws \InvalidArgumentException if the stream is not a stream resource + */ + public function __construct($stream, $size = null) + { + if (!is_resource($stream)) { + throw new \InvalidArgumentException('Stream must be a resource'); + } + + $this->size = $size; + $this->stream = $stream; + $this->meta = stream_get_meta_data($this->stream); + $this->seekable = $this->meta['seekable']; + $this->readable = isset(self::$readWriteHash['read'][$this->meta['mode']]); + $this->writable = isset(self::$readWriteHash['write'][$this->meta['mode']]); + } + + /** + * Closes the stream when the destructed + */ + public function __destruct() + { + $this->close(); + } + + public function __toString() + { + $this->seek(0); + + return (string) stream_get_contents($this->stream); + } + + public function getContents($maxLength = -1) + { + return stream_get_contents($this->stream, $maxLength); + } + + public function close() + { + if (is_resource($this->stream)) { + fclose($this->stream); + } + $this->meta = []; + $this->stream = null; + } + + public function detach() + { + $this->stream = null; + } + + public function getSize() + { + if ($this->size !== null) { + return $this->size; + } + + // If the stream is a file based stream and local, then use fstat + clearstatcache(true, $this->meta['uri']); + $stats = fstat($this->stream); + if (isset($stats['size'])) { + $this->size = $stats['size']; + return $this->size; + } + + return null; + } + + public function isReadable() + { + return $this->stream && $this->readable; + } + + public function isWritable() + { + return $this->stream && $this->writable; + } + + public function isSeekable() + { + return $this->stream && $this->seekable; + } + + public function eof() + { + return feof($this->stream); + } + + public function tell() + { + return ftell($this->stream); + } + + public function setSize($size) + { + $this->size = $size; + + return $this; + } + + public function seek($offset, $whence = SEEK_SET) + { + return $this->seekable + ? fseek($this->stream, $offset, $whence) === 0 + : false; + } + + public function read($length) + { + return fread($this->stream, $length); + } + + public function write($string) + { + // We can't know the size after writing anything + $this->size = null; + + return fwrite($this->stream, $string); + } + + /** + * Get stream metadata as an associative array or retrieve a specific key. + * + * The keys returned are identical to the keys returned from PHP's + * stream_get_meta_data() function. + * + * @param string $key Specific metadata to retrieve. + * + * @return array|mixed|null Returns an associative array if no key is + * no key is provided. Returns a specific key + * value if a key is provided and the value is + * found, or null if the key is not found. + * @see http://php.net/manual/en/function.stream-get-meta-data.php + */ + public function getMetadata($key = null) + { + return !$key + ? $this->meta + : (isset($this->meta[$key]) ? $this->meta[$key] : null); + } +} diff --git a/core/vendor/guzzlehttp/streams/src/StreamDecoratorTrait.php b/core/vendor/guzzlehttp/streams/src/StreamDecoratorTrait.php new file mode 100644 index 00000000000..801129742c1 --- /dev/null +++ b/core/vendor/guzzlehttp/streams/src/StreamDecoratorTrait.php @@ -0,0 +1,118 @@ +stream = $stream; + } + + public function __toString() + { + try { + $this->seek(0); + return $this->getContents(); + } catch (\Exception $e) { + // Really, PHP? https://bugs.php.net/bug.php?id=53648 + trigger_error('StreamDecorator::__toString exception: ' + . (string) $e, E_USER_ERROR); + return ''; + } + } + + public function getContents($maxLength = -1) + { + return copy_to_string($this, $maxLength); + } + + /** + * Allow decorators to implement custom methods + * + * @param string $method Missing method name + * @param array $args Method arguments + * + * @return mixed + */ + public function __call($method, array $args) + { + $result = call_user_func_array(array($this->stream, $method), $args); + + // Always return the wrapped object if the result is a return $this + return $result === $this->stream ? $this : $result; + } + + public function close() + { + return $this->stream->close(); + } + + public function getMetadata($key = null) + { + return $this->stream instanceof MetadataStreamInterface + ? $this->stream->getMetadata($key) + : null; + } + + public function detach() + { + $this->stream->detach(); + + return $this; + } + + public function getSize() + { + return $this->stream->getSize(); + } + + public function eof() + { + return $this->stream->eof(); + } + + public function tell() + { + return $this->stream->tell(); + } + + public function isReadable() + { + return $this->stream->isReadable(); + } + + public function isWritable() + { + return $this->stream->isWritable(); + } + + public function isSeekable() + { + return $this->stream->isSeekable(); + } + + public function seek($offset, $whence = SEEK_SET) + { + return $this->stream->seek($offset, $whence); + } + + public function read($length) + { + return $this->stream->read($length); + } + + public function write($string) + { + return $this->stream->write($string); + } +} diff --git a/core/vendor/guzzlehttp/streams/src/StreamInterface.php b/core/vendor/guzzlehttp/streams/src/StreamInterface.php new file mode 100644 index 00000000000..7e07cf73cdb --- /dev/null +++ b/core/vendor/guzzlehttp/streams/src/StreamInterface.php @@ -0,0 +1,119 @@ +eof()) { + $buf = $stream->read(1048576); + if ($buf === '' || $buf === false) { + break; + } + $buffer .= $buf; + } + } else { + $len = 0; + while (!$stream->eof() && $len < $maxLen) { + $buf = $stream->read($maxLen - $len); + if ($buf === '' || $buf === false) { + break; + } + $buffer .= $buf; + $len = strlen($buffer); + } + } + + return $buffer; +} + +/** + * Copy the contents of a stream into another stream until the given number of + * bytes have been read. + * + * @param StreamInterface $source Stream to read from + * @param StreamInterface $dest Stream to write to + * @param int $maxLen Maximum number of bytes to read. Pass -1 to + * read the entire stream. + */ +function copy_to_stream( + StreamInterface $source, + StreamInterface $dest, + $maxLen = -1 +) { + if ($maxLen === -1) { + while (!$source->eof()) { + if (!$dest->write($source->read(1048576))) { + break; + } + } + return; + } + + $bytes = 0; + while (!$source->eof()) { + $buf = $source->read($maxLen - $bytes); + if (!($len = strlen($buf))) { + break; + } + $bytes += $len; + $dest->write($buf); + if ($bytes == $maxLen) { + break; + } + } +} + +/** + * Calculate a hash of a Stream + * + * @param StreamInterface $stream Stream to calculate the hash for + * @param string $algo Hash algorithm (e.g. md5, crc32, etc) + * @param bool $rawOutput Whether or not to use raw output + * + * @return bool|string Returns false on failure or a hash string on success + */ +function hash( + StreamInterface $stream, + $algo, + $rawOutput = false +) { + $pos = $stream->tell(); + if (!$stream->seek(0)) { + return false; + } + + $ctx = hash_init($algo); + while ($data = $stream->read(1048576)) { + hash_update($ctx, $data); + } + + $out = hash_final($ctx, (bool) $rawOutput); + $stream->seek($pos); + + return $out; +} + +/** + * Read a line from the stream up to the maximum allowed buffer length + * + * @param StreamInterface $stream Stream to read from + * @param int $maxLength Maximum buffer length + * + * @return string|bool + */ +function read_line(StreamInterface $stream, $maxLength = null) +{ + $buffer = ''; + $size = 0; + + while (!$stream->eof()) { + if (false === ($byte = $stream->read(1))) { + return $buffer; + } + $buffer .= $byte; + // Break when a new line is found or the max length - 1 is reached + if ($byte == PHP_EOL || ++$size == $maxLength - 1) { + break; + } + } + + return $buffer; +} diff --git a/core/vendor/guzzlehttp/streams/tests/CachingStreamTest.php b/core/vendor/guzzlehttp/streams/tests/CachingStreamTest.php new file mode 100644 index 00000000000..a7688ba26da --- /dev/null +++ b/core/vendor/guzzlehttp/streams/tests/CachingStreamTest.php @@ -0,0 +1,141 @@ +decorated = Stream::factory('testing'); + $this->body = new CachingStream($this->decorated); + } + + public function tearDown() + { + $this->decorated->close(); + $this->body->close(); + } + + public function testUsesRemoteSizeIfPossible() + { + $body = Stream::factory('test'); + $caching = new CachingStream($body); + $this->assertEquals(4, $caching->getSize()); + } + + /** + * @expectedException \RuntimeException + * @expectedExceptionMessage Cannot seek to byte 10 + */ + public function testCannotSeekPastWhatHasBeenRead() + { + $this->body->seek(10); + } + + /** + * @expectedException \RuntimeException + * @expectedExceptionMessage supports only SEEK_SET and SEEK_CUR + */ + public function testCannotUseSeekEnd() + { + $this->body->seek(2, SEEK_END); + } + + public function testRewindUsesSeek() + { + $a = Stream::factory('foo'); + $d = $this->getMockBuilder('GuzzleHttp\Stream\CachingStream') + ->setMethods(array('seek')) + ->setConstructorArgs(array($a)) + ->getMock(); + $d->expects($this->once()) + ->method('seek') + ->with(0) + ->will($this->returnValue(true)); + $d->seek(0); + } + + public function testCanSeekToReadBytes() + { + $this->assertEquals('te', $this->body->read(2)); + $this->body->seek(0); + $this->assertEquals('test', $this->body->read(4)); + $this->assertEquals(4, $this->body->tell()); + $this->body->seek(2); + $this->assertEquals(2, $this->body->tell()); + $this->body->seek(2, SEEK_CUR); + $this->assertEquals(4, $this->body->tell()); + $this->assertEquals('ing', $this->body->read(3)); + } + + public function testWritesToBufferStream() + { + $this->body->read(2); + $this->body->write('hi'); + $this->body->seek(0); + $this->assertEquals('tehiing', (string) $this->body); + } + + public function testSkipsOverwrittenBytes() + { + $decorated = Stream::factory( + implode("\n", array_map(function ($n) { + return str_pad($n, 4, '0', STR_PAD_LEFT); + }, range(0, 25))), + true + ); + + $body = new CachingStream($decorated); + + $this->assertEquals("0000\n", \GuzzleHttp\Stream\read_line($body)); + $this->assertEquals("0001\n", \GuzzleHttp\Stream\read_line($body)); + // Write over part of the body yet to be read, so skip some bytes + $this->assertEquals(5, $body->write("TEST\n")); + $this->assertEquals(5, $this->readAttribute($body, 'skipReadBytes')); + // Read, which skips bytes, then reads + $this->assertEquals("0003\n", \GuzzleHttp\Stream\read_line($body)); + $this->assertEquals(0, $this->readAttribute($body, 'skipReadBytes')); + $this->assertEquals("0004\n", \GuzzleHttp\Stream\read_line($body)); + $this->assertEquals("0005\n", \GuzzleHttp\Stream\read_line($body)); + + // Overwrite part of the cached body (so don't skip any bytes) + $body->seek(5); + $this->assertEquals(5, $body->write("ABCD\n")); + $this->assertEquals(0, $this->readAttribute($body, 'skipReadBytes')); + $this->assertEquals("TEST\n", \GuzzleHttp\Stream\read_line($body)); + $this->assertEquals("0003\n", \GuzzleHttp\Stream\read_line($body)); + $this->assertEquals("0004\n", \GuzzleHttp\Stream\read_line($body)); + $this->assertEquals("0005\n", \GuzzleHttp\Stream\read_line($body)); + $this->assertEquals("0006\n", \GuzzleHttp\Stream\read_line($body)); + $this->assertEquals(5, $body->write("1234\n")); + $this->assertEquals(5, $this->readAttribute($body, 'skipReadBytes')); + + // Seek to 0 and ensure the overwritten bit is replaced + $body->seek(0); + $this->assertEquals("0000\nABCD\nTEST\n0003\n0004\n0005\n0006\n1234\n0008\n0009\n", $body->read(50)); + + // Ensure that casting it to a string does not include the bit that was overwritten + $this->assertContains("0000\nABCD\nTEST\n0003\n0004\n0005\n0006\n1234\n0008\n0009\n", (string) $body); + } + + public function testClosesBothStreams() + { + $s = fopen('php://temp', 'r'); + $a = Stream::factory($s); + $d = new CachingStream($a); + $d->close(); + $this->assertFalse(is_resource($s)); + } +} diff --git a/core/vendor/guzzlehttp/streams/tests/LimitStreamTest.php b/core/vendor/guzzlehttp/streams/tests/LimitStreamTest.php new file mode 100644 index 00000000000..8a07c492518 --- /dev/null +++ b/core/vendor/guzzlehttp/streams/tests/LimitStreamTest.php @@ -0,0 +1,95 @@ +decorated = Stream::factory(fopen(__FILE__, 'r')); + $this->body = new LimitStream($this->decorated, 10, 3); + } + + public function testReturnsSubset() + { + $body = new LimitStream(Stream::factory('foo'), -1, 1); + $this->assertEquals('oo', (string) $body); + $this->assertTrue($body->eof()); + $body->seek(0); + $this->assertFalse($body->eof()); + $this->assertEquals('oo', $body->read(100)); + $this->assertTrue($body->eof()); + } + + public function testReturnsSubsetWhenCastToString() + { + $body = Stream::factory('foo_baz_bar'); + $limited = new LimitStream($body, 3, 4); + $this->assertEquals('baz', (string) $limited); + } + + public function testReturnsSubsetOfEmptyBodyWhenCastToString() + { + $body = Stream::factory(''); + $limited = new LimitStream($body, 0, 10); + $this->assertEquals('', (string) $limited); + } + + public function testSeeksWhenConstructed() + { + $this->assertEquals(0, $this->body->tell()); + $this->assertEquals(3, $this->decorated->tell()); + } + + public function testAllowsBoundedSeek() + { + $this->body->seek(100); + $this->assertEquals(13, $this->decorated->tell()); + $this->body->seek(0); + $this->assertEquals(0, $this->body->tell()); + $this->assertEquals(3, $this->decorated->tell()); + $this->assertEquals(false, $this->body->seek(1000, SEEK_END)); + } + + public function testReadsOnlySubsetOfData() + { + $data = $this->body->read(100); + $this->assertEquals(10, strlen($data)); + $this->assertFalse($this->body->read(1000)); + + $this->body->setOffset(10); + $newData = $this->body->read(100); + $this->assertEquals(10, strlen($newData)); + $this->assertNotSame($data, $newData); + } + + public function testClaimsConsumedWhenReadLimitIsReached() + { + $this->assertFalse($this->body->eof()); + $this->body->read(1000); + $this->assertTrue($this->body->eof()); + } + + public function testContentLengthIsBounded() + { + $this->assertEquals(10, $this->body->getSize()); + } + + public function testGetContentsIsBasedOnSubset() + { + $body = new LimitStream(Stream::factory('foobazbar'), 3, 3); + $this->assertEquals('baz', $body->getContents()); + } +} diff --git a/core/vendor/guzzlehttp/streams/tests/NoSeekStreamTest.php b/core/vendor/guzzlehttp/streams/tests/NoSeekStreamTest.php new file mode 100644 index 00000000000..b8988eead30 --- /dev/null +++ b/core/vendor/guzzlehttp/streams/tests/NoSeekStreamTest.php @@ -0,0 +1,24 @@ +getMockBuilder('GuzzleHttp\Stream\StreamInterface') + ->setMethods(['isSeekable', 'seek']) + ->getMockForAbstractClass(); + $s->expects($this->never())->method('seek'); + $s->expects($this->never())->method('isSeekable'); + $wrapped = new NoSeekStream($s); + $this->assertFalse($wrapped->isSeekable()); + $this->assertFalse($wrapped->seek(2)); + } +} diff --git a/core/vendor/guzzlehttp/streams/tests/StreamDecoratorTraitTest.php b/core/vendor/guzzlehttp/streams/tests/StreamDecoratorTraitTest.php new file mode 100644 index 00000000000..1d49936bfb6 --- /dev/null +++ b/core/vendor/guzzlehttp/streams/tests/StreamDecoratorTraitTest.php @@ -0,0 +1,117 @@ +c = fopen('php://temp', 'r+'); + fwrite($this->c, 'foo'); + fseek($this->c, 0); + $this->a = Stream::factory($this->c); + $this->b = new Str($this->a); + } + + public function testCatchesExceptionsWhenCastingToString() + { + $s = $this->getMockBuilder('GuzzleHttp\Stream\StreamInterface') + ->setMethods(['read']) + ->getMockForAbstractClass(); + $s->expects($this->once()) + ->method('read') + ->will($this->throwException(new \Exception('foo'))); + $msg = ''; + set_error_handler(function ($errNo, $str) use (&$msg) { $msg = $str; }); + echo new Str($s); + restore_error_handler(); + $this->assertContains('foo', $msg); + } + + public function testToString() + { + $this->assertEquals('foo', (string) $this->b); + } + + public function testHasSize() + { + $this->assertEquals(3, $this->b->getSize()); + $this->assertSame($this->b, $this->b->setSize(2)); + $this->assertEquals(2, $this->b->getSize()); + } + + public function testReads() + { + $this->assertEquals('foo', $this->b->read(10)); + } + + public function testCheckMethods() + { + $this->assertEquals($this->a->isReadable(), $this->b->isReadable()); + $this->assertEquals($this->a->isWritable(), $this->b->isWritable()); + $this->assertEquals($this->a->isSeekable(), $this->b->isSeekable()); + } + + public function testSeeksAndTells() + { + $this->assertTrue($this->b->seek(1)); + $this->assertEquals(1, $this->a->tell()); + $this->assertEquals(1, $this->b->tell()); + $this->assertTrue($this->b->seek(0)); + $this->assertEquals(0, $this->a->tell()); + $this->assertEquals(0, $this->b->tell()); + $this->assertTrue($this->b->seek(0, SEEK_END)); + $this->assertEquals(3, $this->a->tell()); + $this->assertEquals(3, $this->b->tell()); + } + + public function testGetsContents() + { + $this->assertEquals('foo', $this->b->getContents()); + $this->assertEquals('', $this->b->getContents()); + $this->b->seek(1); + $this->assertEquals('o', $this->b->getContents(1)); + $this->assertEquals('', $this->b->getContents(0)); + } + + public function testCloses() + { + $this->b->close(); + $this->assertFalse(is_resource($this->c)); + } + + public function testDetaches() + { + $this->b->detach(); + $this->assertFalse($this->b->isReadable()); + } + + public function testWrapsMetadata() + { + $this->assertSame($this->b->getMetadata(), $this->a->getMetadata()); + $this->assertSame($this->b->getMetadata('uri'), $this->a->getMetadata('uri')); + } + + public function testWrapsWrites() + { + $this->b->seek(0, SEEK_END); + $this->b->write('foo'); + $this->assertEquals('foofoo', (string) $this->a); + } +} diff --git a/core/vendor/guzzlehttp/streams/tests/StreamTest.php b/core/vendor/guzzlehttp/streams/tests/StreamTest.php new file mode 100644 index 00000000000..d1460aa8a0e --- /dev/null +++ b/core/vendor/guzzlehttp/streams/tests/StreamTest.php @@ -0,0 +1,150 @@ +assertTrue($stream->isReadable()); + $this->assertTrue($stream->isWritable()); + $this->assertTrue($stream->isSeekable()); + $this->assertEquals('php://temp', $stream->getMetadata('uri')); + $this->assertInternalType('array', $stream->getMetadata()); + $this->assertEquals(4, $stream->getSize()); + $this->assertFalse($stream->eof()); + $stream->close(); + } + + public function testStreamClosesHandleOnDestruct() + { + $handle = fopen('php://temp', 'r'); + $stream = new Stream($handle); + unset($stream); + $this->assertFalse(is_resource($handle)); + } + + public function testConvertsToString() + { + $handle = fopen('php://temp', 'w+'); + fwrite($handle, 'data'); + $stream = new Stream($handle); + $this->assertEquals('data', (string) $stream); + $this->assertEquals('data', (string) $stream); + $stream->close(); + } + + public function testGetsContents() + { + $handle = fopen('php://temp', 'w+'); + fwrite($handle, 'data'); + $stream = new Stream($handle); + $this->assertEquals('', $stream->getContents()); + $stream->seek(0); + $this->assertEquals('data', $stream->getContents()); + $this->assertEquals('', $stream->getContents()); + $stream->seek(0); + $this->assertEquals('da', $stream->getContents(2)); + $stream->close(); + } + + public function testChecksEof() + { + $handle = fopen('php://temp', 'w+'); + fwrite($handle, 'data'); + $stream = new Stream($handle); + $this->assertFalse($stream->eof()); + $stream->read(4); + $this->assertTrue($stream->eof()); + $stream->close(); + } + + public function testAllowsSettingManualSize() + { + $handle = fopen('php://temp', 'w+'); + fwrite($handle, 'data'); + $stream = new Stream($handle); + $stream->setSize(10); + $this->assertEquals(10, $stream->getSize()); + $stream->close(); + } + + public function testGetSize() + { + $size = filesize(__FILE__); + $handle = fopen(__FILE__, 'r'); + $stream = new Stream($handle); + $this->assertEquals($size, $stream->getSize()); + // Load from cache + $this->assertEquals($size, $stream->getSize()); + $stream->close(); + } + + public function testEnsuresSizeIsConsistent() + { + $h = fopen('php://temp', 'w+'); + $this->assertEquals(3, fwrite($h, 'foo')); + $stream = new Stream($h); + $this->assertEquals(3, $stream->getSize()); + $this->assertEquals(4, $stream->write('test')); + $this->assertEquals(7, $stream->getSize()); + $this->assertEquals(7, $stream->getSize()); + $stream->close(); + } + + public function testProvidesStreamPosition() + { + $handle = fopen('php://temp', 'w+'); + $stream = new Stream($handle); + $this->assertEquals(0, $stream->tell()); + $stream->write('foo'); + $this->assertEquals(3, $stream->tell()); + $stream->seek(1); + $this->assertEquals(1, $stream->tell()); + $this->assertSame(ftell($handle), $stream->tell()); + $stream->close(); + } + + public function testKeepsPositionOfResource() + { + $h = fopen(__FILE__, 'r'); + fseek($h, 10); + $stream = Stream::factory($h); + $this->assertEquals(10, $stream->tell()); + $stream->close(); + } + + public function testCanDetachStream() + { + $r = fopen('php://temp', 'w+'); + $stream = new Stream($r); + $this->assertTrue($stream->isReadable()); + $stream->detach(); + $this->assertFalse($stream->isReadable()); + $stream->close(); + } + + public function testCreatesWithFactory() + { + $stream = Stream::factory('foo'); + $this->assertInstanceOf('GuzzleHttp\Stream\Stream', $stream); + $this->assertEquals('foo', $stream->getContents()); + $stream->close(); + } +} diff --git a/core/vendor/guzzlehttp/streams/tests/functionsTest.php b/core/vendor/guzzlehttp/streams/tests/functionsTest.php new file mode 100644 index 00000000000..f6af8a0ffd2 --- /dev/null +++ b/core/vendor/guzzlehttp/streams/tests/functionsTest.php @@ -0,0 +1,126 @@ +assertEquals('foobaz', Stream\copy_to_string($s)); + $s->seek(0); + $this->assertEquals('foo', Stream\copy_to_string($s, 3)); + $this->assertEquals('baz', Stream\copy_to_string($s, 3)); + $this->assertEquals('', Stream\copy_to_string($s)); + } + + public function testCopiesToStream() + { + $s1 = Stream\create('foobaz'); + $s2 = Stream\create(''); + Stream\copy_to_stream($s1, $s2); + $this->assertEquals('foobaz', (string) $s2); + $s2 = Stream\create(''); + $s1->seek(0); + Stream\copy_to_stream($s1, $s2, 3); + $this->assertEquals('foo', (string) $s2); + Stream\copy_to_stream($s1, $s2, 3); + $this->assertEquals('foobaz', (string) $s2); + } + + public function testReadsLines() + { + $s = Stream\create("foo\nbaz\nbar"); + $this->assertEquals("foo\n", Stream\read_line($s)); + $this->assertEquals("baz\n", Stream\read_line($s)); + $this->assertEquals("bar", Stream\read_line($s)); + } + + public function testReadsLinesUpToMaxLength() + { + $s = Stream\create("12345\n"); + $this->assertEquals("123", Stream\read_line($s, 4)); + $this->assertEquals("45\n", Stream\read_line($s)); + } + + public function testReadsLineUntilFalseReturnedFromRead() + { + $s = $this->getMockBuilder('GuzzleHttp\Stream\Stream') + ->setMethods(['read', 'eof']) + ->disableOriginalConstructor() + ->getMock(); + $s->expects($this->exactly(2)) + ->method('read') + ->will($this->returnCallback(function () { + static $c = false; + if ($c) { + return false; + } + $c = true; + return 'h'; + })); + $s->expects($this->exactly(2)) + ->method('eof') + ->will($this->returnValue(false)); + $this->assertEquals("h", Stream\read_line($s)); + } + + public function testCalculatesHash() + { + $s = Stream\create('foobazbar'); + $this->assertEquals(md5('foobazbar'), Stream\hash($s, 'md5')); + } + + public function testCalculatesHashSeeksToOriginalPosition() + { + $s = Stream\create('foobazbar'); + $s->seek(4); + $this->assertEquals(md5('foobazbar'), Stream\hash($s, 'md5')); + $this->assertEquals(4, $s->tell()); + } + + public function testFactoryCreatesFromEmptyString() + { + $s = Stream\create(); + $this->assertInstanceOf('GuzzleHttp\Stream\Stream', $s); + } + + public function testFactoryCreatesFromResource() + { + $r = fopen(__FILE__, 'r'); + $s = Stream\create($r); + $this->assertInstanceOf('GuzzleHttp\Stream\Stream', $s); + $this->assertSame(file_get_contents(__FILE__), (string) $s); + } + + public function testFactoryCreatesFromObjectWithToString() + { + $r = new HasToString(); + $s = Stream\create($r); + $this->assertInstanceOf('GuzzleHttp\Stream\Stream', $s); + $this->assertEquals('foo', (string) $s); + } + + public function testCreatePassesThrough() + { + $s = Stream\create('foo'); + $this->assertSame($s, Stream\create($s)); + } + + /** + * @expectedException \InvalidArgumentException + */ + public function testThrowsExceptionForUnknown() + { + Stream\create(new \stdClass()); + } +} + +class HasToString +{ + public function __toString() { + return 'foo'; + } +}