示例#1
0
 /**
  * Intercept the exception and inject a response
  *
  * @param ResponseInterface $response Response to set
  */
 public function intercept(ResponseInterface $response)
 {
     $this->stopPropagation();
     $this->getTransaction()->setResponse($response);
     $this->exception->setThrowImmediately(false);
     RequestEvents::emitComplete($this->getTransaction());
 }
 /**
  * Receive a response header from curl
  *
  * @param resource $curl   Curl handle
  * @param string   $header Received header
  *
  * @return int
  */
 public function receiveResponseHeader($curl, $header)
 {
     static $normalize = array("\r", "\n");
     $length = strlen($header);
     $header = str_replace($normalize, '', $header);
     if (strpos($header, 'HTTP/') === 0) {
         $startLine = explode(' ', $header, 3);
         // Only download the body to a target body when a successful
         // response is received.
         if ($startLine[1][0] != '2') {
             $this->body = null;
         }
         $this->statusCode = $startLine[1];
         $this->reasonPhrase = isset($startLine[2]) ? $startLine[2] : null;
         $this->protocolVersion = substr($startLine[0], -3);
         $this->headers = array();
     } elseif ($pos = strpos($header, ':')) {
         $this->headers[substr($header, 0, $pos)][] = substr($header, $pos + 1);
     } elseif ($header == '' && $this->statusCode >= 200) {
         $response = $this->messageFactory->createResponse($this->statusCode, $this->headers, $this->body, array('protocol_version' => $this->protocolVersion, 'reason_phrase' => $this->reasonPhrase));
         $this->headers = $this->body = null;
         $this->transaction->setResponse($response);
         // Allows events to react before downloading any of the body
         RequestEvents::emitHeaders($this->transaction);
     }
     return $length;
 }
 private function createResponseObject(RequestInterface $request, array $headers, TransactionInterface $transaction, StreamInterface $stream)
 {
     $parts = explode(' ', array_shift($headers), 3);
     $options = ['protocol_version' => substr($parts[0], -3)];
     if (isset($parts[2])) {
         $options['reason_phrase'] = $parts[2];
     }
     $response = $this->messageFactory->createResponse($parts[1], $this->headersFromLines($headers), null, $options);
     // Automatically decode responses when instructed.
     if ($request->getConfig()->get('decode_content')) {
         switch ($response->getHeader('Content-Encoding')) {
             case 'gzip':
             case 'deflate':
                 $stream = new InflateStream($stream);
                 break;
         }
     }
     // Drain the stream immediately if 'stream' was not enabled.
     if (!$request->getConfig()['stream']) {
         $stream = $this->getSaveToBody($request, $stream);
     }
     $response->setBody($stream);
     $transaction->setResponse($response);
     RequestEvents::emitHeaders($transaction);
     return $response;
 }
 /**
  * Transfers an HTTP request and populates a response
  *
  * @param TransactionInterface $transaction Transaction abject to populate
  *
  * @return ResponseInterface
  */
 public function send(TransactionInterface $transaction)
 {
     // HTTP/1.1 streams using the PHP stream wrapper require a
     // Connection: close header. Setting here so that it is added before
     // emitting the request.before_send event.
     $request = $transaction->getRequest();
     if ($request->getProtocolVersion() == '1.1' && !$request->hasHeader('Connection')) {
         $transaction->getRequest()->setHeader('Connection', 'close');
     }
     try {
         RequestEvents::emitBefore($transaction);
         if (!$transaction->getResponse()) {
             $this->createResponse($transaction);
             RequestEvents::emitComplete($transaction);
         }
         return $transaction->getResponse();
     } catch (RequestException $e) {
         if ($e->hasResponse() && $e->getResponse()->getBody()) {
             $message = trim($e->getResponse()->getBody()->__toString());
             if (empty($message)) {
                 $message = $e->getMessage();
             }
             throw new APIException($message, $e->getRequest(), $e->getResponse(), $e);
         }
         throw $e;
     }
 }
