* * For the full copyright and license information, please view the LICENSE * file that was distributed with this source code. */ namespace Symfony\Component\HttpClient\Response; use Psr\Log\LoggerInterface; use Symfony\Component\HttpClient\Chunk\DataChunk; use Symfony\Component\HttpClient\Chunk\ErrorChunk; use Symfony\Component\HttpClient\Chunk\FirstChunk; use Symfony\Component\HttpClient\Chunk\LastChunk; use Symfony\Component\HttpClient\Exception\TransportException; use Symfony\Component\HttpClient\Internal\Canary; use Symfony\Component\HttpClient\Internal\ClientState; /** * Implements common logic for transport-level response classes. * * @author Nicolas Grekas
*
* @internal
*/
trait TransportResponseTrait
{
/**
* @var \Symfony\Component\HttpClient\Internal\Canary
*/
private $canary;
/**
* @var mixed[]
*/
private $headers = [];
/**
* @var mixed[]
*/
private $info = [
'response_headers' => [],
'http_code' => 0,
'error' => null,
'canceled' => false,
];
/** @var object|resource */
private $handle;
/**
* @var int|string
*/
private $id;
/**
* @var float|null
*/
private $timeout = 0;
/**
* @var \InflateContext|bool|null
*/
private $inflate = null;
/**
* @var mixed[]|null
*/
private $finalInfo;
/**
* @var \Psr\Log\LoggerInterface|null
*/
private $logger;
public function getStatusCode()
{
if ($this->initializer) {
self::initialize($this);
}
return $this->info['http_code'];
}
/**
* @param bool $throw
*/
public function getHeaders($throw = true)
{
if ($this->initializer) {
self::initialize($this);
}
if ($throw) {
$this->checkStatusCode();
}
return $this->headers;
}
public function cancel()
{
$this->info['canceled'] = true;
$this->info['error'] = 'Response has been canceled.';
$this->close();
}
/**
* Closes the response and all its network handles.
*/
protected function close()
{
$this->canary->cancel();
$this->inflate = null;
}
/**
* Adds pending responses to the activity list.
* @param $this $response
* @param mixed[] $runningResponses
*/
abstract protected static function schedule($response, &$runningResponses);
/**
* Performs all pending non-blocking operations.
* @param \Symfony\Component\HttpClient\Internal\ClientState $multi
* @param mixed[] $responses
*/
abstract protected static function perform($multi, &$responses);
/**
* Waits for network activity.
* @param \Symfony\Component\HttpClient\Internal\ClientState $multi
* @param float $timeout
*/
abstract protected static function select($multi, $timeout);
/**
* @param mixed[] $responseHeaders
* @param mixed[] $info
* @param mixed[] $headers
* @param string $debug
*/
private static function addResponseHeaders($responseHeaders, &$info, &$headers, &$debug = '')
{
foreach ($responseHeaders as $h) {
if (11 <= \strlen($h) && '/' === $h[4] && preg_match('#^HTTP/\d+(?:\.\d+)? (\d\d\d)(?: |$)#', $h, $m)) {
if ($headers) {
$debug .= "< \r\n";
$headers = [];
}
$info['http_code'] = (int) $m[1];
} elseif (2 === \count($m = explode(':', $h, 2))) {
$headers[strtolower($m[0])][] = ltrim($m[1]);
}
$debug .= "< {$h}\r\n";
$info['response_headers'][] = $h;
}
$debug .= "< \r\n";
}
/**
* Ensures the request is always sent and that the response code was checked.
*/
private function doDestruct()
{
$this->shouldBuffer = true;
if ($this->initializer && null === $this->info['error']) {
self::initialize($this);
$this->checkStatusCode();
}
}
/**
* Implements an event loop based on a buffer activity queue.
*
* @param iterable