Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Introduce ResponseParsingException and throw this exception in … #825

Open
wants to merge 10 commits into
base: master
Choose a base branch
from
18 changes: 14 additions & 4 deletions src/Provider/AbstractProvider.php
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
use League\OAuth2\Client\OptionProvider\OptionProviderInterface;
use League\OAuth2\Client\OptionProvider\PostAuthOptionProvider;
use League\OAuth2\Client\Provider\Exception\IdentityProviderException;
use League\OAuth2\Client\Provider\Exception\ResponseParsingException;
use League\OAuth2\Client\Token\AccessToken;
use League\OAuth2\Client\Token\AccessTokenInterface;
use League\OAuth2\Client\Tool\ArrayAccessorTrait;
Expand Down Expand Up @@ -520,6 +521,8 @@ protected function getAccessTokenRequest(array $params)
* @param mixed $grant
* @param array $options
* @throws IdentityProviderException
* @throws ResponseParsingException if the flag $mayThrowResponseParsingException is true and
* response body cannot be parsed.
* @return AccessTokenInterface
*/
public function getAccessToken($grant, array $options = [])
Expand Down Expand Up @@ -613,6 +616,8 @@ public function getResponse(RequestInterface $request)
*
* @param RequestInterface $request
* @throws IdentityProviderException
* @throws ResponseParsingException if the flag $mayThrowResponseParsingException is true and
* response body cannot be parsed.
* @return mixed
*/
public function getParsedResponse(RequestInterface $request)
Expand Down Expand Up @@ -665,9 +670,9 @@ protected function getContentType(ResponseInterface $response)
/**
* Parses the response according to its content-type header.
*
* @throws UnexpectedValueException
* @throws ResponseParsingException if response body cannot be parsed.
* @param ResponseInterface $response
* @return array
* @return array|string
*/
protected function parseResponse(ResponseInterface $response)
{
Expand All @@ -686,11 +691,14 @@ protected function parseResponse(ResponseInterface $response)
return $this->parseJson($content);
} catch (UnexpectedValueException $e) {
if (strpos($type, 'json') !== false) {
throw $e;
throw new ResponseParsingException($response, $content, $e->getMessage(), $e->getCode(), $e);
}

// for any other content types
if ($response->getStatusCode() == 500) {
throw new UnexpectedValueException(
throw new ResponseParsingException(
$response,
$content,
'An OAuth server error was encountered that did not contain a JSON body',
0,
$e
Expand Down Expand Up @@ -774,6 +782,8 @@ public function getResourceOwner(AccessToken $token)
*
* @param AccessToken $token
* @return mixed
* @throws ResponseParsingException if the flag $mayThrowResponseParsingException is true and
* response body cannot be parsed.
*/
protected function fetchResourceOwnerDetails(AccessToken $token)
{
Expand Down
79 changes: 79 additions & 0 deletions src/Provider/Exception/ResponseParsingException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
<?php
/**
* This file is part of the league/oauth2-client library
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*
* @copyright Copyright (c) Alex Bilbie <hello@alexbilbie.com>
* @license http://opensource.org/licenses/MIT MIT
* @link http://thephpleague.com/oauth2-client/ Documentation
* @link https://packagist.org/packages/league/oauth2-client Packagist
* @link https://github.com/thephpleague/oauth2-client GitHub
*/

namespace League\OAuth2\Client\Provider\Exception;

use Exception;
use Psr\Http\Message\ResponseInterface;
use UnexpectedValueException;

/**
* Exception thrown if the parser cannot parse the provider response.
*/
class ResponseParsingException extends UnexpectedValueException
{
/**
* @var ResponseInterface
*/
protected $response;

/**
* @var string
*/
protected $responseBody;

/**
* @param ResponseInterface $response The response
* @param string $responseBody The response body
* @param null $message
* @param int $code
* @param Exception|null $previous
*/
public function __construct(
ResponseInterface $response,
$responseBody,
$message = null,
$code = 0,
Exception $previous = null
) {
$this->response = $response;
$this->responseBody = $responseBody;

if (null === $message) {
$message = sprintf('Cannot parse response body: "%s"', $responseBody);
}

parent::__construct($message, $code, $previous);
}

/**
* Returns the exception's response.
*
* @return ResponseInterface
*/
public function getResponse()
{
return $this->response;
}

/**
* Returns the exception's response body.
*
* @return string
*/
public function getResponseBody()
{
return $this->responseBody;
}
}
47 changes: 37 additions & 10 deletions test/src/Provider/AbstractProviderTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,25 +2,26 @@

namespace League\OAuth2\Client\Test\Provider;

use League\OAuth2\Client\OptionProvider\PostAuthOptionProvider;
use Mockery;
use ReflectionClass;
use UnexpectedValueException;
use GuzzleHttp\Exception\BadResponseException;
use GuzzleHttp\ClientInterface;
use League\OAuth2\Client\Provider\AbstractProvider;
use League\OAuth2\Client\Test\Provider\Fake as MockProvider;
use GuzzleHttp\Exception\BadResponseException;
use League\OAuth2\Client\Grant\AbstractGrant;
use League\OAuth2\Client\Grant\GrantFactory;
use League\OAuth2\Client\Grant\Exception\InvalidGrantException;
use League\OAuth2\Client\Grant\GrantFactory;
use League\OAuth2\Client\OptionProvider\PostAuthOptionProvider;
use League\OAuth2\Client\Provider\AbstractProvider;
use League\OAuth2\Client\Provider\Exception\IdentityProviderException;
use League\OAuth2\Client\Provider\Exception\ResponseParsingException;
use League\OAuth2\Client\Test\Provider\Fake as MockProvider;
use League\OAuth2\Client\Token\AccessToken;
use League\OAuth2\Client\Token\AccessTokenInterface;
use League\OAuth2\Client\Tool\RequestFactory;
use League\OAuth2\Client\Provider\Exception\IdentityProviderException;
use Mockery;
use PHPUnit\Framework\TestCase;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\RequestInterface;
use Psr\Http\Message\ResponseInterface;
use Psr\Http\Message\StreamInterface;
use ReflectionClass;
use UnexpectedValueException;

class AbstractProviderTest extends TestCase
{
Expand Down Expand Up @@ -649,6 +650,32 @@ public function testParseResponseNonJsonFailure()
$this->testParseResponse('<xml></xml>', 'application/xml', null, 500);
}

public function responseParsingExceptionProvider()
{
// List only combinations of content-type and status code that should lead to exception
// if the response body cannot be parsed as JSON
return [
['application/json', 401],
['application/xml', 500]
];
}

/**
* @dataProvider responseParsingExceptionProvider
*/
public function testResponseParsingException($type, $statusCode)
{
$exception = null;
try {
$this->testParseResponse('{13}', $type, null, $statusCode);
} catch (ResponseParsingException $exception) {
}
$this->assertInstanceOf(ResponseParsingException::class, $exception);
$response = $exception->getResponse();
$this->assertSame($statusCode, $response->getStatusCode());
$this->assertSame('{13}', $exception->getResponseBody());
}

public function getAppendQueryProvider()
{
return [
Expand Down
39 changes: 39 additions & 0 deletions test/src/Provider/Exception/ResponseParsingExceptionTest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
<?php

namespace League\OAuth2\Client\Test\Provider\Exception;

use GuzzleHttp\Psr7\Response;
use League\OAuth2\Client\Provider\Exception\ResponseParsingException;
use PHPUnit\Framework\TestCase;
use Psr\Http\Message\ResponseInterface;

class ResponseParsingExceptionTest extends TestCase
{
private $body = 'foo';

protected function generateResponseParsingException()
{
return new ResponseParsingException(new Response('401'), $this->body);
}

public function testGetResponse()
{
$this->assertInstanceOf(
ResponseInterface::class,
$this->generateResponseParsingException()->getResponse()
);
}

public function testGetResponseBody()
{
$this->assertSame(
$this->body,
$this->generateResponseParsingException()->getResponseBody()
);
}

public function testMissingMessage()
{
$this->assertNotEmpty($this->generateResponseParsingException()->getMessage());
}
}