diff --git a/src/Exception/RequestException.php b/src/Exception/RequestException.php index 23dd02c4..f55fc847 100644 --- a/src/Exception/RequestException.php +++ b/src/Exception/RequestException.php @@ -79,24 +79,63 @@ class RequestException extends TransferException $level = floor($response->getStatusCode() / 100); if ($level == '4') { - $label = 'Client error response'; + $label = 'Client Error'; $className = __NAMESPACE__ . '\\ClientException'; } elseif ($level == '5') { - $label = 'Server error response'; + $label = 'Server Error'; $className = __NAMESPACE__ . '\\ServerException'; } else { - $label = 'Unsuccessful response'; + $label = 'Unsuccessful Request'; $className = __CLASS__; } - $message = $label . ' [url] ' . $request->getUri() - . ' [http method] ' . $request->getMethod() - . ' [status code] ' . $response->getStatusCode() - . ' [reason phrase] ' . $response->getReasonPhrase(); + // Server Error: `GET /` resulted in a `404 Not Found` response: + // ... (truncated) + $message = sprintf( + '%s: `%s` resulted in a `%s` response', + $label, + $request->getMethod() . ' ' . $request->getUri(), + $response->getStatusCode() . ' ' . $response->getReasonPhrase() + ); + + $summary = static::getResponseBodySummary($response); + + if (is_string($summary)) { + $message .= ":\n{$summary}\n"; + } return new $className($message, $request, $response, $previous, $ctx); } + /** + * Get a short summary of the response + * + * Will return `null` if the response is not printable. + * + * @param ResponseInterface $response + * + * @return string|null + */ + public static function getResponseBodySummary(ResponseInterface $response) + { + $body = $response->getBody(); + + if (!$body->isSeekable()) { + return null; + } + + $summary = $body->read(120); + $body->rewind(); + + // Matches any printable character, including unicode characters: + // letters, marks, numbers, punctuation, spacing, and separators. + if (preg_match('/[^\pL\pM\pN\pP\pS\pZ\n\r\t]/', $summary)) { + return null; + } + + return $summary; + } + /** * Get the request that caused the exception * diff --git a/src/Middleware.php b/src/Middleware.php index 2f165f39..85d31654 100644 --- a/src/Middleware.php +++ b/src/Middleware.php @@ -2,9 +2,7 @@ namespace GuzzleHttp; use GuzzleHttp\Cookie\CookieJarInterface; -use GuzzleHttp\Exception\ClientException; use GuzzleHttp\Exception\RequestException; -use GuzzleHttp\Exception\ServerException; use GuzzleHttp\Promise\RejectedPromise; use GuzzleHttp\Psr7; use Psr\Http\Message\ResponseInterface; @@ -64,9 +62,7 @@ final class Middleware if ($code < 400) { return $response; } - throw $code > 499 - ? new ServerException("Server error: $code", $request, $response) - : new ClientException("Client error: $code", $request, $response); + throw RequestException::create($request, $response); } ); }; diff --git a/tests/Exception/RequestExceptionTest.php b/tests/Exception/RequestExceptionTest.php index 61b87d8a..f252cae1 100644 --- a/tests/Exception/RequestExceptionTest.php +++ b/tests/Exception/RequestExceptionTest.php @@ -31,8 +31,12 @@ class RequestExceptionTest extends \PHPUnit_Framework_TestCase public function testCreatesClientErrorResponseException() { $e = RequestException::create(new Request('GET', '/'), new Response(400)); - $this->assertEquals( - 'Client error response [url] / [http method] GET [status code] 400 [reason phrase] Bad Request', + $this->assertContains( + 'GET /', + $e->getMessage() + ); + $this->assertContains( + '400 Bad Request', $e->getMessage() ); $this->assertInstanceOf('GuzzleHttp\Exception\ClientException', $e); @@ -41,8 +45,12 @@ class RequestExceptionTest extends \PHPUnit_Framework_TestCase public function testCreatesServerErrorResponseException() { $e = RequestException::create(new Request('GET', '/'), new Response(500)); - $this->assertEquals( - 'Server error response [url] / [http method] GET [status code] 500 [reason phrase] Internal Server Error', + $this->assertContains( + 'GET /', + $e->getMessage() + ); + $this->assertContains( + '500 Internal Server Error', $e->getMessage() ); $this->assertInstanceOf('GuzzleHttp\Exception\ServerException', $e); @@ -51,8 +59,57 @@ class RequestExceptionTest extends \PHPUnit_Framework_TestCase public function testCreatesGenericErrorResponseException() { $e = RequestException::create(new Request('GET', '/'), new Response(600)); - $this->assertEquals( - 'Unsuccessful response [url] / [http method] GET [status code] 600 [reason phrase] ', + $this->assertContains( + 'GET /', + $e->getMessage() + ); + $this->assertContains( + '600 ', + $e->getMessage() + ); + $this->assertInstanceOf('GuzzleHttp\Exception\RequestException', $e); + } + + public function dataPrintableResponses() + { + return [ + ['You broke the test!'], + ['