From b73158d3d0f03b977a0399d495edfb263d4cc3ef Mon Sep 17 00:00:00 2001 From: Matteo Scaramuccia Date: Sun, 9 Nov 2014 08:06:46 +0100 Subject: [PATCH] MDL-48023 Files API: Theme files must be cache-able by shared proxies. The profile image AKA user icon will be cache-able by shared proxies too, under its specific accessibility constraints/conditions. --- lib/filelib.php | 34 +++++++++++++++++++++++++--------- lib/outputlib.php | 4 ++++ theme/clean/lib.php | 4 ++++ theme/more/lib.php | 4 ++++ 4 files changed, 37 insertions(+), 9 deletions(-) diff --git a/lib/filelib.php b/lib/filelib.php index 0d3ba4db597..62c56621c20 100644 --- a/lib/filelib.php +++ b/lib/filelib.php @@ -2288,12 +2288,13 @@ function send_file($path, $filename, $lifetime = null , $filter=0, $pathisstring } if ($lifetime > 0) { - $private = ''; + $cacheability = ' public,'; if (isloggedin() and !isguestuser()) { - $private = ' private,'; + // By default, under the conditions above, this file must be cache-able only by browsers. + $cacheability = ' private,'; } $nobyteserving = false; - header('Cache-Control:'.$private.' max-age='.$lifetime.', no-transform'); + header('Cache-Control:'.$cacheability.' max-age='.$lifetime.', no-transform'); header('Expires: '. gmdate('D, d M Y H:i:s', time() + $lifetime) .' GMT'); header('Pragma: '); @@ -2366,7 +2367,10 @@ function send_file($path, $filename, $lifetime = null , $filter=0, $pathisstring * (bool) dontdie - return control to caller afterwards. this is not recommended and only used for cleanup tasks. * if this is passed as true, ignore_user_abort is called. if you don't want your processing to continue on cancel, * you must detect this case when control is returned using connection_aborted. Please not that session is closed - * and should not be reopened. + * and should not be reopened + * (string|null) cacheability - force the cacheability setting of the HTTP response, "private" or "public", + * when $lifetime is greater than 0. Cacheability defaults to "private" when logged in as other than guest; otherwise, + * defaults to "public". * * @category files * @param stored_file $stored_file local file object @@ -2463,11 +2467,17 @@ function send_stored_file($stored_file, $lifetime=null, $filter=0, $forcedownloa } if ($lifetime > 0) { - $private = ''; - if (isloggedin() and !isguestuser()) { - $private = ' private,'; + $cacheability = ' public,'; + if (!empty($options['cacheability']) && ($options['cacheability'] === 'public')) { + // This file must be cache-able by both browsers and proxies. + $cacheability = ' public,'; + } else if (!empty($options['cacheability']) && ($options['cacheability'] === 'private')) { + // This file must be cache-able only by browsers. + $cacheability = ' private,'; + } else if (isloggedin() and !isguestuser()) { + $cacheability = ' private,'; } - header('Cache-Control:'.$private.' max-age='.$lifetime.', no-transform'); + header('Cache-Control:'.$cacheability.' max-age='.$lifetime.', no-transform'); header('Expires: '. gmdate('D, d M Y H:i:s', time() + $lifetime) .' GMT'); header('Pragma: '); @@ -4177,7 +4187,13 @@ function file_pluginfile($relativepath, $forcedownload, $preview = null) { send_file($imagefile, basename($imagefile), 60*60*24*14); } - send_stored_file($file, 60*60*24*365, 0, false, array('preview' => $preview)); // enable long caching, there are many images on each page + $options = array('preview' => $preview); + if (empty($CFG->forcelogin) && empty($CFG->forceloginforprofileimage)) { + // Profile images should be cache-able by both browsers and proxies according + // to $CFG->forcelogin and $CFG->forceloginforprofileimage. + $options['cacheability'] = 'public'; + } + send_stored_file($file, 60*60*24*365, 0, false, $options); // enable long caching, there are many images on each page } else if ($filearea === 'private' and $context->contextlevel == CONTEXT_USER) { require_login(); diff --git a/lib/outputlib.php b/lib/outputlib.php index 6ff4db7d2a0..844df550e13 100644 --- a/lib/outputlib.php +++ b/lib/outputlib.php @@ -1475,6 +1475,10 @@ class theme_config { $lifetime = 0; } else { $lifetime = 60*60*24*60; + // By default, theme files must be cache-able by both browsers and proxies. + if (!array_key_exists('cacheability', $options)) { + $options['cacheability'] = 'public'; + } } $fs = get_file_storage(); diff --git a/theme/clean/lib.php b/theme/clean/lib.php index b1904800126..7d2368698e3 100644 --- a/theme/clean/lib.php +++ b/theme/clean/lib.php @@ -88,6 +88,10 @@ function theme_clean_set_logo($css, $logo) { function theme_clean_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload, array $options = array()) { if ($context->contextlevel == CONTEXT_SYSTEM and $filearea === 'logo') { $theme = theme_config::load('clean'); + // By default, theme files must be cache-able by both browsers and proxies. + if (!array_key_exists('cacheability', $options)) { + $options['cacheability'] = 'public'; + } return $theme->setting_file_serve('logo', $args, $forcedownload, $options); } else { send_file_not_found(); diff --git a/theme/more/lib.php b/theme/more/lib.php index bd5e91db1df..0e8017f9f7a 100644 --- a/theme/more/lib.php +++ b/theme/more/lib.php @@ -149,6 +149,10 @@ function theme_more_set_logo($css, $logo) { function theme_more_pluginfile($course, $cm, $context, $filearea, $args, $forcedownload, array $options = array()) { if ($context->contextlevel == CONTEXT_SYSTEM && ($filearea === 'logo' || $filearea === 'backgroundimage')) { $theme = theme_config::load('more'); + // By default, theme files must be cache-able by both browsers and proxies. + if (!array_key_exists('cacheability', $options)) { + $options['cacheability'] = 'public'; + } return $theme->setting_file_serve($filearea, $args, $forcedownload, $options); } else { send_file_not_found();