mirror of
https://github.com/Yetangitu/ampache
synced 2025-10-03 17:59:21 +02:00
138 lines
3.3 KiB
PHP
138 lines
3.3 KiB
PHP
<?php
|
|
|
|
namespace React\Http;
|
|
|
|
use Evenement\EventEmitter;
|
|
use React\Socket\ConnectionInterface;
|
|
use React\Stream\WritableStreamInterface;
|
|
|
|
class Response extends EventEmitter implements WritableStreamInterface
|
|
{
|
|
private $closed = false;
|
|
private $writable = true;
|
|
private $conn;
|
|
private $headWritten = false;
|
|
private $chunkedEncoding = true;
|
|
|
|
public function __construct(ConnectionInterface $conn)
|
|
{
|
|
$this->conn = $conn;
|
|
|
|
$this->conn->on('end', function () {
|
|
$this->close();
|
|
});
|
|
|
|
$this->conn->on('error', function ($error) {
|
|
$this->emit('error', array($error, $this));
|
|
$this->close();
|
|
});
|
|
|
|
$this->conn->on('drain', function () {
|
|
$this->emit('drain');
|
|
});
|
|
}
|
|
|
|
public function isWritable()
|
|
{
|
|
return $this->writable;
|
|
}
|
|
|
|
public function writeContinue()
|
|
{
|
|
if ($this->headWritten) {
|
|
throw new \Exception('Response head has already been written.');
|
|
}
|
|
|
|
$this->conn->write("HTTP/1.1 100 Continue\r\n");
|
|
}
|
|
|
|
public function writeHead($status = 200, array $headers = array())
|
|
{
|
|
if ($this->headWritten) {
|
|
throw new \Exception('Response head has already been written.');
|
|
}
|
|
|
|
if (isset($headers['Content-Length'])) {
|
|
$this->chunkedEncoding = false;
|
|
}
|
|
|
|
$headers = array_merge(
|
|
array('X-Powered-By' => 'React/alpha'),
|
|
$headers
|
|
);
|
|
if ($this->chunkedEncoding) {
|
|
$headers['Transfer-Encoding'] = 'chunked';
|
|
}
|
|
|
|
$data = $this->formatHead($status, $headers);
|
|
$this->conn->write($data);
|
|
|
|
$this->headWritten = true;
|
|
}
|
|
|
|
private function formatHead($status, array $headers)
|
|
{
|
|
$status = (int) $status;
|
|
$text = isset(ResponseCodes::$statusTexts[$status]) ? ResponseCodes::$statusTexts[$status] : '';
|
|
$data = "HTTP/1.1 $status $text\r\n";
|
|
|
|
foreach ($headers as $name => $value) {
|
|
$name = str_replace(array("\r", "\n"), '', $name);
|
|
|
|
foreach ((array) $value as $val) {
|
|
$val = str_replace(array("\r", "\n"), '', $val);
|
|
|
|
$data .= "$name: $val\r\n";
|
|
}
|
|
}
|
|
$data .= "\r\n";
|
|
|
|
return $data;
|
|
}
|
|
|
|
public function write($data)
|
|
{
|
|
if (!$this->headWritten) {
|
|
throw new \Exception('Response head has not yet been written.');
|
|
}
|
|
|
|
if ($this->chunkedEncoding) {
|
|
$len = strlen($data);
|
|
$chunk = dechex($len)."\r\n".$data."\r\n";
|
|
$flushed = $this->conn->write($chunk);
|
|
} else {
|
|
$flushed = $this->conn->write($data);
|
|
}
|
|
|
|
return $flushed;
|
|
}
|
|
|
|
public function end($data = null)
|
|
{
|
|
if (null !== $data) {
|
|
$this->write($data);
|
|
}
|
|
|
|
if ($this->chunkedEncoding) {
|
|
$this->conn->write("0\r\n\r\n");
|
|
}
|
|
|
|
$this->emit('end');
|
|
$this->removeAllListeners();
|
|
$this->conn->end();
|
|
}
|
|
|
|
public function close()
|
|
{
|
|
if ($this->closed) {
|
|
return;
|
|
}
|
|
|
|
$this->closed = true;
|
|
|
|
$this->writable = false;
|
|
$this->emit('close');
|
|
$this->removeAllListeners();
|
|
$this->conn->close();
|
|
}
|
|
}
|