/** * Intercept the exception and inject a response * * @param puzzle_message_ResponseInterface $response Response to set */ public function intercept(puzzle_message_ResponseInterface $response) { $this->stopPropagation(); $this->getTransaction()->setResponse($response); $this->exception->setThrowImmediately(false); puzzle_event_RequestEvents::emitComplete($this->getTransaction()); }
private function createResponseObject(puzzle_message_RequestInterface $request, array $headers, puzzle_adapter_TransactionInterface $transaction, puzzle_stream_StreamInterface $stream) { $parts = explode(' ', array_shift($headers), 3); $options = array('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 puzzle_stream_InflateStream($stream); break; } } // Drain the stream immediately if 'stream' was not enabled. $config = $request->getConfig(); if (!$config['stream']) { $stream = $this->getSaveToBody($request, $stream); } $response->setBody($stream); $transaction->setResponse($response); puzzle_event_RequestEvents::emitHeaders($transaction); return $response; }
/** * 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 puzzle_event_RequestEvents::emitHeaders($this->transaction); } return $length; }
public function send(puzzle_adapter_TransactionInterface $transaction) { puzzle_event_RequestEvents::emitBefore($transaction); if (!$transaction->getResponse()) { // Read the request body if it is present if ($transaction->getRequest()->getBody()) { $transaction->getRequest()->getBody()->__toString(); } $response = is_callable($this->response) ? call_user_func($this->response, $transaction) : $this->response; if (!$response instanceof puzzle_message_ResponseInterface) { throw new RuntimeException('Invalid mocked response'); } $transaction->setResponse($response); puzzle_event_RequestEvents::emitHeaders($transaction); puzzle_event_RequestEvents::emitComplete($transaction); } return $transaction->getResponse(); }
private function validateResponseWasSet(puzzle_adapter_TransactionInterface $transaction, puzzle_adapter_curl_BatchContext $context) { if ($transaction->getResponse()) { return true; } $body = $transaction->getRequest()->getBody(); if (!$body) { // This is weird and should probably never happen. puzzle_event_RequestEvents::emitError($transaction, new puzzle_exception_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! puzzle_event_RequestEvents::emitError($transaction, new puzzle_exception_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; }
/** * 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 puzzle_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 puzzle_ClientInterface::sendAll()} * * @return SplObjectStorage Requests are the key and each value is a * {@see puzzle_message_ResponseInterface} if the request succeeded * or a {@see puzzle_exception_RequestException} if it failed. * @throws InvalidArgumentException if the event format is incorrect. */ function puzzle_batch(puzzle_ClientInterface $client, $requests, array $options = array()) { global $__closure_puzzle_batch_hash; $__closure_puzzle_batch_hash = new puzzle_SplObjectStorage(); foreach ($requests as $request) { $__closure_puzzle_batch_hash->offsetSet($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 = puzzle_event_RequestEvents::convertEventArray($options, array('complete', 'error'), array('priority' => puzzle_event_RequestEvents::EARLY, 'once' => true, 'fn' => '__callback_puzzle_batch_convertEvents')); // Send the requests in parallel and aggregate the results. $client->sendAll($requests, $options); // Update the received value for any of the intercepted requests. foreach ($__closure_puzzle_batch_hash as $request) { $storedEvent = $__closure_puzzle_batch_hash->offsetGet($request); if ($storedEvent instanceof puzzle_event_CompleteEvent) { $__closure_puzzle_batch_hash->offsetSet($request, $storedEvent->getResponse()); } elseif ($storedEvent instanceof puzzle_event_ErrorEvent) { $__closure_puzzle_batch_hash->offsetSet($request, $storedEvent->getException()); } } return $__closure_puzzle_batch_hash; }
private function handleError(puzzle_adapter_TransactionInterface $transaction, $info, $handle) { $error = curl_error($handle); $this->releaseEasyHandle($handle); puzzle_event_RequestEvents::emitError($transaction, new puzzle_exception_AdapterException("cURL error {$info['curl_result']}: {$error}"), $info); }
/** * @dataProvider prepareEventProvider */ public function testConvertsEventArrays(array $in, array $events, $add, array $out) { $result = puzzle_event_RequestEvents::convertEventArray($in, $events, $add); $this->assertEquals($out, $result); }