Skip to content

Commit 26c65bc

Browse files
committed
Do not render exceptions in streamed download
1 parent f2bfbed commit 26c65bc

File tree

3 files changed

+70
-1
lines changed

3 files changed

+70
-1
lines changed

src/Illuminate/Foundation/Exceptions/Handler.php

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,13 @@ protected function prepareException(Throwable $e)
369369
*/
370370
protected function mapException(Throwable $e)
371371
{
372+
if (
373+
method_exists($e, 'getInnerException') &&
374+
($inner = $e->getInnerException()) instanceof Throwable
375+
) {
376+
return $inner;
377+
}
378+
372379
foreach ($this->exceptionMap as $class => $mapper) {
373380
if (is_a($e, $class)) {
374381
return $mapper($e);
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
<?php
2+
3+
namespace Illuminate\Routing\Exceptions;
4+
5+
use Illuminate\Http\Response;
6+
use RuntimeException;
7+
use Throwable;
8+
9+
class StreamedResponseException extends RuntimeException
10+
{
11+
/**
12+
* The actual exception thrown during the stream.
13+
*
14+
* @var \Throwable
15+
*/
16+
public $originalException;
17+
18+
/**
19+
* Create a new exception instance.
20+
*
21+
* @param \Throwable $originalException
22+
* @return void
23+
*/
24+
public function __construct(Throwable $originalException)
25+
{
26+
$this->originalException = $originalException;
27+
28+
parent::__construct($originalException->message);
29+
}
30+
31+
/**
32+
* Render the exception.
33+
*
34+
* @return \Illuminate\Http\Response
35+
*/
36+
public function render()
37+
{
38+
// Since we are in the process of streaming a file download,
39+
// we don't actually want it to render anything into the
40+
// file being downloaded. We return an empty response.
41+
return new Response('');
42+
}
43+
44+
/**
45+
* Get the actual exception thrown during the stream.
46+
*
47+
* @return \Throwable
48+
*/
49+
public function getInnerException()
50+
{
51+
return $this->originalException;
52+
}
53+
}

src/Illuminate/Routing/ResponseFactory.php

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
use Illuminate\Support\Traits\Macroable;
1111
use Symfony\Component\HttpFoundation\BinaryFileResponse;
1212
use Symfony\Component\HttpFoundation\StreamedResponse;
13+
use Throwable;
1314

1415
class ResponseFactory implements FactoryContract
1516
{
@@ -138,7 +139,15 @@ public function stream($callback, $status = 200, array $headers = [])
138139
*/
139140
public function streamDownload($callback, $name = null, array $headers = [], $disposition = 'attachment')
140141
{
141-
$response = new StreamedResponse($callback, 200, $headers);
142+
$withWrappedException = function () use ($callback) {
143+
try {
144+
$callback();
145+
} catch (Throwable $e) {
146+
throw new StreamedResponseException($e);
147+
}
148+
};
149+
150+
$response = new StreamedResponse($withWrappedException, 200, $headers);
142151

143152
if (! is_null($name)) {
144153
$response->headers->set('Content-Disposition', $response->headers->makeDisposition(

0 commit comments

Comments
 (0)