示例#5
0
 private function createResponseObject(array $headers, TransactionInterface $transaction, $stream)
 {
     $parts = explode(' ', array_shift($headers), 3);
     $options = ['protocol_version' => substr($parts[0], -3)];
     if (isset($parts[2])) {
         $options['reason_phrase'] = $parts[2];
     }
     $response = $this->messageFactory->createResponse($parts[1], $this->headersFromLines($headers), $stream, $options);
     $transaction->setResponse($response);
     RequestEvents::emitHeaders($transaction);
     return $response;
 }
示例#6
0
 /**
  * Sends multiple commands concurrently and returns a hash map of commands
  * mapped to their corresponding result or exception.
  *
  * Note: This method keeps every command and command and result in memory,
  * and as such is NOT recommended when sending a large number or an
  * indeterminable number of commands concurrently. Instead, you should use
  * executeAll() and utilize the event system to work with results.
  *
  * @param ServiceClientInterface $client
  * @param array|\Iterator        $commands Commands to send.
  * @param array                  $options  Passes through the options available
  *                                         in {@see ServiceClientInterface::createPool()}
  *
  * @return BatchResults
  * @throws \InvalidArgumentException if the event format is incorrect.
  */
 public static function batch(ServiceClientInterface $client, $commands, array $options = [])
 {
     $hash = new \SplObjectStorage();
     foreach ($commands as $command) {
         $hash->attach($command);
     }
     $client->executeAll($commands, RequestEvents::convertEventArray($options, ['process'], ['priority' => RequestEvents::LATE, 'fn' => function (ProcessEvent $e) use($hash) {
         if ($e->getException()) {
             $hash[$e->getCommand()] = $e->getException();
         } else {
             $hash[$e->getCommand()] = $e->getResult();
         }
     }]));
     return new BatchResults($hash);
 }
示例#7
0
 /**
  * Transfers an HTTP request and populates a response
  *
  * @param TransactionInterface $transaction Transaction abject to populate
  *
  * @return ResponseInterface
  */
 public function send(TransactionInterface $transaction)
 {
     // HTTP/1.1 streams using the PHP stream wrapper require a
     // Connection: close header. Setting here so that it is added before
     // emitting the request.before_send event.
     $request = $transaction->getRequest();
     if ($request->getProtocolVersion() == '1.1' && !$request->hasHeader('Connection')) {
         $transaction->getRequest()->setHeader('Connection', 'close');
     }
     RequestEvents::emitBefore($transaction);
     if (!$transaction->getResponse()) {
         $this->createResponse($transaction);
         RequestEvents::emitComplete($transaction);
     }
     return $transaction->getResponse();
 }
 public function send(TransactionInterface $transaction)
 {
     RequestEvents::emitBefore($transaction);
     if (!$transaction->getResponse()) {
         $response = is_callable($this->response) ? call_user_func($this->response, $transaction) : $this->response;
         if (!$response instanceof ResponseInterface) {
             throw new \RuntimeException('Invalid mocked response');
         }
         // Read the request body if it is present
         if ($transaction->getRequest()->getBody()) {
             $transaction->getRequest()->getBody()->__toString();
         }
         $transaction->setResponse($response);
         RequestEvents::emitHeaders($transaction);
         RequestEvents::emitComplete($transaction);
     }
     return $transaction->getResponse();
 }
