]> BookStack Code Mirror - bookstack/blobdiff - app/Http/Controllers/Controller.php
Fixed streamed outputs in more extreme scenarios
[bookstack] / app / Http / Controllers / Controller.php
index 13a86f6f7c78672ef99cdab9dedb566d1b148cec..4c979c26a1ac1526f46e9afcf37d9414fb2e5dd9 100644 (file)
@@ -12,6 +12,7 @@ use Illuminate\Foundation\Validation\ValidatesRequests;
 use Illuminate\Http\JsonResponse;
 use Illuminate\Http\Response;
 use Illuminate\Routing\Controller as BaseController;
+use Symfony\Component\HttpFoundation\StreamedResponse;
 
 abstract class Controller extends BaseController
 {
@@ -54,6 +55,7 @@ abstract class Controller extends BaseController
     protected function showPermissionError()
     {
         $message = request()->wantsJson() ? trans('errors.permissionJson') : trans('errors.permission');
+
         throw new NotifyException($message, '/', 403);
     }
 
@@ -119,6 +121,22 @@ abstract class Controller extends BaseController
         ]);
     }
 
+    /**
+     * Create a response that forces a download, from a given stream of content.
+     */
+    protected function streamedDownloadResponse($stream, string $fileName): StreamedResponse
+    {
+        return response()->stream(function() use ($stream) {
+            ob_end_clean();
+            fpassthru($stream);
+            fclose($stream);
+        }, 200, [
+            'Content-Type'           => 'application/octet-stream',
+            'Content-Disposition'    => 'attachment; filename="' . $fileName . '"',
+            'X-Content-Type-Options' => 'nosniff',
+        ]);
+    }
+
     /**
      * Create a file download response that provides the file with a content-type
      * correct for the file, in a way so the browser can show the content in browser.
@@ -134,6 +152,27 @@ abstract class Controller extends BaseController
         ]);
     }
 
+    /**
+     * Create a file download response that provides the file with a content-type
+     * correct for the file, in a way so the browser can show the content in browser,
+     * for a given content stream.
+     */
+    protected function streamedInlineDownloadResponse($stream, string $fileName): StreamedResponse
+    {
+        $sniffContent = fread($stream, 1000);
+        $mime = (new WebSafeMimeSniffer())->sniff($sniffContent);
+
+        return response()->stream(function() use ($sniffContent, $stream) {
+           echo $sniffContent;
+           fpassthru($stream);
+           fclose($stream);
+        }, 200, [
+            'Content-Type'           => $mime,
+            'Content-Disposition'    => 'inline; filename="' . $fileName . '"',
+            'X-Content-Type-Options' => 'nosniff',
+        ]);
+    }
+
     /**
      * Show a positive, successful notification to the user on next view load.
      */