WIP Mail REST API: do NOT read attachments into memory, they might be to big

This commit is contained in:
ralf 2023-06-30 17:13:42 +02:00
parent 8a3fd670ee
commit 65b239ca2c
2 changed files with 22 additions and 5 deletions

View File

@ -1522,13 +1522,14 @@ class CalDAV extends HTTP_WebDAV_Server
if (method_exists($handler, 'post')) if (method_exists($handler, 'post'))
{ {
// read the content in a string, if a stream is given // read the content in a string, if a stream is given
if (isset($options['stream'])) if (isset($options['stream']) && !self::isFileUpload())
{ {
$options['content'] = ''; $options['content'] = '';
while(!feof($options['stream'])) while(!feof($options['stream']))
{ {
$options['content'] .= fread($options['stream'],8192); $options['content'] .= fread($options['stream'],8192);
} }
fseek($options['stream'], 0);
} }
return $handler->post($options,$id,$user); return $handler->post($options,$id,$user);
} }
@ -2331,8 +2332,8 @@ class CalDAV extends HTTP_WebDAV_Server
{ {
self::$request_starttime = microtime(true); self::$request_starttime = microtime(true);
// do NOT log non-text attachments // do NOT log non-text attachments
$this->store_request = $_SERVER['REQUEST_METHOD'] != 'POST' || !isset($_GET['action']) || $this->store_request = $_SERVER['REQUEST_METHOD'] != 'POST' ||
!in_array($_GET['action'], array('attachment-add', 'attachment-update')) || !self::isFileUpload() ||
substr($_SERVER['CONTENT_TYPE'], 0, 5) == 'text/'; substr($_SERVER['CONTENT_TYPE'], 0, 5) == 'text/';
ob_start(); ob_start();
} }
@ -2341,6 +2342,19 @@ class CalDAV extends HTTP_WebDAV_Server
if (self::$request_starttime) self::log_request(); if (self::$request_starttime) self::log_request();
} }
/**
* Check if request is a possibly large, binary file upload:
* - CalDAV managed attachments or
* - Mail REST API attachment upload
*
* @return bool
*/
protected static function isFileUpload()
{
return (isset($_GET['action']) && in_array($_GET['action'], array('attachment-add', 'attachment-update'))) ||
strpos($_SERVER['REQUEST_URI'], '/mail/attachments/');
}
/** /**
* Sanitizing filename to gard agains path traversal and / eg. in UserAgent string * Sanitizing filename to gard agains path traversal and / eg. in UserAgent string
* *

View File

@ -58,7 +58,7 @@ class ApiHandler extends Api\CalDAV\Handler
try { try {
if (str_starts_with($path, '/mail/attachments/')) if (str_starts_with($path, '/mail/attachments/'))
{ {
return self::storeAttachment($path, $options['content']); return self::storeAttachment($path, $options['stream'] ?? $options['content']);
} }
elseif (preg_match('#^/mail(/(\d+))?(/compose)?#', $path, $matches)) elseif (preg_match('#^/mail(/(\d+))?(/compose)?#', $path, $matches))
{ {
@ -146,8 +146,11 @@ class ApiHandler extends Api\CalDAV\Handler
{ {
$attachment_path = tempnam($GLOBALS['egw_info']['server']['temp_dir'], 'attach--'. $attachment_path = tempnam($GLOBALS['egw_info']['server']['temp_dir'], 'attach--'.
(str_replace('/', '-', substr($path, 18)) ?: 'no-name').'--'); (str_replace('/', '-', substr($path, 18)) ?: 'no-name').'--');
if (file_put_contents($attachment_path, $content)) if (is_resource($content) ?
stream_copy_to_stream($content, $fp=fopen($attachment_path, 'w')) :
file_put_contents($attachment_path, $content))
{ {
if (isset($fp)) fclose($fp);
header('Location: '.($location = '/mail/attachments/'.substr(basename($attachment_path), 8))); header('Location: '.($location = '/mail/attachments/'.substr(basename($attachment_path), 8)));
echo json_encode([ echo json_encode([
'status' => 200, 'status' => 200,