From 21c40e5d013b8ef309cd8b408d171236d7c4960f Mon Sep 17 00:00:00 2001 From: ralf Date: Fri, 30 Jun 2023 17:13:42 +0200 Subject: [PATCH] WIP Mail REST API: do NOT read attachments into memory, they might be to big --- api/src/CalDAV.php | 20 +++++++++++++++++--- mail/src/ApiHandler.php | 7 +++++-- 2 files changed, 22 insertions(+), 5 deletions(-) diff --git a/api/src/CalDAV.php b/api/src/CalDAV.php index f8063a92bd..353edb9f51 100644 --- a/api/src/CalDAV.php +++ b/api/src/CalDAV.php @@ -1522,13 +1522,14 @@ class CalDAV extends HTTP_WebDAV_Server if (method_exists($handler, 'post')) { // read the content in a string, if a stream is given - if (isset($options['stream'])) + if (isset($options['stream']) && !self::isFileUpload()) { $options['content'] = ''; while(!feof($options['stream'])) { $options['content'] .= fread($options['stream'],8192); } + fseek($options['stream'], 0); } return $handler->post($options,$id,$user); } @@ -2331,8 +2332,8 @@ class CalDAV extends HTTP_WebDAV_Server { self::$request_starttime = microtime(true); // do NOT log non-text attachments - $this->store_request = $_SERVER['REQUEST_METHOD'] != 'POST' || !isset($_GET['action']) || - !in_array($_GET['action'], array('attachment-add', 'attachment-update')) || + $this->store_request = $_SERVER['REQUEST_METHOD'] != 'POST' || + !self::isFileUpload() || substr($_SERVER['CONTENT_TYPE'], 0, 5) == 'text/'; ob_start(); } @@ -2341,6 +2342,19 @@ class CalDAV extends HTTP_WebDAV_Server 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 * diff --git a/mail/src/ApiHandler.php b/mail/src/ApiHandler.php index 24bace43b7..e0c4a8fa84 100644 --- a/mail/src/ApiHandler.php +++ b/mail/src/ApiHandler.php @@ -58,7 +58,7 @@ class ApiHandler extends Api\CalDAV\Handler try { 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)) { @@ -146,8 +146,11 @@ class ApiHandler extends Api\CalDAV\Handler { $attachment_path = tempnam($GLOBALS['egw_info']['server']['temp_dir'], 'attach--'. (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))); echo json_encode([ 'status' => 200,