From c6977daafb33f7a9c49ae34f53108cb25d943193 Mon Sep 17 00:00:00 2001 From: Joel Wurtz Date: Fri, 25 Dec 2015 18:37:07 +0100 Subject: [PATCH 1/2] Add a safety catch for max restarts, fix #7 --- spec/PluginClientSpec.php | 16 ++++++++++++ src/Exception/LoopException.php | 9 +++++++ src/PluginClient.php | 43 ++++++++++++++++++++++++++++++++- 3 files changed, 67 insertions(+), 1 deletion(-) create mode 100644 src/Exception/LoopException.php diff --git a/spec/PluginClientSpec.php b/spec/PluginClientSpec.php index f02f41c..909325c 100644 --- a/spec/PluginClientSpec.php +++ b/spec/PluginClientSpec.php @@ -4,6 +4,7 @@ use Http\Client\HttpAsyncClient; use Http\Client\HttpClient; +use Http\Client\Plugin\Plugin; use Http\Promise\Promise; use Psr\Http\Message\RequestInterface; use Psr\Http\Message\ResponseInterface; @@ -45,4 +46,19 @@ function it_sends_async_request_with_underlying_client(HttpAsyncClient $asyncCli $this->beConstructedWith($asyncClient); $this->sendAsyncRequest($request)->shouldReturn($promise); } + + function it_throws_loop_exception(HttpClient $client, RequestInterface $request) + { + $this->beConstructedWith($client, [new DefectuousPlugin()]); + + $this->shouldThrow('Http\Client\Plugin\Exception\LoopException')->duringSendRequest($request); + } +} + +class DefectuousPlugin implements Plugin +{ + public function handleRequest(RequestInterface $request, callable $next, callable $first) + { + return $first($request); + } } diff --git a/src/Exception/LoopException.php b/src/Exception/LoopException.php new file mode 100644 index 0000000..ae6bdd6 --- /dev/null +++ b/src/Exception/LoopException.php @@ -0,0 +1,9 @@ +client = $client; @@ -44,6 +54,7 @@ public function __construct($client, array $plugins = []) } $this->plugins = $plugins; + $this->options = $this->configure($options); } /** @@ -66,6 +77,23 @@ public function sendAsyncRequest(RequestInterface $request) return $pluginChain($request); } + /** + * Configure the plugin client. + * + * @param array $options + * + * @return array + */ + protected function configure(array $options = []) + { + $resolver = new OptionsResolver(); + $resolver->setDefaults([ + 'max_restarts' => 10, + ]); + + return $resolver->resolve($options); + } + /** * @param Plugin[] $pluginList * @@ -74,6 +102,8 @@ public function sendAsyncRequest(RequestInterface $request) private function createPluginChain($pluginList) { $client = $this->client; + $options = $this->options; + $lastCallable = function (RequestInterface $request) use ($client) { return $client->sendAsyncRequest($request); }; @@ -87,6 +117,17 @@ private function createPluginChain($pluginList) $firstCallable = $lastCallable; } + $firstCalls = 0; + $firstCallable = function (RequestInterface $request) use ($options, $lastCallable, &$firstCalls) { + if ($firstCalls > $options['max_restarts']) { + throw new LoopException('Too many restarts in plugin client', $request); + } + + ++$firstCalls; + + return $lastCallable($request); + }; + return $firstCallable; } } From c930d9929fbadfa1865e0c93e21a42d16708a569 Mon Sep 17 00:00:00 2001 From: Joel Wurtz Date: Fri, 25 Dec 2015 21:29:37 +0100 Subject: [PATCH 2/2] Fix on PHP7 --- spec/PluginClientSpec.php | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/spec/PluginClientSpec.php b/spec/PluginClientSpec.php index 909325c..7c727a0 100644 --- a/spec/PluginClientSpec.php +++ b/spec/PluginClientSpec.php @@ -10,6 +10,14 @@ use Psr\Http\Message\ResponseInterface; use PhpSpec\ObjectBehavior; +class DefectuousPlugin implements Plugin +{ + public function handleRequest(RequestInterface $request, callable $next, callable $first) + { + return $first($request); + } +} + class PluginClientSpec extends ObjectBehavior { function let(HttpClient $client) @@ -54,11 +62,3 @@ function it_throws_loop_exception(HttpClient $client, RequestInterface $request) $this->shouldThrow('Http\Client\Plugin\Exception\LoopException')->duringSendRequest($request); } } - -class DefectuousPlugin implements Plugin -{ - public function handleRequest(RequestInterface $request, callable $next, callable $first) - { - return $first($request); - } -}