summaryrefslogtreecommitdiff
path: root/Postman/Postman-Mail/sendgrid/vendor/sendgrid/php-http-client/lib/Client.php
diff options
context:
space:
mode:
Diffstat (limited to 'Postman/Postman-Mail/sendgrid/vendor/sendgrid/php-http-client/lib/Client.php')
-rw-r--r--Postman/Postman-Mail/sendgrid/vendor/sendgrid/php-http-client/lib/Client.php561
1 files changed, 461 insertions, 100 deletions
diff --git a/Postman/Postman-Mail/sendgrid/vendor/sendgrid/php-http-client/lib/Client.php b/Postman/Postman-Mail/sendgrid/vendor/sendgrid/php-http-client/lib/Client.php
index d3ca94d..ec732b9 100644
--- a/Postman/Postman-Mail/sendgrid/vendor/sendgrid/php-http-client/lib/Client.php
+++ b/Postman/Postman-Mail/sendgrid/vendor/sendgrid/php-http-client/lib/Client.php
@@ -1,46 +1,225 @@
<?php
/**
- * HTTP Client library
- *
- * PHP version 5.4
- *
- * @author Matt Bernier <dx@sendgrid.com>
- * @author Elmer Thomas <dx@sendgrid.com>
- * @copyright 2016 SendGrid
- * @license https://opensource.org/licenses/MIT The MIT License
- * @version GIT: <git_id>
- * @link http://packagist.org/packages/sendgrid/php-http-client
- */
+ * HTTP Client library
+ *
+ * @author Matt Bernier <dx@sendgrid.com>
+ * @author Elmer Thomas <dx@sendgrid.com>
+ * @copyright 2018 SendGrid
+ * @license https://opensource.org/licenses/MIT The MIT License
+ * @version GIT: <git_id>
+ * @link http://packagist.org/packages/sendgrid/php-http-client
+ */
namespace SendGrid;
/**
- * Quickly and easily access any REST or REST-like API.
- */
+ *
+ * Class Client
+ * @package SendGrid
+ * @version 3.9.5
+ *
+ * Quickly and easily access any REST or REST-like API.
+ *
+ * @method Response get($body = null, $query = null, $headers = null)
+ * @method Response post($body = null, $query = null, $headers = null)
+ * @method Response patch($body = null, $query = null, $headers = null)
+ * @method Response put($body = null, $query = null, $headers = null)
+ * @method Response delete($body = null, $query = null, $headers = null)
+ *
+ * @method Client version($value)
+ * @method Client|Response send()
+ *
+ * Adding all the endpoints as a method so code completion works
+ *
+ * General
+ * @method Client stats()
+ * @method Client search()
+ * @method Client monthly()
+ * @method Client sums()
+ * @method Client monitor()
+ * @method Client test()
+ *
+ * Access settings
+ * @method Client access_settings()
+ * @method Client activity()
+ * @method Client whitelist()
+ *
+ * Alerts
+ * @method Client alerts()
+ *
+ * Api keys
+ * @method Client api_keys()
+ *
+ * ASM
+ * @method Client asm()
+ * @method Client groups()
+ *
+ * Browsers
+ * @method Client browsers()
+ *
+ * Campaigns
+ * @method Client campaigns()
+ * @method Client schedules()
+ * @method Client now()
+ *
+ * Categories
+ * @method Client categories()
+ *
+ * Clients
+ * @method Client clients()
+ *
+ * ContactDB
+ * @method Client contactdb()
+ * @method Client custom_fields()
+ * @method Client lists()
+ * @method Client recipients()
+ * @method Client billable_count()
+ * @method Client count()
+ * @method Client reserved_fields()
+ * @method Client segments()
+ *
+ * Devices
+ * @method Client devices()
+ *
+ * Geo
+ * @method Client geo()
+ *
+ * Ips
+ * @method Client ips()
+ * @method Client assigned()
+ * @method Client pools()
+ * @method Client warmup()
+ *
+ * Mail
+ * @method Client mail()
+ * @method Client batch()
+ *
+ * Mailbox Providers
+ * @method Client mailbox_providers()
+ *
+ * Mail settings
+ * @method Client mail_settings()
+ * @method Client address_whitelist()
+ * @method Client bcc()
+ * @method Client bounce_purge()
+ * @method Client footer()
+ * @method Client forward_bounce()
+ * @method Client forward_spam()
+ * @method Client plain_content()
+ * @method Client spam_check()
+ * @method Client template()
+ *
+ * Partner settings
+ * @method Client partner_settings()
+ * @method Client new_relic()
+ *
+ * Scopes
+ * @method Client scopes()
+ *
+ * Senders
+ * @method Client senders()
+ * @method Client resend_verification()
+ *
+ * Sub Users
+ * @method Client subusers()
+ * @method Client reputations()
+ *
+ * Supressions
+ * @method Client suppressions()
+ * @method Client global()
+ * @method Client blocks()
+ * @method Client bounces()
+ * @method Client invalid_emails()
+ * @method Client spam_reports()
+ * @method Client unsubcribes()
+ *
+ * Templates
+ * @method Client templates()
+ * @method Client versions()
+ * @method Client activate()
+ *
+ * Tracking settings
+ * @method Client tracking_settings()
+ * @method Client click()
+ * @method Client google_analytics()
+ * @method Client open()
+ * @method Client subscription()
+ *
+ * User
+ * @method Client user()
+ * @method Client account()
+ * @method Client credits()
+ * @method Client email()
+ * @method Client password()
+ * @method Client profile()
+ * @method Client scheduled_sends()
+ * @method Client enforced_tls()
+ * @method Client settings()
+ * @method Client username()
+ * @method Client webhooks()
+ * @method Client event()
+ * @method Client parse()
+ *
+ * Missed any? Simply add them by doing: @method Client method()
+ */
class Client
{
- /** @var string */
+ const TOO_MANY_REQUESTS_HTTP_CODE = 429;
+
+ /**
+ * @var string
+ */
protected $host;
- /** @var array */
+
+ /**
+ * @var array
+ */
protected $headers;
- /** @var string */
+
+ /**
+ * @var string
+ */
protected $version;
- /** @var array */
+
+ /**
+ * @var array
+ */
protected $path;
- /** @var array */
+
+ /**
+ * @var array
+ */
protected $curlOptions;
- /** @var array */
- private $methods;
- /** @var bool */
- private $retryOnLimit;
+
+ /**
+ * @var bool
+ */
+ protected $isConcurrentRequest;
+
+ /**
+ * @var array
+ */
+ protected $savedRequests;
+
+ /**
+ * @var bool
+ */
+ protected $retryOnLimit;
+
+ /**
+ * These are the supported HTTP verbs
+ *
+ * @var array
+ */
+ private $methods = ['get', 'post', 'patch', 'put', 'delete'];
/**
* Initialize the client
*
* @param string $host the base url (e.g. https://api.sendgrid.com)
* @param array $headers global request headers
- * @param string $version api version (configurable)
+ * @param string $version api version (configurable) - this is specific to the SendGrid API
* @param array $path holds the segments of the url path
* @param array $curlOptions extra options to set during curl initialization
* @param bool $retryOnLimit set default retry on limit flag
@@ -52,10 +231,9 @@ class Client
$this->version = $version;
$this->path = $path ?: [];
$this->curlOptions = $curlOptions ?: [];
- // These are the supported HTTP verbs
- $this->methods = ['delete', 'get', 'patch', 'post', 'put'];
-
$this->retryOnLimit = $retryOnLimit;
+ $this->isConcurrentRequest = false;
+ $this->savedRequests = [];
}
/**
@@ -99,29 +277,54 @@ class Client
}
/**
- * Make a new Client object
- *
- * @param string $name name of the url segment
- *
- * @return Client object
- */
- private function buildClient($name = null)
+ * Set extra options to set during curl initialization
+ *
+ * @param array $options
+ *
+ * @return Client
+ */
+ public function setCurlOptions(array $options)
{
- if (isset($name)) {
- $this->path[] = $name;
- }
- $client = new Client($this->host, $this->headers, $this->version, $this->path, $this->curlOptions);
- $this->path = [];
- return $client;
+ $this->curlOptions = $options;
+
+ return $this;
}
/**
- * Build the final URL to be passed
- *
- * @param array $queryParams an array of all the query parameters
- *
- * @return string
- */
+ * Set default retry on limit flag
+ *
+ * @param bool $retry
+ *
+ * @return Client
+ */
+ public function setRetryOnLimit($retry)
+ {
+ $this->retryOnLimit = $retry;
+
+ return $this;
+ }
+
+ /**
+ * Set concurrent request flag
+ *
+ * @param bool $isConcurrent
+ *
+ * @return Client
+ */
+ public function setIsConcurrentRequest($isConcurrent)
+ {
+ $this->isConcurrentRequest = $isConcurrent;
+
+ return $this;
+ }
+
+ /**
+ * Build the final URL to be passed
+ *
+ * @param array $queryParams an array of all the query parameters
+ *
+ * @return string
+ */
private function buildUrl($queryParams = null)
{
$path = '/' . implode('/', $this->path);
@@ -132,86 +335,231 @@ class Client
}
/**
- * Make the API call and return the response. This is separated into
- * it's own function, so we can mock it easily for testing.
- *
- * @param string $method the HTTP verb
- * @param string $url the final url to call
- * @param array $body request body
- * @param array $headers any additional request headers
- * @param bool $retryOnLimit should retry if rate limit is reach?
- *
- * @return Response object
- */
- public function makeRequest($method, $url, $body = null, $headers = null, $retryOnLimit = false)
+ * Creates curl options for a request
+ * this function does not mutate any private variables
+ *
+ * @param string $method
+ * @param array $body
+ * @param array $headers
+ *
+ * @return array
+ */
+ private function createCurlOptions($method, $body = null, $headers = null)
{
- $curl = curl_init($url);
-
- curl_setopt_array($curl, [
- CURLOPT_RETURNTRANSFER => true,
- CURLOPT_HEADER => 1,
- CURLOPT_CUSTOMREQUEST => strtoupper($method),
- CURLOPT_SSL_VERIFYPEER => false,
- ] + $this->curlOptions);
+ $options = [
+ CURLOPT_RETURNTRANSFER => true,
+ CURLOPT_HEADER => true,
+ CURLOPT_CUSTOMREQUEST => strtoupper($method),
+ CURLOPT_SSL_VERIFYPEER => true,
+ CURLOPT_FAILONERROR => false
+ ] + $this->curlOptions;
if (isset($headers)) {
- $this->headers = array_merge($this->headers, $headers);
+ $headers = array_merge($this->headers, $headers);
+ } else {
+ $headers = $this->headers;
}
+
if (isset($body)) {
$encodedBody = json_encode($body);
- curl_setopt($curl, CURLOPT_POSTFIELDS, $encodedBody);
- $this->headers = array_merge($this->headers, ['Content-Type: application/json']);
+ $options[CURLOPT_POSTFIELDS] = $encodedBody;
+ $headers = array_merge($headers, ['Content-Type: application/json']);
+ }
+ $options[CURLOPT_HTTPHEADER] = $headers;
+
+ return $options;
+ }
+
+ /**
+ * @param array $requestData
+ * e.g. ['method' => 'POST', 'url' => 'www.example.com', 'body' => 'test body', 'headers' => []]
+ * @param bool $retryOnLimit
+ *
+ * @return array
+ */
+ private function createSavedRequest(array $requestData, $retryOnLimit = false)
+ {
+ return array_merge($requestData, ['retryOnLimit' => $retryOnLimit]);
+ }
+
+ /**
+ * @param array $requests
+ *
+ * @return array
+ */
+ private function createCurlMultiHandle(array $requests)
+ {
+ $channels = [];
+ $multiHandle = curl_multi_init();
+
+ foreach ($requests as $id => $data) {
+ $channels[$id] = curl_init($data['url']);
+ $curlOpts = $this->createCurlOptions($data['method'], $data['body'], $data['headers']);
+ curl_setopt_array($channels[$id], $curlOpts);
+ curl_multi_add_handle($multiHandle, $channels[$id]);
}
- curl_setopt($curl, CURLOPT_HTTPHEADER, $this->headers);
- $response = curl_exec($curl);
- $headerSize = curl_getinfo($curl, CURLINFO_HEADER_SIZE);
- $statusCode = curl_getinfo($curl, CURLINFO_HTTP_CODE);
+ return [$channels, $multiHandle];
+ }
+
+ /**
+ * Prepare response object
+ *
+ * @param resource $channel the curl resource
+ * @param string $content
+ *
+ * @return Response object
+ */
+ private function parseResponse($channel, $content)
+ {
+ $headerSize = curl_getinfo($channel, CURLINFO_HEADER_SIZE);
+ $statusCode = curl_getinfo($channel, CURLINFO_HTTP_CODE);
- $responseBody = substr($response, $headerSize);
- $responseHeaders = substr($response, 0, $headerSize);
+ $responseBody = substr($content, $headerSize);
+ $responseHeaders = substr($content, 0, $headerSize);
$responseHeaders = explode("\n", $responseHeaders);
$responseHeaders = array_map('trim', $responseHeaders);
- curl_close($curl);
-
- $response = new Response($statusCode, $responseBody, $responseHeaders);
+ return new Response($statusCode, $responseBody, $responseHeaders);
+ }
- if ($statusCode == 429 && $retryOnLimit) {
- $headers = $response->headers(true);
- $sleepDurations = $headers['X-Ratelimit-Reset'] - time();
- sleep($sleepDurations > 0 ? $sleepDurations : 0);
- return $this->makeRequest($method, $url, $body, $headers, false);
+ /**
+ * Retry request
+ *
+ * @param array $responseHeaders headers from rate limited response
+ * @param string $method the HTTP verb
+ * @param string $url the final url to call
+ * @param array $body request body
+ * @param array $headers original headers
+ *
+ * @return Response response object
+ */
+ private function retryRequest(array $responseHeaders, $method, $url, $body, $headers)
+ {
+ $sleepDurations = $responseHeaders['X-Ratelimit-Reset'] - time();
+ sleep($sleepDurations > 0 ? $sleepDurations : 0);
+ return $this->makeRequest($method, $url, $body, $headers, false);
+ }
+
+ /**
+ * Make the API call and return the response.
+ * This is separated into it's own function, so we can mock it easily for testing.
+ *
+ * @param string $method the HTTP verb
+ * @param string $url the final url to call
+ * @param array $body request body
+ * @param array $headers any additional request headers
+ * @param bool $retryOnLimit should retry if rate limit is reach?
+ *
+ * @return Response object
+ */
+ public function makeRequest($method, $url, $body = null, $headers = null, $retryOnLimit = false)
+ {
+ $channel = curl_init($url);
+
+ $options = $this->createCurlOptions($method, $body, $headers);
+
+ curl_setopt_array($channel, $options);
+ $content = curl_exec($channel);
+
+ $response = $this->parseResponse($channel, $content);
+
+ if ($response->statusCode() === self::TOO_MANY_REQUESTS_HTTP_CODE && $retryOnLimit) {
+ $responseHeaders = $response->headers(true);
+ return $this->retryRequest($responseHeaders, $method, $url, $body, $headers);
}
+ curl_close($channel);
+
return $response;
}
/**
- * Add variable values to the url.
- * (e.g. /your/api/{variable_value}/call)
- * Another example: if you have a PHP reserved word, such as and,
- * in your url, you must use this method.
- *
- * @param string $name name of the url segment
- *
- * @return Client object
- */
+ * Send all saved requests at once
+ *
+ * @param array $requests
+ *
+ * @return Response[]
+ */
+ public function makeAllRequests(array $requests = [])
+ {
+ if (empty($requests)) {
+ $requests = $this->savedRequests;
+ }
+ list($channels, $multiHandle) = $this->createCurlMultiHandle($requests);
+
+ // running all requests
+ $isRunning = null;
+ do {
+ curl_multi_exec($multiHandle, $isRunning);
+ } while ($isRunning);
+
+ // get response and close all handles
+ $retryRequests = [];
+ $responses = [];
+ $sleepDurations = 0;
+ foreach ($channels as $id => $channel) {
+
+ $content = curl_multi_getcontent($channel);
+ $response = $this->parseResponse($channel, $content);
+
+ if ($response->statusCode() === self::TOO_MANY_REQUESTS_HTTP_CODE && $requests[$id]['retryOnLimit']) {
+ $headers = $response->headers(true);
+ $sleepDurations = max($sleepDurations, $headers['X-Ratelimit-Reset'] - time());
+ $requestData = [
+ 'method' => $requests[$id]['method'],
+ 'url' => $requests[$id]['url'],
+ 'body' => $requests[$id]['body'],
+ 'headers' => $headers,
+ ];
+ $retryRequests[] = $this->createSavedRequest($requestData, false);
+ } else {
+ $responses[] = $response;
+ }
+
+ curl_multi_remove_handle($multiHandle, $channel);
+ }
+ curl_multi_close($multiHandle);
+
+ // retry requests
+ if (!empty($retryRequests)) {
+ sleep($sleepDurations > 0 ? $sleepDurations : 0);
+ $responses = array_merge($responses, $this->makeAllRequests($retryRequests));
+ }
+ return $responses;
+ }
+
+ /**
+ * Add variable values to the url. (e.g. /your/api/{variable_value}/call)
+ * Another example: if you have a PHP reserved word, such as and, in your url, you must use this method.
+ *
+ * @param string $name name of the url segment
+ *
+ * @return Client object
+ */
public function _($name = null)
{
- return $this->buildClient($name);
+ if (isset($name)) {
+ $this->path[] = $name;
+ }
+ $client = new static($this->host, $this->headers, $this->version, $this->path);
+ $client->setCurlOptions($this->curlOptions);
+ $client->setRetryOnLimit($this->retryOnLimit);
+ $this->path = [];
+
+ return $client;
}
/**
- * Dynamically add method calls to the url, then call a method.
- * (e.g. client.name.name.method())
- *
- * @param string $name name of the dynamic method call or HTTP verb
- * @param array $args parameters passed with the method call
- *
- * @return Client|Response object
- */
+ * Dynamically add method calls to the url, then call a method.
+ * (e.g. client.name.name.method())
+ *
+ * @param string $name name of the dynamic method call or HTTP verb
+ * @param array $args parameters passed with the method call
+ *
+ * @return Client|Response|Response[]|null object
+ */
public function __call($name, $args)
{
$name = strtolower($name);
@@ -221,12 +569,25 @@ class Client
return $this->_();
}
+ // send all saved requests
+ if (($name === 'send') && $this->isConcurrentRequest) {
+ return $this->makeAllRequests();
+ }
+
if (in_array($name, $this->methods, true)) {
$body = isset($args[0]) ? $args[0] : null;
$queryParams = isset($args[1]) ? $args[1] : null;
$url = $this->buildUrl($queryParams);
$headers = isset($args[2]) ? $args[2] : null;
$retryOnLimit = isset($args[3]) ? $args[3] : $this->retryOnLimit;
+
+ if ($this->isConcurrentRequest) {
+ // save request to be sent later
+ $requestData = ['method' => $name, 'url' => $url, 'body' => $body, 'headers' => $headers];
+ $this->savedRequests[] = $this->createSavedRequest($requestData, $retryOnLimit);
+ return null;
+ }
+
return $this->makeRequest($name, $url, $body, $headers, $retryOnLimit);
}