public function writer(InternalRequest $ireq) : \Generator
{
$headers = yield;
$client = $ireq->client;
if (!empty($headers["connection"])) {
foreach ($headers["connection"] as $connection) {
if (\strcasecmp($connection, "close") === 0) {
$client->shouldClose = true;
}
}
}
$lines = ["HTTP/{$ireq->protocol} {$headers[":status"]} {$headers[":reason"]}"];
unset($headers[":status"], $headers[":reason"]);
foreach ($headers as $headerField => $headerLines) {
if ($headerField[0] !== ":") {
foreach ($headerLines as $headerLine) {
/* verify header fields (per RFC) and header values against containing \n */
\assert(strpbrk($headerField, "\n\t ()<>@,;:\\\"/[]?={}") === false && strpbrk($headerLine, "\n") === false);
$lines[] = "{$headerField}: {$headerLine}";
}
}
}
$lines[] = "\r\n";
$msgPart = \implode("\r\n", $lines);
$msgs = "";
do {
$msgs .= $msgPart;
if ($msgPart === false || \strlen($msgs) >= $client->options->outputBufferSize) {
$client->writeBuffer .= $msgs;
($this->responseWriter)($client);
$msgs = "";
if ($client->isDead & Client::CLOSED_WR) {
if (!$client->bufferPromisor) {
$client->bufferPromisor = new Deferred();
$client->bufferPromisor->fail(new ClientException());
}
while (true) {
yield;
}
}
$client->bufferSize = \strlen($client->writeBuffer);
if ($client->bufferPromisor) {
if ($client->bufferSize <= $client->options->softStreamCap) {
$client->bufferPromisor->succeed();
}
} elseif ($client->bufferSize > $client->options->softStreamCap) {
$client->bufferPromisor = new Deferred();
}
}
} while (($msgPart = yield) !== null);
$client->writeBuffer .= $msgs;
// parserEmitLock check is required to prevent recursive continuation of the parser
if ($client->requestParser && $client->parserEmitLock && !$client->shouldClose) {
$client->requestParser->send(false);
}
($this->responseWriter)($client, $final = true);
if ($client->isDead & Client::CLOSED_WR) {
if (!$client->bufferPromisor) {
$client->bufferPromisor = new Deferred();
$client->bufferPromisor->fail(new ClientException());
}
} elseif ($client->isDead & Client::CLOSED_RD && $client->bodyPromisors) {
array_pop($client->bodyPromisors)->fail(new ClientException());
// just one element with Http1Driver
}
}