示例#9
0
文件: Pool.php 项目: samj1912/repo
 /**
  * Sends multiple requests in parallel and returns an array of responses
  * and exceptions that uses the same ordering as the provided requests.
  *
  * IMPORTANT: This method keeps every request and response in memory, and
  * as such, is NOT recommended when sending a large number or an
  * indeterminate number of requests concurrently.
  *
  * @param ClientInterface $client   Client used to send the requests
  * @param array|\Iterator $requests Requests to send in parallel
  * @param array           $options  Passes through the options available in
  *                                  {@see GuzzleHttp\Pool::__construct}
  *
  * @return BatchResults Returns a container for the results.
  * @throws \InvalidArgumentException if the event format is incorrect.
  */
 public static function batch(ClientInterface $client, $requests, array $options = [])
 {
     $hash = new \SplObjectStorage();
     foreach ($requests as $request) {
         $hash->attach($request);
     }
     // In addition to the normally run events when requests complete, add
     // and event to continuously track the results of transfers in the hash.
     (new self($client, $requests, RequestEvents::convertEventArray($options, ['end'], ['priority' => RequestEvents::LATE, 'fn' => function (EndEvent $e) use($hash) {
         $hash[$e->getRequest()] = $e->getException() ? $e->getException() : $e->getResponse();
     }])))->wait();
     return new BatchResults($hash);
 }
示例#10
0
 /**
  * Convenience method for sending multiple requests in parallel and
  * retrieving a hash map of requests to response objects or
  * RequestException objects.
  *
  * Note: This method keeps every request and response in memory, and as
  * such is NOT recommended when sending a large number or an indeterminable
  * number of requests in parallel.
  *
  * @param ClientInterface $client   Client used to send the requests
  * @param array|\Iterator $requests Requests to send in parallel
  * @param array           $options  Passes through the options available in
  *                                  {@see GuzzleHttp\ClientInterface::sendAll()}
  *
  * @return \SplObjectStorage Requests are the key and each value is a
  *     {@see GuzzleHttp\Message\ResponseInterface} if the request succeeded
  *     or a {@see GuzzleHttp\Exception\RequestException} if it failed.
  * @throws \InvalidArgumentException if the event format is incorrect.
  */
 function batch(ClientInterface $client, $requests, array $options = array())
 {
     $hash = new \SplObjectStorage();
     foreach ($requests as $request) {
         $hash->attach($request);
     }
     // Merge the necessary complete and error events to the event listeners
     // so that as each request succeeds or fails, it is added to the result
     // hash.
     $options = RequestEvents::convertEventArray($options, array('complete', 'error'), array('priority' => RequestEvents::EARLY, 'once' => true, 'fn' => function ($e) use($hash) {
         /** @noinspection PhpUndefinedMethodInspection */
         $hash[$e->getRequest()] = $e;
     }));
     // Send the requests in parallel and aggregate the results.
     $client->sendAll($requests, $options);
     // Update the received value for any of the intercepted requests.
     foreach ($hash as $request) {
         /** @var \GuzzleHttp\Event\ErrorEvent[] $hash */
         if ($hash[$request] instanceof CompleteEvent) {
             $hash[$request] = $hash[$request]->getResponse();
         } elseif ($hash[$request] instanceof ErrorEvent) {
             $hash[$request] = $hash[$request]->getException();
         }
     }
     return $hash;
 }
示例#11
0
 private function preventCommandExceptions(array $options)
 {
     // Prevent CommandExceptions from being thrown
     return RequestEvents::convertEventArray($options, array('error'), array('priority' => RequestEvents::LATE, 'fn' => function (CommandErrorEvent $e) {
         $e->stopPropagation();
     }));
 }
示例#12
0
 private function handleError(TransactionInterface $transaction, $info, $handle)
 {
     $error = curl_error($handle);
     $this->releaseEasyHandle($handle);
     RequestEvents::emitError($transaction, new AdapterException("cURL error {$info['curl_result']}: {$error}"), $info);
 }
 private function createResponseObject(array $headers, TransactionInterface $transaction, $stream)
 {
     $parts = explode(' ', array_shift($headers), 3);
     $options = ['protocol_version' => substr($parts[0], -3)];
     if (isset($parts[2])) {
         $options['reason_phrase'] = $parts[2];
     }
     // Set the size on the stream if it was returned in the response
     $responseHeaders = [];
     foreach ($headers as $header) {
         $headerParts = explode(':', $header, 2);
         $responseHeaders[$headerParts[0]] = isset($headerParts[1]) ? $headerParts[1] : '';
     }
     $response = $this->messageFactory->createResponse($parts[1], $responseHeaders, $stream, $options);
     $transaction->setResponse($response);
     RequestEvents::emitHeaders($transaction);
     return $response;
 }
