Skip to content

Commit b1cd4b0

Browse files
committed
bug symfony#42033 [HttpFoundation] Fix deleteFileAfterSend on client abortion (nerg4l)
This PR was squashed before being merged into the 4.4 branch. Discussion ---------- [HttpFoundation] Fix deleteFileAfterSend on client abortion | Q | A | ------------- | --- | Branch? | 4.4 | Bug fix? | yes | New feature? | no <!-- please update src/**/CHANGELOG.md files --> | Deprecations? | no <!-- please update UPGRADE-*.md and src/**/CHANGELOG.md files --> | Tickets | Fix symfony#27538 <!-- prefix each issue number with "Fix #", no need to create an issue if none exist, explain below instead --> | License | MIT | Doc PR | <!-- required for new features --> <!-- Replace this notice by a short README for your feature/bugfix. This will help people understand your PR and can be used as a start for the documentation. Additionally (see https://symfony.com/releases): - Always add tests and ensure they pass. - Never break backward compatibility (see https://symfony.com/bc). - Bug fixes must be submitted against the lowest maintained branch where they apply (lowest branches are regularly merged to upper ones so they get the fixes too.) - Features and deprecations must be submitted against branch 5.x. - Changelog entry should follow https://symfony.com/doc/current/contributing/code/conventions.html#writing-a-changelog-entry --> **Description** If someone sets `deleteFileAfterSend` to `true` for a `BinaryFileResponse` instance they expect the file to be deleted when the response finished. This is not the case when the response is cancelled because PHP won't continue running the code. `ignore_user_abort` can be used to allow it to finish but this means `stream_copy_to_stream` will also continue to run regardless of the abort. To fix this later problem it can be a solution to run the copy in a loop and detect the connect abort manually with `connection_aborted`. **Tests** I don't know how can I simulate connection abort in PHPUnit. I would appreciate if I could get some guidance if it is possible. **Todo** - [ ] add tests if connection abort can be simulated - [ ] gather feedback for my changes Commits ------- f097bef [HttpFoundation] Fix deleteFileAfterSend on client abortion
2 parents 43126b1 + f097bef commit b1cd4b0

File tree

1 file changed

+34
-1
lines changed

1 file changed

+34
-1
lines changed

src/Symfony/Component/HttpFoundation/BinaryFileResponse.php

Lines changed: 34 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ class BinaryFileResponse extends Response
3434
protected $offset = 0;
3535
protected $maxlen = -1;
3636
protected $deleteFileAfterSend = false;
37+
protected $chunkSize = 8 * 1024;
3738

3839
/**
3940
* @param \SplFileInfo|string $file The file to stream
@@ -124,6 +125,22 @@ public function getFile()
124125
return $this->file;
125126
}
126127

128+
/**
129+
* Sets the response stream chunk size.
130+
*
131+
* @return $this
132+
*/
133+
public function setChunkSize(int $chunkSize): self
134+
{
135+
if ($chunkSize < 1 || $chunkSize > \PHP_INT_MAX) {
136+
throw new \LogicException('The chunk size of a BinaryFileResponse cannot be less than 1 or greater than PHP_INT_MAX.');
137+
}
138+
139+
$this->chunkSize = $chunkSize;
140+
141+
return $this;
142+
}
143+
127144
/**
128145
* Automatically sets the Last-Modified header according the file modification date.
129146
*/
@@ -303,7 +320,23 @@ public function sendContent()
303320
$out = fopen('php://output', 'w');
304321
$file = fopen($this->file->getPathname(), 'r');
305322

306-
stream_copy_to_stream($file, $out, $this->maxlen, $this->offset);
323+
ignore_user_abort(true);
324+
325+
if (0 !== $this->offset) {
326+
fseek($file, $this->offset);
327+
}
328+
329+
$length = $this->maxlen;
330+
while ($length && !feof($file)) {
331+
$read = ($length > $this->chunkSize) ? $this->chunkSize : $length;
332+
$length -= $read;
333+
334+
stream_copy_to_stream($file, $out, $read);
335+
336+
if (connection_aborted()) {
337+
break;
338+
}
339+
}
307340

308341
fclose($out);
309342
fclose($file);

0 commit comments

Comments
 (0)