From 5d252d96493fdaf41f46ada8442590ad44474c6e Mon Sep 17 00:00:00 2001 From: Oscar Otero Date: Mon, 2 Mar 2020 23:53:18 +0100 Subject: [PATCH] use temp streams to store the body --- src/Http/CurlDispatcher.php | 68 ++++++++++++++++++---------------- tests/MultipleRequestsTest.php | 5 +++ 2 files changed, 42 insertions(+), 31 deletions(-) diff --git a/src/Http/CurlDispatcher.php b/src/Http/CurlDispatcher.php index 0345e179..c391562f 100644 --- a/src/Http/CurlDispatcher.php +++ b/src/Http/CurlDispatcher.php @@ -16,7 +16,7 @@ final class CurlDispatcher private RequestInterface $request; private $curl; private array $headers = []; - private bool $multi = false; + private $body; private ?int $error = null; /** @@ -28,7 +28,7 @@ public static function fetch(?ResponseFactoryInterface $responseFactory, Request if (count($requests) === 1) { $connection = new static($requests[0]); - return [$connection($responseFactory)]; + return [$connection->exec($responseFactory)]; } //Init connections @@ -37,7 +37,6 @@ public static function fetch(?ResponseFactoryInterface $responseFactory, Request foreach ($requests as $request) { $connection = new static($request); - $connection->multi = true; curl_multi_add_handle($multi, $connection->curl); $connections[] = $connection; @@ -72,7 +71,7 @@ public static function fetch(?ResponseFactoryInterface $responseFactory, Request curl_multi_close($multi); return array_map( - fn ($connection) => $connection($responseFactory), + fn ($connection) => $connection->exec($responseFactory), $connections ); } @@ -101,33 +100,14 @@ private function __construct(RequestInterface $request) CURLOPT_USERAGENT => $request->getHeaderLine('User-Agent'), CURLOPT_COOKIEJAR => $cookies, CURLOPT_COOKIEFILE => $cookies, + CURLOPT_HEADERFUNCTION => [$this, 'writeHeader'], + CURLOPT_WRITEFUNCTION => [$this, 'writeBody'], ]); - - curl_setopt( - $this->curl, - CURLOPT_HEADERFUNCTION, - function ($resource, $string) { - if (preg_match('/^([\w-]+):(.*)$/', $string, $matches)) { - $name = strtolower($matches[1]); - $value = trim($matches[2]); - $this->headers[] = [$name, $value]; - } elseif ($this->headers) { - $key = array_key_last($this->headers); - $this->headers[$key][1] .= ' '.trim($string); - } - - return strlen($string); - } - ); } - public function __invoke(ResponseFactoryInterface $responseFactory): ResponseInterface + private function exec(ResponseFactoryInterface $responseFactory): ResponseInterface { - if ($this->multi) { - $body = curl_multi_getcontent($this->curl); - } else { - $body = curl_exec($this->curl); - } + curl_exec($this->curl); $info = curl_getinfo($this->curl); @@ -148,11 +128,14 @@ public function __invoke(ResponseFactoryInterface $responseFactory): ResponseInt $response = $response->withAddedHeader($name, $value); } - if (!$response->hasHeader('Content-Location')) { - $response = $response->withHeader('Content-Location', $info['url']); - } + $response = $response + ->withAddedHeader('Content-Location', $info['url']) + ->withAddedHeader('X-Request-Time', sprintf('%.3f ms', $info['total_time'])); - $response->getBody()->write($body); + if ($this->body) { + //5Mb max + $response->getBody()->write(stream_get_contents($this->body, 5000000, 0)); + } return $response; } @@ -177,4 +160,27 @@ private function getRequestHeaders(): array return $headers; } + + private function writeHeader($curl, $string): int + { + if (preg_match('/^([\w-]+):(.*)$/', $string, $matches)) { + $name = strtolower($matches[1]); + $value = trim($matches[2]); + $this->headers[] = [$name, $value]; + } elseif ($this->headers) { + $key = array_key_last($this->headers); + $this->headers[$key][1] .= ' '.trim($string); + } + + return strlen($string); + } + + private function writeBody($curl, $string): int + { + if (!$this->body) { + $this->body = fopen('php://temp', 'w+'); + } + + return fwrite($this->body, $string); + } } diff --git a/tests/MultipleRequestsTest.php b/tests/MultipleRequestsTest.php index cfe229bf..846e09de 100644 --- a/tests/MultipleRequestsTest.php +++ b/tests/MultipleRequestsTest.php @@ -19,7 +19,12 @@ public function testParallel() $this->assertCount(3, $infos); $this->assertEquals('https://oscarotero.com/', $infos[0]->url); + $this->assertEquals('Óscar Otero - Web designer and developer', $infos[0]->title); + $this->assertEquals('https://github.com/oscarotero', $infos[1]->url); + $this->assertEquals('oscarotero - Overview', $infos[1]->title); + $this->assertEquals('https://twitter.com/misteroom', $infos[2]->url); + $this->assertEquals('en', $infos[2]->language); } }