Added test to cover.
For #5119
# Example: EXPORT_PDF_COMMAND="/scripts/convert.sh {input_html_path} {output_pdf_path}"
EXPORT_PDF_COMMAND=false
+# Export PDF Command Timeout
+# The number of seconds that the export PDF command will run before a timeout occurs.
+# Only applies for the EXPORT_PDF_COMMAND option, not for DomPDF or wkhtmltopdf.
+EXPORT_PDF_COMMAND_TIMEOUT=15
+
# Set path to wkhtmltopdf binary for PDF generation.
# Can be 'false' or a path path like: '/home/bins/wkhtmltopdf'
# When false, BookStack will attempt to find a wkhtmltopdf in the application
// Example: EXPORT_PDF_COMMAND="/scripts/convert.sh {input_html_path} {output_pdf_path}"
'pdf_command' => env('EXPORT_PDF_COMMAND', false),
+ // The amount of time allowed for PDF generation command to run
+ // before the process times out and is stopped.
+ 'pdf_command_timeout' => env('EXPORT_PDF_COMMAND_TIMEOUT', 15),
+
// 2024-04: Snappy/WKHTMLtoPDF now considered deprecated in regard to BookStack support.
'snappy' => [
'pdf_binary' => env('WKHTMLTOPDF', false),
use BookStack\Exceptions\PdfExportException;
use Knp\Snappy\Pdf as SnappyPdf;
use Dompdf\Dompdf;
+use Symfony\Component\Process\Exception\ProcessTimedOutException;
use Symfony\Component\Process\Process;
class PdfGenerator
file_put_contents($inputHtml, $html);
+ $timeout = intval(config('exports.pdf_command_timeout'));
$process = Process::fromShellCommandline($command);
- $process->setTimeout(15);
- $process->run();
+ $process->setTimeout($timeout);
+
+ try {
+ $process->run();
+ } catch (ProcessTimedOutException $e) {
+ throw new PdfExportException("PDF Export via command failed due to timeout at {$timeout} second(s)");
+ }
if (!$process->isSuccessful()) {
throw new PdfExportException("PDF Export via command failed with exit code {$process->getExitCode()}, stdout: {$process->getOutput()}, stderr: {$process->getErrorOutput()}");
}, PdfExportException::class);
}
+ public function test_pdf_command_timout_option_limits_export_time()
+ {
+ $page = $this->entities->page();
+ $command = 'php -r \'sleep(4);\'';
+ config()->set('exports.pdf_command', $command);
+ config()->set('exports.pdf_command_timeout', 1);
+
+ $this->assertThrows(function () use ($page) {
+ $start = time();
+ $this->withoutExceptionHandling()->asEditor()->get($page->getUrl('/export/pdf'));
+
+ $this->assertTrue(time() < ($start + 3));
+ }, PdfExportException::class,
+ "PDF Export via command failed due to timeout at 1 second(s)");
+ }
+
public function test_html_exports_contain_csp_meta_tag()
{
$entities = [