protected function sendRequest(SocketStream $socket, HttpRequest $request, int &$sent) : \Generator { $request = $this->normalizeRequest($request); $body = $request->getBody(); $size = (yield $body->getSize()); $sendfile = false; if ($body instanceof FileBody && $socket->isSendfileSupported()) { $sendfile = true; $chunk = $size ? '' : null; } else { if ($request->getProtocolVersion() == '1.0' && $size === null) { if (!$body->isCached()) { $body = new BufferedBody((yield $body->getReadableStream())); } (yield $body->discard()); $size = (yield $body->getSize()); } $bodyStream = (yield $body->getReadableStream()); $clen = $size === null ? 4089 : 4096; $chunk = (yield $bodyStream->readBuffer($clen)); $len = \strlen($chunk ?? ''); if ($chunk === null) { $size = 0; } elseif ($len < $clen) { $size = $len; } } $buffer = $this->serializeHeaders($request, $size); $expect = false; if ($this->expectContinue && $chunk !== null && $request->getProtocolVersion() == '1.1') { $expect = true; $buffer .= "Expect: 100-continue\r\n"; } (yield $socket->write($buffer . "\r\n")); (yield $socket->flush()); if ($expect) { if (!\preg_match("'^HTTP/1\\.1\\s+100(?:\$|\\s)'i", $line = (yield $socket->readLine()))) { try { return $line; } finally { if (isset($bodyStream)) { $bodyStream->close(); } } } } if ($sendfile) { if ($size) { $sent += (yield LoopConfig::currentFilesystem()->sendfile($body->getFile(), $socket->getSocket(), $size)); } } elseif ($size === null) { $sent += (yield $socket->write(\dechex($len) . "\r\n" . $chunk . "\r\n")); if ($len === $clen) { // Align each chunk with length and line breaks to fit into 4 KB payload. $sent += (yield new CopyBytes($bodyStream, $socket, true, null, 4089, function (string $chunk) { return \dechex(\strlen($chunk)) . "\r\n" . $chunk . "\r\n"; })); } (yield $socket->write("0\r\n\r\n")); } elseif ($size > 0) { $sent += (yield $socket->write($chunk)); if ($len === $clen) { $sent += (yield new CopyBytes($bodyStream, $socket, true, $size - $len)); } } (yield $socket->flush()); }