From 7643f3cf7b5d59f7b42d60ffd8ef607d5a55ffdf Mon Sep 17 00:00:00 2001 From: Miguel Dantas Date: Wed, 26 Jun 2019 03:39:39 +0100 Subject: [PATCH] [CORE][ACTION] Removed getfile action. Superseded by attachment/*/download, which additionally uses a file hash as oposed to a filename. Additionally, added etag and last modified HTTP headers to attachments, to more effectively take advantage of caching --- README.md | 2 +- actions/attachment.php | 48 ++++++++- actions/attachment_thumbnail.php | 50 +++++----- actions/getfile.php | 164 ------------------------------- lib/framework.php | 2 +- lib/router.php | 4 - 6 files changed, 71 insertions(+), 199 deletions(-) delete mode 100644 actions/getfile.php diff --git a/README.md b/README.md index 290c9eed34..369dbfbd9b 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# GNU social 1.25.x +# GNU social 1.26.x (c) 2010-2019 Free Software Foundation, Inc This is the README file for GNU social, the free diff --git a/actions/attachment.php b/actions/attachment.php index 5fe801ad31..2a967c72b7 100644 --- a/actions/attachment.php +++ b/actions/attachment.php @@ -60,7 +60,7 @@ class AttachmentAction extends ManagedAction parent::prepare($args); if (!empty($id = $this->trimmed('attachment'))) { - $this->attachment = File::getKV($id); + $this->attachment = File::getByID($id); } elseif (!empty($filehash = $this->trimmed('filehash'))) { $this->attachment = File::getByHash($filehash); } @@ -135,6 +135,52 @@ class AttachmentAction extends ManagedAction $ns->show(); } + /** + * Last-modified date for file + * + * @return int last-modified date as unix timestamp + */ + public function lastModified() + { + if (common_config('site', 'use_x_sendfile')) { + return null; + } + + return filemtime($this->attachment->getPath()); + } + + /** + * etag header for file + * + * This returns the same data (inode, size, mtime) as Apache would, + * but in decimal instead of hex. + * + * @return string etag http header + */ + function etag() + { + if (common_config('site', 'use_x_sendfile')) { + return null; + } + + $cache = Cache::instance(); + if($cache) { + $key = Cache::key('attachments:etag:' . $this->attachment->getPath()); + $etag = $cache->get($key); + if($etag === false) { + $etag = crc32(file_get_contents($this->attachment->getPath())); + $cache->set($key,$etag); + } + return $etag; + } + + $stat = stat($this->path); + return '"' . $stat['ino'] . '-' . $stat['size'] . '-' . $stat['mtime'] . '"'; + } + + /** + * Include $this as a file read from $filepath, for viewing and downloading + */ public function sendFile(string $filepath) { if (common_config('site', 'use_x_sendfile')) { header('X-Sendfile: ' . $filepath); diff --git a/actions/attachment_thumbnail.php b/actions/attachment_thumbnail.php index 577505c8e1..85ffb7e5df 100644 --- a/actions/attachment_thumbnail.php +++ b/actions/attachment_thumbnail.php @@ -63,38 +63,32 @@ class Attachment_thumbnailAction extends AttachmentAction $file = $e->file; } - if (!$file->isLocal()) { - // Not locally stored, redirect to the URL the file came from - // Don't use getURL because it can give us a local URL, which we don't want - common_redirect($file->url, 302); - } else { - $filepath = $this->attachment->getPath(); - $filename = MediaFile::getDisplayName($file); + $filepath = $this->attachment->getPath(); + $filename = MediaFile::getDisplayName($file); - // Disable errors, to not mess with the file contents (suppress errors in case access to this - // function is blocked, like in some shared hosts). Automatically reset at the end of the - // script execution, and we don't want to have any more errors until then, so don't reset it - @ini_set('display_errors', 0); + // Disable errors, to not mess with the file contents (suppress errors in case access to this + // function is blocked, like in some shared hosts). Automatically reset at the end of the + // script execution, and we don't want to have any more errors until then, so don't reset it + @ini_set('display_errors', 0); - header("Content-Description: File Transfer"); - header("Content-Type: {$file->mimetype}"); - header("Content-Disposition: inline; filename=\"{$filename}\""); - header('Expires: 0'); - header('Content-Transfer-Encoding: binary'); - $filesize = $this->file->size; - // 'if available', it says, so ensure we have it - if (empty($filesize)) { - $filesize = filesize($this->attachment->filename); - } - header("Content-Length: {$filesize}"); - // header('Cache-Control: private, no-transform, no-store, must-revalidate'); + header("Content-Description: File Transfer"); + header("Content-Type: {$file->mimetype}"); + header("Content-Disposition: inline; filename=\"{$filename}\""); + header('Expires: 0'); + header('Content-Transfer-Encoding: binary'); + $filesize = $this->file->size; + // 'if available', it says, so ensure we have it + if (empty($filesize)) { + $filesize = filesize($this->attachment->filename); + } + header("Content-Length: {$filesize}"); + // header('Cache-Control: private, no-transform, no-store, must-revalidate'); - $ret = @readfile($filepath); + $ret = @readfile($filepath); - if ($ret === false || $ret !== $filesize) { - common_log(LOG_ERR, "The lengths of the file as recorded on the DB (or on disk) for the file " . - "{$filepath}, with id={$this->attachment->id} differ from what was sent to the user."); - } + if ($ret === false || $ret !== $filesize) { + common_log(LOG_ERR, "The lengths of the file as recorded on the DB (or on disk) for the file " . + "{$filepath}, with id={$this->attachment->id} differ from what was sent to the user."); } } } diff --git a/actions/getfile.php b/actions/getfile.php deleted file mode 100644 index f0c98f7416..0000000000 --- a/actions/getfile.php +++ /dev/null @@ -1,164 +0,0 @@ -. - * - * @category PrivateAttachments - * @package StatusNet - * @author Jeffery To - * @copyright 2009 StatusNet, Inc. - * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 - * @link http://status.net/ - */ - -if (!defined('GNUSOCIAL')) { exit(1); } - -/** - * An action for returning a requested file - * - * The StatusNet system will do an implicit user check if the site is - * private before allowing this to continue - * - * @category PrivateAttachments - * @package StatusNet - * @author Jeffery To - * @copyright 2009 StatusNet, Inc. - * @license http://www.fsf.org/licensing/licenses/agpl-3.0.html AGPL 3.0 - * @link http://status.net/ - */ -class GetfileAction extends Action -{ - /** - * Path of file to return - */ - var $path = null; - - /** - * Get file name - * - * @param array $args $_REQUEST array - * - * @return success flag - */ - protected function prepare(array $args=array()) - { - parent::prepare($args); - - $filename = $this->trimmed('filename'); - $path = null; - - if ($filename && File::validFilename($filename)) { - $path = File::path($filename); - } - - if (empty($path) or !file_exists($path)) { - // TRANS: Client error displayed when requesting a non-existent file. - $this->clientError(_('No such file.'), 404); - } - if (!is_readable($path)) { - // TRANS: Client error displayed when requesting a file without having read access to it. - $this->clientError(_('Cannot read file.'), 403); - } - - $this->path = $path; - return true; - } - - /** - * Is this page read-only? - * - * @return boolean true - */ - function isReadOnly($args) - { - return true; - } - - /** - * Last-modified date for file - * - * @return int last-modified date as unix timestamp - */ - function lastModified() - { - if (common_config('site', 'use_x_sendfile')) { - return null; - } - - return filemtime($this->path); - } - - /** - * etag for file - * - * This returns the same data (inode, size, mtime) as Apache would, - * but in decimal instead of hex. - * - * @return string etag http header - */ - function etag() - { - if (common_config('site', 'use_x_sendfile')) { - return null; - } - - $cache = Cache::instance(); - if($cache) { - $key = Cache::key('attachments:etag:' . $this->path); - $etag = $cache->get($key); - if($etag === false) { - $etag = crc32(file_get_contents($this->path)); - $cache->set($key,$etag); - } - return $etag; - } - - $stat = stat($this->path); - return '"' . $stat['ino'] . '-' . $stat['size'] . '-' . $stat['mtime'] . '"'; - } - - /** - * Handle input, produce output - * - * @return void - */ - protected function handle() - { - // undo headers set by PHP sessions - $sec = session_cache_expire() * 60; - header('Expires: ' . date(DATE_RFC1123, time() + $sec)); - header('Cache-Control: max-age=' . $sec); - - parent::handle(); - - $path = $this->path; - - $finfo = new finfo(FILEINFO_MIME_TYPE); - - header('Content-Type: ' . $finfo->file($path)); - - if (common_config('site', 'use_x_sendfile')) { - header('X-Sendfile: ' . $path); - } else { - header('Content-Length: ' . filesize($path)); - readfile($path); - } - } -} diff --git a/lib/framework.php b/lib/framework.php index c42ccbda04..f7d93ee923 100644 --- a/lib/framework.php +++ b/lib/framework.php @@ -32,7 +32,7 @@ defined('GNUSOCIAL') || die(); define('GNUSOCIAL_ENGINE', 'GNU social'); define('GNUSOCIAL_ENGINE_URL', 'https://www.gnu.org/software/social/'); -define('GNUSOCIAL_BASE_VERSION', '1.25.0'); +define('GNUSOCIAL_BASE_VERSION', '1.26.0'); define('GNUSOCIAL_LIFECYCLE', 'dev'); // 'dev', 'alpha[0-9]+', 'beta[0-9]+', 'rc[0-9]+', 'release' define('GNUSOCIAL_VERSION', GNUSOCIAL_BASE_VERSION . '-' . GNUSOCIAL_LIFECYCLE); diff --git a/lib/router.php b/lib/router.php index 8b6e7b01f5..d6f63ab026 100644 --- a/lib/router.php +++ b/lib/router.php @@ -802,10 +802,6 @@ class Router array('action' => 'plugindisable'), array('plugin' => '[A-Za-z0-9_]+')); - $m->connect('getfile/:filename', - array('action' => 'getfile'), - array('filename' => '[A-Za-z0-9._-]+')); - // Common people-tag stuff $m->connect('peopletag/:tag', array('action' => 'peopletag', -- 2.39.5