diff --git a/_test/conf/acl.auth.php b/_test/conf/acl.auth.php index 8a1b01f23f1cebb240c74a7751f731a64fa96595..49574072002f6c3ce960f309a0b1b398e550a9a9 100644 --- a/_test/conf/acl.auth.php +++ b/_test/conf/acl.auth.php @@ -19,6 +19,7 @@ # delete 16 * @ALL 8 +private:* @ALL 0 # for testing wildcards: users:* @ALL 1 diff --git a/_test/tests/inc/media_ispublic.test.php b/_test/tests/inc/media_ispublic.test.php new file mode 100644 index 0000000000000000000000000000000000000000..307c64654154c32e7ddf900c373fa0567dc1f12b --- /dev/null +++ b/_test/tests/inc/media_ispublic.test.php @@ -0,0 +1,18 @@ +<?php + +class media_ispublic_test extends DokuWikiTest { + + + public function test_external(){ + $this->assertTrue(media_ispublic('http://www.example.com/foo.png')); + $this->assertTrue(media_ispublic('https://www.example.com/foo.png')); + $this->assertTrue(media_ispublic('hTTp://www.example.com/foo.png')); + $this->assertTrue(media_ispublic('hTTps://www.example.com/foo.png')); + } + + public function test_internal(){ + $this->assertTrue(media_ispublic('wiki:logo.png')); + $this->assertFalse(media_ispublic('private:logo.png')); + } + +} \ No newline at end of file diff --git a/inc/media.php b/inc/media.php index db1ca0d5786fcbc6290a91b46851cc140cc367d9..501d170f30a472d62e653d21c841eaf33ff2c2aa 100644 --- a/inc/media.php +++ b/inc/media.php @@ -82,6 +82,20 @@ function media_metasave($id,$auth,$data){ } } +/** + * Check if a media item is public (eg, external URL or readable by @ALL) + * + * @author Andreas Gohr <andi@splitbrain.org> + * @param string $id the media ID or URL + * @return bool + */ +function media_ispublic($id){ + if(preg_match('/^https?:\/\//i',$id)) return true; + $id = cleanID($id); + if(auth_aclcheck(getNS($id).':*', '', array()) >= AUTH_READ) return true; + return false; +} + /** * Display the form to edit image meta data * diff --git a/lib/exe/fetch.php b/lib/exe/fetch.php index 9bac4d272abd26b6dcff454457f10095681a929a..a9147a6c07a058b9478fcdc36895173f8943b0a8 100644 --- a/lib/exe/fetch.php +++ b/lib/exe/fetch.php @@ -47,6 +47,7 @@ if(!defined('SIMPLE_TEST')) { 'height' => $HEIGHT, 'status' => $STATUS, 'statusmessage' => $STATUSMESSAGE, + 'ispublic' => media_ispublic($MEDIA), ); // handle the file status @@ -81,10 +82,13 @@ if(!defined('SIMPLE_TEST')) { // finally send the file to the client $evt = new Doku_Event('MEDIA_SENDFILE', $data); if($evt->advise_before()) { - sendFile($data['file'], $data['mime'], $data['download'], $data['cache']); + $cache = $data['cache']; + if($cache != 0 && !$data['ispublic']) $cache = 0; // no cache headers for private files FS#2734 + + sendFile($data['file'], $data['mime'], $data['download'], $cache); } // Do something after the download finished. - $evt->advise_after(); + $evt->advise_after(); // will not be emitted on 304 or x-sendfile }// END DO main @@ -93,8 +97,18 @@ if(!defined('SIMPLE_TEST')) { /** * Set headers and send the file to the client * + * Unless $cache is set to 0, the data may end up in intermediate proxy servers. Therefor, + * if you're sending (ACL protected) private files, $cache should be 0. + * + * This function will abort the current script when a 304 is sent or file sending is handled + * through x-sendfile + * * @author Andreas Gohr <andi@splitbrain.org> * @author Ben Coburn <btcoburn@silicodon.net> + * @param string $file local file to send + * @param string $mime mime type of the file + * @param bool $dl set to true to force a browser download + * @param int $cache remaining cache time in seconds (-1 for $conf['cache'], 0 for off) */ function sendFile($file, $mime, $dl, $cache) { global $conf; @@ -115,9 +129,10 @@ function sendFile($file, $mime, $dl, $cache) { header('Cache-Control: public, proxy-revalidate, no-transform, max-age='.max($fmtime - time() + $conf['cachetime'] + 10, 0)); header('Pragma: public'); } else if($cache == 0) { - // nocache - header('Cache-Control: must-revalidate, no-transform, post-check=0, pre-check=0'); - header('Pragma: public'); + // nocache, avoid resending files from intermediate caches without revalidation FS#2734 + header('Expires: Thu, 01 Jan 1970 00:00:00 GMT'); + header('Cache-Control: private, no-transform, max-age=0'); + header('Pragma: no-cache'); } //send important headers first, script stops here if '304 Not Modified' response http_conditionalRequest($fmtime);