From 0204332740c9f9744a0354386104f5232514e355 Mon Sep 17 00:00:00 2001 From: Colin O'Dell Date: Tue, 2 Oct 2018 09:52:23 -0400 Subject: [PATCH 1/7] Throw a \RuntimeException whenever a curl request fails (#90) --- lib/Client.php | 8 ++++++++ test/unit/ClientTest.php | 10 ++++++++++ 2 files changed, 18 insertions(+) diff --git a/lib/Client.php b/lib/Client.php index ec732b9..73031fe 100644 --- a/lib/Client.php +++ b/lib/Client.php @@ -415,6 +415,10 @@ private function parseResponse($channel, $content) $headerSize = curl_getinfo($channel, CURLINFO_HEADER_SIZE); $statusCode = curl_getinfo($channel, CURLINFO_HTTP_CODE); + if ($statusCode === 0) { + throw new \RuntimeException(curl_error($channel)); + } + $responseBody = substr($content, $headerSize); $responseHeaders = substr($content, 0, $headerSize); @@ -453,6 +457,8 @@ private function retryRequest(array $responseHeaders, $method, $url, $body, $hea * @param bool $retryOnLimit should retry if rate limit is reach? * * @return Response object + * + * @throws \RuntimeException */ public function makeRequest($method, $url, $body = null, $headers = null, $retryOnLimit = false) { @@ -481,6 +487,8 @@ public function makeRequest($method, $url, $body = null, $headers = null, $retry * @param array $requests * * @return Response[] + * + * @throws \RuntimeException */ public function makeAllRequests(array $requests = []) { diff --git a/test/unit/ClientTest.php b/test/unit/ClientTest.php index 538b1b0..e8428c1 100644 --- a/test/unit/ClientTest.php +++ b/test/unit/ClientTest.php @@ -195,6 +195,16 @@ public function testCreateCurlOptionsWithBodyAndHeaders() ], $result); } + /** + * @expectedException \RuntimeException + * @expectedExceptionMessageRegExp /certificate/i + */ + public function testMakeRequestWithUntrustedRootCert() + { + $client = new Client('https://untrusted-root.badssl.com/'); + $client->makeRequest('GET', 'https://untrusted-root.badssl.com/'); + } + /** * @param object $obj * @param string $name From 80f02858cbd047016baaed8cfbf4ad62a73f4eb0 Mon Sep 17 00:00:00 2001 From: Colin O'Dell Date: Tue, 2 Oct 2018 10:11:14 -0400 Subject: [PATCH 2/7] Auto-locate the system's CA bundle or fall back to Mozilla's (#90) --- composer.json | 3 +++ lib/Client.php | 9 +++++++++ 2 files changed, 12 insertions(+) diff --git a/composer.json b/composer.json index 5c0a3af..1b3101d 100644 --- a/composer.json +++ b/composer.json @@ -23,6 +23,9 @@ "phpunit/phpunit": "~4.4", "squizlabs/php_codesniffer": "~2.0" }, + "suggest": { + "composer/ca-bundle": "Including this library will ensure that a valid CA bundle is available for secure connections" + }, "autoload": { "psr-4": { "SendGrid\\": "lib/" diff --git a/lib/Client.php b/lib/Client.php index 73031fe..7263e73 100644 --- a/lib/Client.php +++ b/lib/Client.php @@ -367,6 +367,15 @@ private function createCurlOptions($method, $body = null, $headers = null) } $options[CURLOPT_HTTPHEADER] = $headers; + if (class_exists('\\Composer\\CaBundle\\CaBundle') && method_exists('\\Composer\\CaBundle\\CaBundle', 'getSystemCaRootBundlePath')) { + $caPathOrFile = \Composer\CaBundle\CaBundle::getSystemCaRootBundlePath(); + if (is_dir($caPathOrFile) || (is_link($caPathOrFile) && is_dir(readlink($caPathOrFile)))) { + $options[CURLOPT_CAPATH] = $caPathOrFile; + } else { + $options[CURLOPT_CAINFO] = $caPathOrFile; + } + } + return $options; } From 281048fb1a4733e71c86d3db917fbbee730521e4 Mon Sep 17 00:00:00 2001 From: Colin O'Dell Date: Wed, 3 Oct 2018 21:39:25 -0400 Subject: [PATCH 3/7] Add some documentation on handling SSL errors --- TROUBLESHOOTING.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/TROUBLESHOOTING.md b/TROUBLESHOOTING.md index 6039b86..14b4f15 100644 --- a/TROUBLESHOOTING.md +++ b/TROUBLESHOOTING.md @@ -3,6 +3,7 @@ If you can't find a solution below, please open an [issue](https://github.com/se ## Table of Contents * [Viewing the Request Body](#request-body) +* [Handling SSL Errors](#ssl-errors) ## Viewing the Request Body @@ -14,3 +15,10 @@ echo $response->statusCode(); echo $response->body(); echo $response->headers(); ``` + + +## Handling SSL Errors + +If any SSL errors occur during API calls, a `RuntimeException` will be thrown. This will provide information to help debug the issue further. + +If the issue is caused by an unrecognized certificate, it may be possible that PHP is unable to locate your system's CA bundle. An easy fix would be requiring the `composer/ca-bundle` package - this library will automatically detect and use that to locate the CA bundle, or use Mozilla's as a fallback. From 8f3179394364a1f0b62faef42aaafa4f84d1072f Mon Sep 17 00:00:00 2001 From: childish-sambino Date: Mon, 12 Oct 2020 15:02:44 -0500 Subject: [PATCH 4/7] Update TROUBLESHOOTING.md --- TROUBLESHOOTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TROUBLESHOOTING.md b/TROUBLESHOOTING.md index f3de1ff..a4b048c 100644 --- a/TROUBLESHOOTING.md +++ b/TROUBLESHOOTING.md @@ -19,6 +19,6 @@ echo $response->headers(); ## Handling SSL Errors -If any SSL errors occur during API calls, a `RuntimeException` will be thrown. This will provide information to help debug the issue further. +If any SSL errors occur during API calls, an `InvalidRequest` will be thrown. This will provide information to help debug the issue further. If the issue is caused by an unrecognized certificate, it may be possible that PHP is unable to locate your system's CA bundle. An easy fix would be requiring the `composer/ca-bundle` package - this library will automatically detect and use that to locate the CA bundle, or use Mozilla's as a fallback. From 13fdf654ea6329d85d9b72698c1f5afe71efab74 Mon Sep 17 00:00:00 2001 From: childish-sambino Date: Mon, 12 Oct 2020 15:03:24 -0500 Subject: [PATCH 5/7] Update ClientTest.php --- test/unit/ClientTest.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/unit/ClientTest.php b/test/unit/ClientTest.php index 6da160f..1f688c8 100644 --- a/test/unit/ClientTest.php +++ b/test/unit/ClientTest.php @@ -210,7 +210,7 @@ public function testThrowExceptionOnInvalidCall() } /** - * @expectedException \RuntimeException + * @expectedException InvalidRequest * @expectedExceptionMessageRegExp /certificate/i */ public function testMakeRequestWithUntrustedRootCert() From eed6f11d3b4f57e3a188321e4386ab07e0f376a9 Mon Sep 17 00:00:00 2001 From: childish-sambino Date: Mon, 12 Oct 2020 15:05:29 -0500 Subject: [PATCH 6/7] Update Client.php --- lib/Client.php | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/lib/Client.php b/lib/Client.php index effeda8..1d2c55c 100644 --- a/lib/Client.php +++ b/lib/Client.php @@ -425,10 +425,6 @@ private function parseResponse($channel, $content) $headerSize = curl_getinfo($channel, CURLINFO_HEADER_SIZE); $statusCode = curl_getinfo($channel, CURLINFO_HTTP_CODE); - if ($statusCode === 0) { - throw new \RuntimeException(curl_error($channel)); - } - $responseBody = mb_substr($content, $headerSize); $responseHeaders = mb_substr($content, 0, $headerSize); @@ -472,7 +468,6 @@ private function retryRequest(array $responseHeaders, $method, $url, $body, $hea * @return Response object * * @throws InvalidRequest - * @throws \RuntimeException */ public function makeRequest($method, $url, $body = null, $headers = null, $retryOnLimit = false) { @@ -507,7 +502,7 @@ public function makeRequest($method, $url, $body = null, $headers = null, $retry * * @return Response[] * - * @throws \RuntimeException + * @throws InvalidRequest */ public function makeAllRequests(array $requests = []) { @@ -528,6 +523,11 @@ public function makeAllRequests(array $requests = []) $sleepDurations = 0; foreach ($channels as $id => $channel) { $content = curl_multi_getcontent($channel); + + if ($content === false) { + throw new InvalidRequest(curl_error($channel), curl_errno($channel)); + } + $response = $this->parseResponse($channel, $content); if ($requests[$id]['retryOnLimit'] && $response->statusCode() === self::TOO_MANY_REQUESTS_HTTP_CODE) { From 70ecbd0729cc8abd9fe26d7411348f32653b74a7 Mon Sep 17 00:00:00 2001 From: Sam Harrison Date: Mon, 12 Oct 2020 15:18:56 -0500 Subject: [PATCH 7/7] update the exception expecting --- test/unit/ClientTest.php | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/test/unit/ClientTest.php b/test/unit/ClientTest.php index 1f688c8..0d829a4 100644 --- a/test/unit/ClientTest.php +++ b/test/unit/ClientTest.php @@ -33,7 +33,7 @@ public function testConstructor() $this->assertAttributeEquals([], 'path', $this->client); $this->assertAttributeEquals([], 'curlOptions', $this->client); $this->assertAttributeEquals(false, 'retryOnLimit', $this->client); - $this->assertAttributeEquals(['get', 'post', 'patch', 'put', 'delete'], 'methods', $this->client); + $this->assertAttributeEquals(['get', 'post', 'patch', 'put', 'delete'], 'methods', $this->client); } public function test_() @@ -209,12 +209,11 @@ public function testThrowExceptionOnInvalidCall() $client->get(); } - /** - * @expectedException InvalidRequest - * @expectedExceptionMessageRegExp /certificate/i - */ public function testMakeRequestWithUntrustedRootCert() { + $this->expectException(InvalidRequest::class); + $this->expectExceptionMessageRegExp('/certificate/i'); + $client = new Client('https://untrusted-root.badssl.com/'); $client->makeRequest('GET', 'https://untrusted-root.badssl.com/'); }