示例#14
0
 /**
  * This function ensures that a response was set on a transaction. If one
  * was not set, then the request is retried if possible. This error
  * typically means you are sending a payload, curl encountered a
  * "Connection died, retrying a fresh connect" error, tried to rewind the
  * stream, and then encountered a "necessary data rewind wasn't possible"
  * error, causing the request to be sent through curl_multi_info_read()
  * without an error status.
  *
  * @param TransactionInterface $transaction
  * @param BatchContext         $context
  *
  * @return bool Returns true if it's OK, and false if it failed.
  * @throws \GuzzleHttp\Exception\RequestException If it failed and cannot
  *                                                recover.
  */
 private function validateResponseWasSet(TransactionInterface $transaction, BatchContext $context)
 {
     if ($transaction->getResponse()) {
         return true;
     }
     $body = $transaction->getRequest()->getBody();
     if (!$body) {
         // This is weird and should probably never happen.
         RequestEvents::emitError($transaction, new RequestException('No response was received for a request with no body. This' . ' could mean that you are saturating your network.', $transaction->getRequest()));
     } elseif (!$body->isSeekable() || !$body->seek(0)) {
         // Nothing we can do with this. Sorry!
         RequestEvents::emitError($transaction, new RequestException('The connection was unexpectedly closed. The request would' . ' have been retried, but attempting to rewind the' . ' request body failed. Consider wrapping your request' . ' body in a CachingStream decorator to work around this' . ' issue if necessary.', $transaction->getRequest()));
     } else {
         $this->retryFailedConnection($transaction, $context);
     }
     return false;
 }
示例#15
0
 public function testThrowsUnInterceptedErrors()
 {
     $ex = new \Exception('Foo');
     $client = new Client();
     $request = new Request('GET', '/');
     $t = new Transaction($client, $request);
     $errCalled = 0;
     $request->getEmitter()->on('before', function (BeforeEvent $e) use($ex) {
         throw $ex;
     });
     $request->getEmitter()->on('error', function (ErrorEvent $e) use(&$errCalled) {
         $errCalled++;
     });
     try {
         RequestEvents::emitBefore($t);
         $this->fail('Did not throw');
     } catch (RequestException $e) {
         $this->assertEquals(1, $errCalled);
     }
 }
 /**
  * @dataProvider prepareEventProvider
  */
 public function testConvertsEventArrays(array $in, array $events, $add, array $out)
 {
     $result = RequestEvents::convertEventArray($in, $events, $add);
     $this->assertEquals($out, $result);
 }
示例#17
0
 private function isCurlException(TransactionInterface $transaction, array $curl, BatchContext $context, array $info)
 {
     if (CURLM_OK == $curl['result'] || CURLM_CALL_MULTI_PERFORM == $curl['result']) {
         return false;
     }
     $request = $transaction->getRequest();
     try {
         // Send curl stats along if they are available
         $stats = ['curl_result' => $curl['result']] + $info;
         RequestEvents::emitError($transaction, new RequestException(sprintf('[curl] (#%s) %s [url] %s', $curl['result'], function_exists('curl_strerror') ? curl_strerror($curl['result']) : self::ERROR_STR, $request->getUrl()), $request), $stats);
     } catch (RequestException $e) {
         $this->throwException($e, $context);
     }
     return true;
 }
示例#18
0
 /**
  * @expectedException \InvalidArgumentException
  */
 public function testValidatesEventFormat()
 {
     RequestEvents::convertEventArray(['foo' => false], ['foo'], []);
 }