mvc/api - improve stream handling and prevent "headers already sent" errors from being thrown.

This commit moves the output handling from the action to the Response object for stream types, which also ensures headers are being sent in the right order.
This commit is contained in:
Ad Schellevis 2024-05-13 18:04:31 +02:00
parent ae2b376885
commit ef9e377fde
4 changed files with 23 additions and 18 deletions

View File

@ -154,14 +154,12 @@ class ApiControllerBase extends ControllerRoot
foreach ($records as $record) {
fputcsv($stream, $record);
}
fseek($stream, 0);
foreach ($headers as $header) {
header($header);
$parts = explode(':', $header, 2);
$this->response->setHeader($parts[0], ltrim($parts[1]));
}
ob_end_flush();
rewind($stream);
fpassthru($stream);
fclose($stream);
$this->response->setContent($stream);
}
/**
@ -179,17 +177,13 @@ class ApiControllerBase extends ControllerRoot
],
$poll_timeout = 2
) {
/* Never allow output compression on streams */
ini_set('zlib.output_compression', 'Off');
ob_end_clean();
$response = (new Backend())->configdpStream($action, $params, $poll_timeout);
foreach ($headers as $header) {
header($header);
$parts = explode(':', $header, 2);
$this->response->setHeader($parts[0], ltrim($parts[1]));
}
while (ob_get_level() > 0) {
ob_end_flush();
}
fpassthru($response);
$this->response->setContent($response);
}
/**

View File

@ -61,11 +61,12 @@ class ControllerRoot extends Controller
protected $langcode = 'en_US';
/**
* XXX: remove in a future version, sessions are handled via session class
* Wrap close session, for long running operations.
*/
protected function sessionClose()
{
session_write_close();
return;
}
/**

View File

@ -33,7 +33,7 @@ use Exception;
class Response
{
private Headers $headers;
private string $content = '';
private mixed $content = '';
private bool $sent = false;
public function __construct()
@ -46,7 +46,7 @@ class Response
return $this->headers;
}
public function setContent(string $content): void
public function setContent(mixed $content): void
{
$this->content = $content;
}
@ -98,7 +98,18 @@ class Response
}
$this->headers->send();
echo $this->content;
if (is_resource($this->content)) {
/* Never allow output compression on streams */
ini_set('zlib.output_compression', 'Off');
while (ob_get_level() > 0) {
ob_end_flush();
}
fpassthru($this->content);
@fclose($this->content);
} elseif (!empty($this->content)) {
echo $this->content;
}
$this->sent = true;
}

View File

@ -87,7 +87,6 @@ class Security
*/
public function checkToken(?string $tokenKey = null, ?string $tokenValue = null): bool
{
$key = $tokenKey ?? $this->getTokenKey(false);
if (empty($key)) {
return false;