SeekquarrySeekquarry - Yioop Repo - Seekquarry

/ tests / ResourceControllerTest.php⤓
<?php
/**
 * SeekQuarry/Yioop --
 * Open Source Pure PHP Search Engine, Crawler, and Indexer
 *
 * Copyright (C) 2009 - 2026  Chris Pollett chris@pollett.org
 *
 * LICENSE:
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU 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 General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 *
 * END LICENSE
 *
 * @author Chris Pollett chris@pollett.org
 * @license https://www.gnu.org/licenses/ GPL3
 * @link https://www.seekquarry.com/
 * @copyright 2009 - 2026
 * @filesource
 */
namespace seekquarry\yioop\tests;

use seekquarry\yioop\configs as C;
use seekquarry\yioop\library as L;
use seekquarry\yioop\controllers\ResourceController;
use seekquarry\atto\WebSite;
use seekquarry\yioop\library\UnitTest;

/**
 * ResourceControllerTest checks when the resource controller sends a
 * file gzip compressed and that the compressed bytes are the file, and
 * which folders requests that name no group may read.
 *
 * @author Chris Pollett
 */
class ResourceControllerTest extends UnitTest
{
    /**
     * setUp runs before each case; nothing is needed here.
     */
    public function setUp()
    {
    }
    /**
     * tearDown runs after each case; nothing is needed here.
     */
    public function tearDown()
    {
    }
    /**
     * styleSheetIsCompressedWhenAcceptedTestCase checks when a file is
     * sent gzip compressed: a style sheet asked for with gzip accepted is,
     * and it is not when gzip is not accepted, when a byte range is asked
     * for, for a picture type, or for a file too large to buffer. It also
     * checks that the compressed bytes the web site gives for the style
     * sheet decode to the whole file.
     */
    public function styleSheetIsCompressedWhenAcceptedTestCase()
    {
        $controller = (new \ReflectionClass(ResourceController::class))
            ->newInstanceWithoutConstructor();
        $controller->web_site = new WebSite();
        $path = C\BASE_DIR . "/css/search.css";
        $size = filesize($path);
        $_SERVER['HTTP_ACCEPT_ENCODING'] = "gzip, deflate";
        unset($_SERVER['HTTP_RANGE'], $_REQUEST['o'], $_REQUEST['l']);
        $this->assertTrue(
            $controller->compressWhenSending("text/css", $size),
            "a style sheet is compressed when gzip is accepted");
        $bytes = $controller->web_site->fileGetContents($path, false, true);
        $this->assertTrue(strlen($bytes) < $size / 3,
            "the compressed style sheet is under a third of its size");
        $this->assertEqual(md5_file($path), md5(gzdecode($bytes)),
            "and decodes to the whole file");
        $this->assertEqual(false,
            $controller->compressWhenSending("image/png", $size),
            "a picture type is not compressed");
        $this->assertEqual(false, $controller->compressWhenSending(
            "text/css", C\MAX_RESOURCE_SERVE_LEN + 1),
            "a file too large to buffer is not compressed");
        $_SERVER['HTTP_RANGE'] = "bytes=0-10";
        $this->assertEqual(false,
            $controller->compressWhenSending("text/css", $size),
            "a byte range request is not compressed");
        unset($_SERVER['HTTP_RANGE'], $_SERVER['HTTP_ACCEPT_ENCODING']);
        $this->assertEqual(false,
            $controller->compressWhenSending("text/css", $size),
            "a request that does not accept gzip is not compressed");
    }
    /**
     * userRequestReadsOnlyTheSafeListTestCase checks that a request with
     * s and no g, which reads a user's folder with no group check, is
     * refused for any file not in ResourceFolders::USER_FILE_SAFE_LIST,
     * and for the safe file asked for in a sub-folder or as a thumbnail.
     */
    public function userRequestReadsOnlyTheSafeListTestCase()
    {
        $controller = $this->bareController();
        $answers = [];
        foreach ([["n" => "redirect.txt"], ["n" => "secrets.txt"],
            ["n" => "user_icon.webp", "sf" => "x"],
            ["n" => "user_icon.webp", "t" => "1"]] as $fields) {
            $_REQUEST = ["f" => "resources", "s" => "5"] + $fields;
            [, $base_dir] = $controller->getNameAndBaseFolder();
            $answers[] = $base_dir;
        }
        $_REQUEST = [];
        $this->assertEqual($answers, [false, false, false, false],
            "only the user's icon itself may be read without a group");
    }
    /**
     * requestWithoutGroupReadsOnlySiteFilesTestCase checks that a request
     * with neither g nor s reads from the site folder, or with sf naming
     * a host from that host's folder, and is refused for an sf that is a
     * path to any other folder under app/resources, such as a page's, or
     * for a thumbnail.
     */
    public function requestWithoutGroupReadsOnlySiteFilesTestCase()
    {
        $controller = $this->bareController();
        $answers = [];
        foreach ([["n" => "logo.png"],
            ["n" => "logo.png", "sf" => "www.example.com"],
            ["n" => "redirect.txt", "sf" => "F4C/F4C6duyWVQs"],
            ["n" => "redirect.txt", "sf" => "../users"],
            ["n" => "logo.png", "t" => "1"]] as $fields) {
            $_REQUEST = ["f" => "resources"] + $fields;
            [, $base_dir] = $controller->getNameAndBaseFolder();
            $answers[] = $base_dir;
        }
        $_REQUEST = [];
        $this->assertEqual($answers, [L\ResourceFolders::sitePath(),
            L\ResourceFolders::domainPath("www.example.com"), false, false,
            false], "the site's and a host's files only");
    }
    /**
     * bareController makes a ResourceController without running its
     * constructor, with a web site object to send through.
     *
     * @return ResourceController the controller
     */
    private function bareController()
    {
        $controller = (new \ReflectionClass(ResourceController::class))
            ->newInstanceWithoutConstructor();
        $controller->web_site = new WebSite();
        return $controller;
    }
}