Skip to content

Commit 4d9f0f4

Browse files
committed
Added response test and did some sanitizing
1 parent 053227b commit 4d9f0f4

File tree

2 files changed

+36
-1
lines changed

2 files changed

+36
-1
lines changed

flight/net/Response.php

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -484,7 +484,7 @@ protected function processResponseCallbacks(): void
484484
* Downloads a file.
485485
*
486486
* @param string $filePath The path to the file to be downloaded.
487-
* @param string $fileName The name the downloaded file should have. If not provided, the name of the file on disk will be used.
487+
* @param string $fileName The name the downloaded file should have. If not provided or is an empty string, the name of the file on disk will be used.
488488
*
489489
* @throws Exception If the file cannot be found.
490490
*
@@ -501,6 +501,8 @@ public function downloadFile(string $filePath, string $fileName = ''): void
501501
$mimeType = mime_content_type($filePath);
502502
$mimeType = $mimeType !== false ? $mimeType : 'application/octet-stream';
503503

504+
// Sanitize filename to prevent header injection
505+
$fileName = str_replace(["\r", "\n", '"'], '', $fileName);
504506
if ($fileName === '') {
505507
$fileName = basename($filePath);
506508
}

tests/EngineTest.php

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1086,11 +1086,13 @@ public function getLoader()
10861086
// doing this so we can overwrite some parts of the response
10871087
$engine->getLoader()->register('response', function () {
10881088
return new class extends Response {
1089+
public $headersSent = [];
10891090
public function setRealHeader(
10901091
string $header_string,
10911092
bool $replace = true,
10921093
int $response_code = 0
10931094
): self {
1095+
$this->headersSent[] = $header_string;
10941096
return $this;
10951097
}
10961098
};
@@ -1100,6 +1102,37 @@ public function setRealHeader(
11001102
$streamPath = stream_get_meta_data($tmpfile)['uri'];
11011103
$this->expectOutputString('I am a teapot');
11021104
$engine->download($streamPath);
1105+
$this->assertContains('Content-Disposition: attachment; filename="'.basename($streamPath).'"', $engine->response()->headersSent);
1106+
}
1107+
1108+
public function testDownloadWithDefaultFileName(): void
1109+
{
1110+
$engine = new class extends Engine {
1111+
public function getLoader()
1112+
{
1113+
return $this->loader;
1114+
}
1115+
};
1116+
// doing this so we can overwrite some parts of the response
1117+
$engine->getLoader()->register('response', function () {
1118+
return new class extends Response {
1119+
public $headersSent = [];
1120+
public function setRealHeader(
1121+
string $header_string,
1122+
bool $replace = true,
1123+
int $response_code = 0
1124+
): self {
1125+
$this->headersSent[] = $header_string;
1126+
return $this;
1127+
}
1128+
};
1129+
});
1130+
$tmpfile = tmpfile();
1131+
fwrite($tmpfile, 'I am a teapot');
1132+
$streamPath = stream_get_meta_data($tmpfile)['uri'];
1133+
$this->expectOutputString('I am a teapot');
1134+
$engine->download($streamPath, 'something.txt');
1135+
$this->assertContains('Content-Disposition: attachment; filename="something.txt"', $engine->response()->headersSent);
11031136
}
11041137

11051138
public function testDownloadBadPath() {

0 commit comments

Comments
 (0)