1: 2: 3: 4: 5: 6: 7: 8: 9: 10: 11: 12: 13: 14: 15: 16: 17: 18: 19: 20: 21: 22: 23: 24: 25: 26: 27: 28: 29: 30: 31: 32: 33: 34: 35: 36: 37: 38: 39: 40: 41: 42: 43: 44: 45: 46: 47: 48: 49: 50: 51: 52: 53: 54: 55: 56: 57: 58: 59: 60: 61: 62: 63: 64: 65: 66: 67: 68: 69: 70: 71: 72: 73: 74: 75: 76: 77: 78: 79: 80: 81: 82: 83: 84: 85:
<?php
namespace Guzzle\Plugin\Async;
use Guzzle\Common\Event;
use Guzzle\Http\Message\Response;
use Guzzle\Http\Exception\CurlException;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
/**
* Sends requests but does not wait for the response
*/
class AsyncPlugin implements EventSubscriberInterface
{
public static function getSubscribedEvents()
{
return array(
'request.before_send' => 'onBeforeSend',
'request.exception' => 'onRequestTimeout',
'request.sent' => 'onRequestSent',
'curl.callback.progress' => 'onCurlProgress'
);
}
/**
* Event used to ensure that progress callback are emitted from the curl handle's request mediator.
*
* @param Event $event
*/
public function onBeforeSend(Event $event)
{
// Ensure that progress callbacks are dispatched
$event['request']->getCurlOptions()->set('progress', true);
}
/**
* Event emitted when a curl progress function is called. When the amount of data uploaded == the amount of data to
* upload OR any bytes have been downloaded, then time the request out after 1ms because we're done with
* transmitting the request, and tell curl not download a body.
*
* @param Event $event
*/
public function onCurlProgress(Event $event)
{
if ($event['handle'] &&
($event['downloaded'] || (isset($event['uploaded']) && $event['upload_size'] === $event['uploaded']))
) {
// Timeout after 1ms
curl_setopt($event['handle'], CURLOPT_TIMEOUT_MS, 1);
// Even if the response is quick, tell curl not to download the body.
// - Note that we can only perform this shortcut if the request transmitted a body so as to ensure that the
// request method is not converted to a HEAD request before the request was sent via curl.
if ($event['uploaded']) {
curl_setopt($event['handle'], CURLOPT_NOBODY, true);
}
}
}
/**
* Event emitted when a curl exception occurs. Ignore the exception and set a mock response.
*
* @param Event $event
*/
public function onRequestTimeout(Event $event)
{
if ($event['exception'] instanceof CurlException) {
$event['request']->setResponse(new Response(200, array(
'X-Guzzle-Async' => 'Did not wait for the response'
)));
}
}
/**
* Event emitted when a request completes because it took less than 1ms. Add an X-Guzzle-Async header to notify the
* caller that there is no body in the message.
*
* @param Event $event
*/
public function onRequestSent(Event $event)
{
// Let the caller know this was meant to be async
$event['request']->getResponse()->setHeader('X-Guzzle-Async', 'Did not wait for the response');
}
}