chg: [internal] Slightly optimise CakeResponseTmp

pull/7975/head
Jakub Onderka 2021-11-21 11:13:12 +01:00
parent 458e900a73
commit c2bdf167a6
4 changed files with 133 additions and 56 deletions

View File

@ -315,28 +315,27 @@ class AttributesController extends AppController
if (empty($attributes)) {
throw new UnauthorizedException(__('Attribute does not exists or you do not have the permission to download this attribute.'));
}
$this->__downloadAttachment($attributes[0]['Attribute']);
return $this->__downloadAttachment($attributes[0]['Attribute']);
}
private function __downloadAttachment($attribute)
private function __downloadAttachment(array $attribute)
{
$file = $this->Attribute->getAttachmentFile($attribute);
if ('attachment' == $attribute['type']) {
if ('attachment' === $attribute['type']) {
$filename = $attribute['value'];
$fileExt = pathinfo($filename, PATHINFO_EXTENSION);
$filename = substr($filename, 0, strlen($filename) - strlen($fileExt) - 1);
} elseif ('malware-sample' == $attribute['type']) {
} elseif ('malware-sample' === $attribute['type']) {
$filenameHash = explode('|', $attribute['value']);
$filename = substr($filenameHash[0], strrpos($filenameHash[0], '\\'));
$fileExt = "zip";
} else {
throw new NotFoundException(__('Attribute not an attachment or malware-sample'));
}
$this->autoRender = false;
$this->response->type($fileExt);
$download_attachments_on_load = Configure::check('MISP.download_attachments_on_load') ? Configure::read('MISP.download_attachments_on_load') : true;
$this->response->file($file->path, array('download' => $download_attachments_on_load, 'name' => $filename . '.' . $fileExt));
return $this->RestResponse->sendFile($file, $fileExt, $download_attachments_on_load, $filename . '.' . $fileExt);
}
public function add_attachment($eventId = null)
@ -1762,7 +1761,7 @@ class AttributesController extends AppController
if (empty($attributes)) {
throw new UnauthorizedException(__('Attribute does not exists or you do not have the permission to download this attribute.'));
}
$this->__downloadAttachment($attributes[0]['Attribute']);
return $this->__downloadAttachment($attributes[0]['Attribute']);
}
// returns an XML with attributes that belong to an event. The type of attributes to be returned can be restricted by type using the 3rd parameter.

View File

@ -590,8 +590,8 @@ class RestResponseComponent extends Component
}
if ($response instanceof TmpFileTool) {
App::uses('CakeResponseTmp', 'Tools');
$cakeResponse = new CakeResponseTmp(['status' => $code, 'type' => $type]);
App::uses('CakeResponseFile', 'Tools');
$cakeResponse = new CakeResponseFile(['status' => $code, 'type' => $type]);
$cakeResponse->file($response);
} else {
$cakeResponse = new CakeResponse(array('body' => $response, 'status' => $code, 'type' => $type));
@ -655,13 +655,24 @@ class RestResponseComponent extends Component
return $this->__sendResponse($data, 200, $format, $raw, $download, $headers);
}
public function sendFile($path, $format = false, $download = false, $name = 'download')
/**
* @param string|File|TmpFileTool $path
* @param string|null $type
* @param bool $download
* @param string $name
* @return CakeResponseFile
* @throws Exception
*/
public function sendFile($path, $type = null, $download = false, $name = 'download')
{
$cakeResponse = new CakeResponse(array(
'status' => 200,
'type' => $format
));
$cakeResponse->file($path, array('name' => $name, 'download' => true));
App::uses('CakeResponseFile', 'Tools');
$cakeResponse = new CakeResponseFile([
'type' => $type
]);
$cakeResponse->file($path, ['name' => $name, 'download' => $download]);
if (Configure::read('Security.disable_browser_cache')) {
$cakeResponse->disableCache();
}
return $cakeResponse;
}

View File

@ -0,0 +1,107 @@
<?php
class CakeResponseFile extends CakeResponse
{
/**
* Modified version that supports also TmpFileTool and File
*
* @param string|TmpFileTool|File $path
* @param array $options
* @throws Exception
*/
public function file($path, $options = array())
{
if ($path instanceof TmpFileTool) {
$this->header('Content-Length', $path->size());
$this->_clearBuffer();
$this->_file = $path;
} else if ($path instanceof File) {
$options += array(
'name' => null,
'download' => null
);
if ($options['download']) {
$name = $options['name'] === null ? $path->name : $options['name'];
$this->download($name);
$this->header('Content-Transfer-Encoding', 'binary');
}
$this->header('Accept-Ranges', 'bytes');
$httpRange = env('HTTP_RANGE');
if (isset($httpRange)) {
$this->_fileRange($path, $httpRange);
} else {
$this->header('Content-Length', filesize($path->path));
}
$this->_clearBuffer();
$this->_file = $path;
} else {
parent::file($path, $options);
}
}
/**
* This method supports TmpFileTool and also provides optimised variant for sending file from `File` object
* @param File|TmpFileTool $file
* @param array $range
* @return bool
* @throws Exception
*/
protected function _sendFile($file, $range)
{
set_time_limit(0);
session_write_close();
if ($file instanceof TmpFileTool) {
foreach ($file->intoChunks() as $chunk) {
if (!$this->_isActive()) {
$file->close();
return false;
}
echo $chunk;
}
} else {
$handler = fopen($file->path, 'rb');
if ($handler === false) {
throw new Exception("File $file->path doesn't exists anymore or is not readable.");
}
$end = $start = false;
if ($range && is_array($range)) {
list($start, $end) = $range;
}
if ($start !== false) {
fseek($handler, $start);
}
$bufferSize = 8192;
while (!feof($handler)) {
if (!$this->_isActive()) {
$file->close();
return false;
}
$offset = ftell($handler);
if ($end && $offset >= $end) {
break;
}
if ($end && $offset + $bufferSize >= $end) {
$bufferSize = $end - $offset + 1;
}
echo fread($handler, $bufferSize);
}
fclose($handler);
}
$this->_flushBuffer();
return true;
}
/**
* Faster version that do not do redundant check
* @return bool
*/
protected function _isActive()
{
return connection_status() === CONNECTION_NORMAL;
}
}

View File

@ -1,40 +0,0 @@
<?php
class CakeResponseTmp extends CakeResponse
{
public function file($path, $options = array())
{
if ($path instanceof TmpFileTool) {
$this->header('Content-Length', $path->size());
$this->_clearBuffer();
$this->_file = $path;
} else {
parent::file($path, $options);
}
}
/**
* @param File|TmpFileTool $file
* @param array $range
* @return bool
* @throws Exception
*/
protected function _sendFile($file, $range)
{
if ($file instanceof TmpFileTool) {
set_time_limit(0);
session_write_close();
foreach ($file->intoChunks() as $chunk) {
if (!$this->_isActive()) {
$file->close();
return false;
}
echo $chunk;
$this->_flushBuffer();
}
return true;
} else {
return parent::_sendFile($file, $range);
}
}
}