/** * Parse the next HTTP response from the given stream. * * @param ReadableStream $stream * @param string $line HTTP response line (mighty already be received while checking for 100 continue). * @param bool $dropBody Drop response body (needed when the response is caused by a HEAD request). * @return HttpResponse * * @throws StreamClosedException When no HTTP response line could be parsed. */ public function parseResponse(ReadableStream $stream, string $line = null, bool $dropBody = false) : \Generator { if ($line === null) { $i = 0; do { if ($i++ > 3 || null === ($line = (yield $stream->readLine()))) { throw new StreamClosedException('Stream closed before HTTP response line was read'); } } while ($line === ''); } $m = null; if (!\preg_match("'^HTTP/(1\\.[01])\\s+([1-5][0-9]{2})(.*)\$'i", \trim($line), $m)) { throw new StreamClosedException('Invalid HTTP response line received'); } $response = new HttpResponse(); $response = $response->withProtocolVersion($m[1]); $response = $response->withStatus((int) $m[2], \trim($m[3])); $response = (yield from $this->parseHeaders($stream, $response)); if ($dropBody || Http::isResponseWithoutBody($response->getStatusCode())) { $body = new StringBody(); if (!$dropBody) { $response = $response->withHeader('Content-Length', '0'); } } else { $body = Body::fromMessage($stream, $response); } static $remove = ['TE', 'Trailer']; foreach ($remove as $name) { $response = $response->withoutHeader($name); } return $response->withBody($body); }
public function parseRequest(ReadableStream $stream) : \Generator { $i = 0; do { if ($i++ > 3 || null === ($line = (yield $stream->readLine()))) { throw new StreamClosedException('Stream closed before HTTP request line was read'); } } while ($line === ''); $m = null; if (!\preg_match("'^(\\S+)\\s+(.+)\\s+HTTP/(1\\.[01])\$'i", \trim($line), $m)) { throw new StreamClosedException('Invalid HTTP request line received'); } $request = new HttpRequest($m[2], $m[1], [], $m[3]); $request = $request->withRequestTarget(\trim($m[2])); $request = (yield from $this->parseHeaders($stream, $request)); $body = Body::fromMessage($stream, $request); static $remove = ['Content-Encoding', 'Trailer']; foreach ($remove as $name) { $request = $request->withoutHeader($name); } return $request->withBody($body); }