X-Git-Url: https://git.mxchange.org/?a=blobdiff_plain;f=src%2FModule%2FProxy.php;h=419289c39f6e2927b57871c20abec77e89d39880;hb=6dbbd081795fa1c8fe57db2248ac162efeeada88;hp=2b8ad01ddadfd9cd89346ceec962350850845ff5;hpb=b543ee8ac78168328c7a7f2d725ee01bb333e941;p=friendica.git diff --git a/src/Module/Proxy.php b/src/Module/Proxy.php index 2b8ad01dda..419289c39f 100644 --- a/src/Module/Proxy.php +++ b/src/Module/Proxy.php @@ -1,21 +1,38 @@ + * @copyright Copyright (C) 2010-2022, the Friendica project + * + * @license GNU AGPL version 3 or any later version + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU Affero General Public License as + * published by the Free Software Foundation, either version 3 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Affero General Public License for more details. + * + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . + * */ + namespace Friendica\Module; use Friendica\BaseModule; -use Friendica\Core\L10n; -use Friendica\Core\System; use Friendica\Core\Logger; -use Friendica\Model\Photo; +use Friendica\Core\System; +use Friendica\DI; +use Friendica\Network\HTTPException\NotModifiedException; use Friendica\Object\Image; use Friendica\Util\HTTPSignature; +use Friendica\Util\Images; use Friendica\Util\Proxy as ProxyUtils; /** - * @brief Module Proxy + * Module Proxy * * urls: * /proxy/[sub1/[sub2/]][.ext][:size] @@ -25,84 +42,55 @@ class Proxy extends BaseModule { /** - * @brief Initializer method for this class. - * - * Sets application instance and checks if /proxy/ path is writable. - * + * Fetch remote image content */ - public static function init() + protected function rawContent(array $request = []) { - // Set application instance here - $a = self::getApp(); - - /* - * Pictures are stored in one of the following ways: - * - * 1. If a folder "proxy" exists and is writeable, then use this for caching - * 2. If a cache path is defined, use this - * 3. If everything else failed, cache into the database - * - * Question: Do we really need these three methods? - */ - if (isset($_SERVER['HTTP_IF_MODIFIED_SINCE']) && isset($_SERVER['HTTP_IF_NONE_MATCH'])) { - header('HTTP/1.1 304 Not Modified'); - header('Last-Modified: ' . gmdate('D, d M Y H:i:s', time()) . ' GMT'); - header('Etag: ' . $_SERVER['HTTP_IF_NONE_MATCH']); - header('Expires: ' . gmdate('D, d M Y H:i:s', time() + (31536000)) . ' GMT'); - header('Cache-Control: max-age=31536000'); + $request = $this->getRequestInfo(); - if (function_exists('header_remove')) { - header_remove('Last-Modified'); - header_remove('Expires'); - header_remove('Cache-Control'); - } - - /// @TODO Stop here? - exit(); + if (!DI::config()->get('system', 'proxify_content')) { + Logger::notice('Proxy access is forbidden', ['request' => $request, 'agent' => $_SERVER['HTTP_USER_AGENT'] ?? '', 'accept' => $_SERVER['HTTP_ACCEPT'] ?? '']); + throw new \Friendica\Network\HTTPException\NotFoundException(); } - if (function_exists('header_remove')) { - header_remove('Pragma'); - header_remove('pragma'); + if (isset($_SERVER["HTTP_IF_MODIFIED_SINCE"])) { + header("Last-Modified: " . gmdate("D, d M Y H:i:s", time()) . " GMT"); + if (!empty($_SERVER["HTTP_IF_NONE_MATCH"])) { + header("Etag: " . $_SERVER["HTTP_IF_NONE_MATCH"]); + } + header("Expires: " . gmdate("D, d M Y H:i:s", time() + (31536000)) . " GMT"); + header("Cache-Control: max-age=31536000"); + if (function_exists("header_remove")) { + header_remove("Last-Modified"); + header_remove("Expires"); + header_remove("Cache-Control"); + } + throw new NotModifiedException(); } - $direct_cache = self::setupDirectCache(); - - $request = self::getRequestInfo(); - if (empty($request['url'])) { throw new \Friendica\Network\HTTPException\BadRequestException(); } - // Webserver already tried direct cache... - - // Try to use filecache; - $cachefile = self::responseFromCache($request); - - // Try to use photo from db - self::responseFromDB($request); - - // - // If script is here, the requested url has never cached before. - // Let's fetch it, scale it if required, then save it in cache. - // + if (!local_user()) { + Logger::info('Redirecting not logged in user to original address', ['url' => $request['url']]); + System::externalRedirect($request['url']); + } // It shouldn't happen but it does - spaces in URL $request['url'] = str_replace(' ', '+', $request['url']); - $fetchResult = HTTPSignature::fetchRaw($request['url'], local_user(), true, ['timeout' => 10]); + + // Fetch the content with the local user + $fetchResult = HTTPSignature::fetchRaw($request['url'], local_user(), ['accept_content' => [], 'timeout' => 10]); $img_str = $fetchResult->getBody(); - // If there is an error then return a blank image - if ((substr($fetchResult->getReturnCode(), 0, 1) == '4') || empty($img_str)) { + if (!$fetchResult->isSuccess() || empty($img_str)) { Logger::info('Error fetching image', ['image' => $request['url'], 'return' => $fetchResult->getReturnCode(), 'empty' => empty($img_str)]); self::responseError(); // stop. } - $tempfile = tempnam(get_temppath(), 'cache'); - file_put_contents($tempfile, $img_str); - $mime = mime_content_type($tempfile); - unlink($tempfile); + $mime = Images::getMimeTypeByData($img_str); $image = new Image($img_str, $mime); if (!$image->isValid()) { @@ -111,91 +99,53 @@ class Proxy extends BaseModule // stop. } - $basepath = $a->getBasePath(); - - // Store original image - if ($direct_cache) { - // direct cache , store under ./proxy/ - file_put_contents($basepath . '/proxy/' . ProxyUtils::proxifyUrl($request['url'], true), $image->asString()); - } elseif($cachefile !== '') { - // cache file - file_put_contents($cachefile, $image->asString()); - } else { - // database - Photo::store($image, 0, 0, $request['urlhash'], $request['url'], '', 100); - } - - // reduce quality - if it isn't a GIF if ($image->getType() != 'image/gif') { $image->scaleDown($request['size']); } - - // Store scaled image - if ($direct_cache && $request['sizetype'] != '') { - file_put_contents($basepath . '/proxy/' . ProxyUtils::proxifyUrl($request['url'], true) . $request['sizetype'], $image->asString()); - } - self::responseImageHttpCache($image); // stop. } - /** - * @brief Build info about requested image to be proxied + * Build info about requested image to be proxied * * @return array * [ * 'url' => requested url, - * 'urlhash' => sha1 has of the url prefixed with 'pic:', * 'size' => requested image size (int) * 'sizetype' => requested image size (string): ':micro', ':thumb', ':small', ':medium', ':large' * ] * @throws \Exception */ - private static function getRequestInfo() + private function getRequestInfo() { - $a = self::getApp(); - $size = 1024; + $size = ProxyUtils::PIXEL_LARGE; $sizetype = ''; - // Look for filename in the arguments - // @TODO: Replace with parameter from router - if (($a->argc > 1) && !isset($_REQUEST['url'])) { - if (isset($a->argv[3])) { - $url = $a->argv[3]; - } elseif (isset($a->argv[2])) { - $url = $a->argv[2]; - } else { - $url = $a->argv[1]; - } - - /// @TODO: Why? And what about $url in this case? - /// @TODO: Replace with parameter from router - if (isset($a->argv[3]) && ($a->argv[3] == 'thumb')) { - $size = 200; - } + if (!empty($this->parameters['url']) && empty($_REQUEST['url'])) { + $url = $this->parameters['url']; // thumb, small, medium and large. if (substr($url, -6) == ':micro') { - $size = 48; + $size = ProxyUtils::PIXEL_MICRO; $sizetype = ':micro'; $url = substr($url, 0, -6); } elseif (substr($url, -6) == ':thumb') { - $size = 80; + $size = ProxyUtils::PIXEL_THUMB; $sizetype = ':thumb'; $url = substr($url, 0, -6); } elseif (substr($url, -6) == ':small') { - $size = 300; + $size = ProxyUtils::PIXEL_SMALL; $url = substr($url, 0, -6); $sizetype = ':small'; } elseif (substr($url, -7) == ':medium') { - $size = 600; + $size = ProxyUtils::PIXEL_MEDIUM; $url = substr($url, 0, -7); $sizetype = ':medium'; } elseif (substr($url, -6) == ':large') { - $size = 1024; + $size = ProxyUtils::PIXEL_LARGE; $url = substr($url, 0, -6); $sizetype = ':large'; } @@ -208,87 +158,17 @@ class Proxy extends BaseModule $url = str_replace(['.jpg', '.jpeg', '.gif', '.png'], ['','','',''], $url); $url = base64_decode(strtr($url, '-_', '+/'), true); - } else { $url = $_REQUEST['url'] ?? ''; } return [ 'url' => $url, - 'urlhash' => 'pic:' . sha1($url), 'size' => $size, 'sizetype' => $sizetype, ]; } - - /** - * @brief setup ./proxy folder for direct cache - * - * @return bool False if direct cache can't be used. - * @throws \Friendica\Network\HTTPException\InternalServerErrorException - */ - private static function setupDirectCache() - { - $a = self::getApp(); - $basepath = $a->getBasePath(); - - // If the cache path isn't there, try to create it - if (!is_dir($basepath . '/proxy') && is_writable($basepath)) { - mkdir($basepath . '/proxy'); - } - - // Checking if caching into a folder in the webroot is activated and working - $direct_cache = (is_dir($basepath . '/proxy') && is_writable($basepath . '/proxy')); - // we don't use direct cache if image url is passed in args and not in querystring - $direct_cache = $direct_cache && ($a->argc > 1) && !isset($_REQUEST['url']); - - return $direct_cache; - } - - - /** - * @brief Try to reply with image in cachefile - * - * @param array $request Array from getRequestInfo - * - * @return string Cache file name, empty string if cache is not enabled. - * - * If cachefile exists, script ends here and this function will never returns - * @throws \Friendica\Network\HTTPException\InternalServerErrorException - * @throws \ImagickException - */ - private static function responseFromCache(&$request) - { - $cachefile = get_cachefile(hash('md5', $request['url'])); - if ($cachefile != '' && file_exists($cachefile)) { - $img = new Image(file_get_contents($cachefile), mime_content_type($cachefile)); - self::responseImageHttpCache($img); - // stop. - } - return $cachefile; - } - - /** - * @brief Try to reply with image in database - * - * @param array $request Array from getRequestInfo - * - * If the image exists in database, then script ends here and this function will never returns - * @throws \Friendica\Network\HTTPException\InternalServerErrorException - * @throws \ImagickException - */ - private static function responseFromDB(&$request) - { - $photo = Photo::getPhoto($request['urlhash']); - - if ($photo !== false) { - $img = Photo::getImageForPhoto($photo); - self::responseImageHttpCache($img); - // stop. - } - } - /** * In case of an error just stop. We don't return content to avoid caching problems * @@ -300,7 +180,7 @@ class Proxy extends BaseModule } /** - * @brief Output the image with cache headers + * Output the image with cache headers * * @param Image $img * @throws \Friendica\Network\HTTPException\InternalServerErrorException