mirror of
https://github.com/guzzle/guzzle.git
synced 2025-01-17 21:38:16 +01:00
parent
90bd509464
commit
e5f0b6b84d
10
CHANGELOG.md
10
CHANGELOG.md
@ -5,9 +5,7 @@ CHANGELOG
|
||||
------------------
|
||||
|
||||
* Now merging in default options using a case-insensitive comparison.
|
||||
* Updating guzzlehttp/streams dependency to ~2.1
|
||||
* No longer utilizing the now deprecated namespaced methods from the stream
|
||||
package.
|
||||
Closes https://github.com/guzzle/guzzle/issues/767
|
||||
* Added the ability to automatically decode `Content-Encoding` response bodies
|
||||
using the `decode_content` request option. This is set to `true` by default
|
||||
to decode the response body if it comes over the wire with a
|
||||
@ -16,6 +14,12 @@ CHANGELOG
|
||||
header and turn on automatic response decoding. This feature now allows you
|
||||
to pass an `Accept-Encoding` header in the headers of a request but still
|
||||
disable automatic response decoding.
|
||||
Closes https://github.com/guzzle/guzzle/issues/764
|
||||
* Added the ability to throw an exception immediately when transferring
|
||||
requests in parallel. Closes https://github.com/guzzle/guzzle/issues/760
|
||||
* Updating guzzlehttp/streams dependency to ~2.1
|
||||
* No longer utilizing the now deprecated namespaced methods from the stream
|
||||
package.
|
||||
|
||||
4.1.8 (2014-08-14)
|
||||
------------------
|
||||
|
@ -285,6 +285,37 @@ failed request to an array that we can use to process errors later.
|
||||
// Handle the error...
|
||||
}
|
||||
|
||||
Throwing Errors Immediately
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
It sometimes is useful to throw exceptions immediately when the occur. The
|
||||
following example shows how to use an event listener to throw exceptions
|
||||
immediately and prevent subsequent requests from being sent.
|
||||
|
||||
.. code-block:: php
|
||||
|
||||
use GuzzleHttp\Event\ErrorEvent;
|
||||
|
||||
$client->sendAll($requests, [
|
||||
'error' => function (ErrorEvent $event) {
|
||||
$event->throwImmediately(true);
|
||||
}
|
||||
]);
|
||||
|
||||
Calling the ``ErrorEvent::throwImmediately()`` instructs the
|
||||
``ParallelAdapterInterface`` sending the request to stop sending subsequent
|
||||
requests, clean up any opened resources, and throw the exception associated
|
||||
with the event as soon as possible. If the error event was not sent by a
|
||||
``ParallelAdapterInterface``, then calling ``throwImmediately()`` has no
|
||||
effect.
|
||||
|
||||
.. note::
|
||||
|
||||
Subsequent listeners of the "error" event can inspect and undo the
|
||||
``throwImmediately()`` call of a previous listener if they know how to
|
||||
handle the associated exception or if the error is intercepted with a
|
||||
response.
|
||||
|
||||
.. _batch-requests:
|
||||
|
||||
Batching Requests
|
||||
|
@ -1,5 +1,4 @@
|
||||
<?php
|
||||
|
||||
namespace GuzzleHttp\Adapter\Curl;
|
||||
|
||||
use GuzzleHttp\Adapter\TransactionInterface;
|
||||
@ -40,6 +39,19 @@ class BatchContext
|
||||
$this->pending = $pending;
|
||||
}
|
||||
|
||||
/**
|
||||
* Closes all of the requests associated with the underlying multi handle.
|
||||
*/
|
||||
public function removeAll()
|
||||
{
|
||||
foreach ($this->handles as $transaction) {
|
||||
$ch = $this->handles[$transaction];
|
||||
curl_multi_remove_handle($this->multi, $ch);
|
||||
curl_close($ch);
|
||||
unset($this->handles[$transaction]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a transaction for a given curl handle
|
||||
*
|
||||
|
@ -178,7 +178,7 @@ class MultiAdapter implements AdapterInterface, ParallelAdapterInterface
|
||||
) {
|
||||
RequestEvents::emitComplete($transaction, $info);
|
||||
}
|
||||
} catch (RequestException $e) {
|
||||
} catch (\Exception $e) {
|
||||
$this->throwException($e, $context);
|
||||
}
|
||||
}
|
||||
@ -233,16 +233,19 @@ class MultiAdapter implements AdapterInterface, ParallelAdapterInterface
|
||||
),
|
||||
$stats
|
||||
);
|
||||
} catch (RequestException $e) {
|
||||
} catch (\Exception $e) {
|
||||
$this->throwException($e, $context);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function throwException(RequestException $e, BatchContext $context)
|
||||
private function throwException(\Exception $e, BatchContext $context)
|
||||
{
|
||||
if ($context->throwsExceptions()) {
|
||||
if ($context->throwsExceptions()
|
||||
|| ($e instanceof RequestException && $e->getThrowImmediately())
|
||||
) {
|
||||
$context->removeAll();
|
||||
$this->releaseMultiHandle($context->getMultiHandle());
|
||||
throw $e;
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
<?php
|
||||
|
||||
namespace GuzzleHttp\Adapter;
|
||||
|
||||
use GuzzleHttp\Exception\RequestException;
|
||||
@ -27,7 +26,9 @@ class FakeParallelAdapter implements ParallelAdapterInterface
|
||||
try {
|
||||
$this->adapter->send($transaction);
|
||||
} catch (RequestException $e) {
|
||||
// no op for batch transaction
|
||||
if ($e->getThrowImmediately()) {
|
||||
throw $e;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -40,6 +40,7 @@ class ErrorEvent extends AbstractTransferEvent
|
||||
{
|
||||
$this->stopPropagation();
|
||||
$this->getTransaction()->setResponse($response);
|
||||
$this->exception->setThrowImmediately(false);
|
||||
RequestEvents::emitComplete($this->getTransaction());
|
||||
}
|
||||
|
||||
@ -62,4 +63,18 @@ class ErrorEvent extends AbstractTransferEvent
|
||||
{
|
||||
return $this->getException()->getResponse();
|
||||
}
|
||||
|
||||
/**
|
||||
* Request that a ParallelAdapterInterface throw the associated exception
|
||||
* if the exception is unhandled.
|
||||
*
|
||||
* If the error event was not emitted from a ParallelAdapterInterface, then
|
||||
* the effect of this method is nil.
|
||||
*
|
||||
* @param bool $throwImmediately Whether or not to throw immediately
|
||||
*/
|
||||
public function throwImmediately($throwImmediately)
|
||||
{
|
||||
$this->exception->setThrowImmediately($throwImmediately);
|
||||
}
|
||||
}
|
||||
|
@ -19,6 +19,9 @@ class RequestException extends TransferException
|
||||
/** @var ResponseInterface */
|
||||
private $response;
|
||||
|
||||
/** @var bool */
|
||||
private $throwImmediately = false;
|
||||
|
||||
public function __construct(
|
||||
$message = '',
|
||||
RequestInterface $request,
|
||||
@ -115,10 +118,33 @@ class RequestException extends TransferException
|
||||
if ($value === null) {
|
||||
return $this->emittedErrorEvent;
|
||||
} elseif ($value === true) {
|
||||
return $this->emittedErrorEvent = true;
|
||||
$this->emittedErrorEvent = true;
|
||||
} else {
|
||||
throw new \InvalidArgumentException('You cannot set the emitted '
|
||||
. 'error value to false.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether or not parallel adapters SHOULD throw the exception
|
||||
* immediately rather than handling errors through asynchronous error
|
||||
* handling.
|
||||
*
|
||||
* @param bool $throwImmediately
|
||||
*
|
||||
*/
|
||||
public function setThrowImmediately($throwImmediately)
|
||||
{
|
||||
$this->throwImmediately = $throwImmediately;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the setting specified by setThrowImmediately().
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function getThrowImmediately()
|
||||
{
|
||||
return $this->throwImmediately;
|
||||
}
|
||||
}
|
||||
|
@ -92,4 +92,20 @@ class BatchContextTest extends \PHPUnit_Framework_TestCase
|
||||
$this->assertFalse($b->hasPending());
|
||||
$this->assertNull($b->nextPending());
|
||||
}
|
||||
|
||||
public function testCanCloseAll()
|
||||
{
|
||||
$m = curl_multi_init();
|
||||
$b = new BatchContext($m, true);
|
||||
$h = curl_init();
|
||||
$t = new Transaction(
|
||||
new Client(),
|
||||
new Request('GET', 'http://httbin.org')
|
||||
);
|
||||
$b->addTransaction($t, $h);
|
||||
$b->removeAll();
|
||||
$this->assertFalse($b->isActive());
|
||||
$this->assertEquals(0, count($this->readAttribute($b, 'handles')));
|
||||
curl_multi_close($m);
|
||||
}
|
||||
}
|
||||
|
@ -64,6 +64,7 @@ class MultiAdapterTest extends AbstractCurl
|
||||
|
||||
public function testChecksForCurlException()
|
||||
{
|
||||
$mh = curl_multi_init();
|
||||
$request = new Request('GET', 'http://httbin.org');
|
||||
$transaction = $this->getMockBuilder('GuzzleHttp\Adapter\Transaction')
|
||||
->setMethods(['getRequest'])
|
||||
@ -74,7 +75,7 @@ class MultiAdapterTest extends AbstractCurl
|
||||
->will($this->returnValue($request));
|
||||
$context = $this->getMockBuilder('GuzzleHttp\Adapter\Curl\BatchContext')
|
||||
->setMethods(['throwsExceptions'])
|
||||
->disableOriginalConstructor()
|
||||
->setConstructorArgs([$mh, true])
|
||||
->getMock();
|
||||
$context->expects($this->once())
|
||||
->method('throwsExceptions')
|
||||
@ -84,8 +85,10 @@ class MultiAdapterTest extends AbstractCurl
|
||||
$r->setAccessible(true);
|
||||
try {
|
||||
$r->invoke($a, $transaction, ['result' => -10], $context, []);
|
||||
curl_multi_close($mh);
|
||||
$this->fail('Did not throw');
|
||||
} catch (RequestException $e) {
|
||||
curl_multi_close($mh);
|
||||
$this->assertSame($request, $e->getRequest());
|
||||
$this->assertContains('[curl] (#-10) ', $e->getMessage());
|
||||
$this->assertContains($request->getUrl(), $e->getMessage());
|
||||
@ -319,4 +322,23 @@ class MultiAdapterTest extends AbstractCurl
|
||||
201
|
||||
);
|
||||
}
|
||||
|
||||
public function testThrowsImmediatelyWhenInstructed()
|
||||
{
|
||||
Server::flush();
|
||||
Server::enqueue(["HTTP/1.1 501\r\nContent-Length: 0\r\n\r\n"]);
|
||||
$c = new Client(['base_url' => Server::$url]);
|
||||
$request = $c->createRequest('GET', '/');
|
||||
$request->getEmitter()->on('error', function (ErrorEvent $e) {
|
||||
$e->throwImmediately(true);
|
||||
});
|
||||
$transactions = [new Transaction($c, $request)];
|
||||
$a = new MultiAdapter(new MessageFactory());
|
||||
try {
|
||||
$a->sendAll(new \ArrayIterator($transactions), 1);
|
||||
$this->fail('Did not throw');
|
||||
} catch (RequestException $e) {
|
||||
$this->assertSame($request, $e->getRequest());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,11 @@
|
||||
<?php
|
||||
|
||||
namespace GuzzleHttp\Tests\Adapter;
|
||||
|
||||
use GuzzleHttp\Adapter\FakeParallelAdapter;
|
||||
use GuzzleHttp\Adapter\MockAdapter;
|
||||
use GuzzleHttp\Client;
|
||||
use GuzzleHttp\Event\ErrorEvent;
|
||||
use GuzzleHttp\Exception\RequestException;
|
||||
use GuzzleHttp\Message\Response;
|
||||
use GuzzleHttp\Adapter\TransactionIterator;
|
||||
|
||||
@ -32,4 +33,27 @@ class FakeParallelAdapterTest extends \PHPUnit_Framework_TestCase
|
||||
$this->assertContains('GET', $sent);
|
||||
$this->assertContains('HEAD', $sent);
|
||||
}
|
||||
|
||||
public function testThrowsImmediatelyIfInstructed()
|
||||
{
|
||||
$client = new Client();
|
||||
$request = $client->createRequest('GET', 'http://httbin.org');
|
||||
$request->getEmitter()->on('error', function (ErrorEvent $e) {
|
||||
$e->throwImmediately(true);
|
||||
});
|
||||
$sent = [];
|
||||
$f = new FakeParallelAdapter(
|
||||
new MockAdapter(function ($trans) use (&$sent) {
|
||||
$sent[] = $trans->getRequest()->getMethod();
|
||||
return new Response(404);
|
||||
})
|
||||
);
|
||||
$tIter = new TransactionIterator([$request], $client, []);
|
||||
try {
|
||||
$f->sendAll($tIter, 1);
|
||||
$this->fail('Did not throw');
|
||||
} catch (RequestException $e) {
|
||||
$this->assertSame($request, $e->getRequest());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,5 +1,4 @@
|
||||
<?php
|
||||
|
||||
namespace GuzzleHttp\Tests\Event;
|
||||
|
||||
use GuzzleHttp\Adapter\Transaction;
|
||||
@ -23,6 +22,11 @@ class ErrorEventTest extends \PHPUnit_Framework_TestCase
|
||||
$except = new RequestException('foo', $request, $response);
|
||||
$event = new ErrorEvent($transaction, $except);
|
||||
|
||||
$event->throwImmediately(true);
|
||||
$this->assertTrue($except->getThrowImmediately());
|
||||
$event->throwImmediately(false);
|
||||
$this->assertFalse($except->getThrowImmediately());
|
||||
|
||||
$this->assertSame($except, $event->getException());
|
||||
$this->assertSame($response, $event->getResponse());
|
||||
$this->assertSame($request, $event->getRequest());
|
@ -81,4 +81,14 @@ class RequestExceptionTest extends \PHPUnit_Framework_TestCase
|
||||
$e = RequestException::create(new Request('GET', '/'), new Response(442));
|
||||
$this->assertEquals(442, $e->getCode());
|
||||
}
|
||||
|
||||
public function testHasThrowState() {
|
||||
$e = RequestException::create(
|
||||
new Request('GET', '/'),
|
||||
new Response(442)
|
||||
);
|
||||
$this->assertFalse($e->getThrowImmediately());
|
||||
$e->setThrowImmediately(true);
|
||||
$this->assertTrue($e->getThrowImmediately());
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user