xref: /dokuwiki/_test/tests/inc/httputils_xaccel.test.php (revision 12ead38a3265c876ad16de2b1607d07abd11f90b)
1<?php
2
3/**
4 * Tests for the nginx X-Accel-Redirect URL construction
5 *
6 * @see http_xaccel_url()
7 * @see https://github.com/dokuwiki/dokuwiki/issues/2895
8 */
9class httputils_xaccel_test extends DokuWikiTest
10{
11    /**
12     * Files inside the DokuWiki directory keep their path relative to the root.
13     * This is the default layout and must match the historic behaviour.
14     */
15    public function test_file_inside_dokuwiki()
16    {
17        $file = DOKU_INC . 'data/media/wiki/dokuwiki.png';
18        $this->assertEquals(
19            DOKU_REL . 'data/media/wiki/dokuwiki.png',
20            http_xaccel_url($file)
21        );
22    }
23
24    /**
25     * lib/ files (also inside the DokuWiki directory) work too.
26     */
27    public function test_libfile_inside_dokuwiki()
28    {
29        $file = DOKU_INC . 'lib/images/fileicons/png.png';
30        $this->assertEquals(
31            DOKU_REL . 'lib/images/fileicons/png.png',
32            http_xaccel_url($file)
33        );
34    }
35
36    /**
37     * A media directory moved out of the DokuWiki root is mapped to the URL it
38     * would have by default (below data/media/). This is the regression in
39     * issue #2895, where the previous blind substr() produced a broken path.
40     */
41    public function test_relocated_mediadir()
42    {
43        global $conf;
44        $conf['mediadir'] = '/srv/dokuwiki-media';
45        $file = '/srv/dokuwiki-media/wiki/dokuwiki.png';
46        $this->assertEquals(
47            DOKU_REL . 'data/media/wiki/dokuwiki.png',
48            http_xaccel_url($file)
49        );
50    }
51
52    /**
53     * The cache directory (used for resized media, compiled CSS/JS and the
54     * sitemap) is mapped as well when relocated.
55     */
56    public function test_relocated_cachedir()
57    {
58        global $conf;
59        $conf['cachedir'] = '/var/cache/dokuwiki';
60        $file = '/var/cache/dokuwiki/a/abcdef0123.css';
61        $this->assertEquals(
62            DOKU_REL . 'data/cache/a/abcdef0123.css',
63            http_xaccel_url($file)
64        );
65    }
66
67    /**
68     * The most specific (longest) configured directory must win, so a file
69     * below a relocated mediadir is not swallowed by a relocated savedir.
70     */
71    public function test_most_specific_dir_wins()
72    {
73        global $conf;
74        $conf['savedir'] = '/srv/dwdata';
75        $conf['mediadir'] = '/srv/dwdata/media';
76        $file = '/srv/dwdata/media/wiki/dokuwiki.png';
77        $this->assertEquals(
78            DOKU_REL . 'data/media/wiki/dokuwiki.png',
79            http_xaccel_url($file)
80        );
81    }
82
83    /**
84     * A file outside DokuWiki and all data directories (e.g. served by a
85     * plugin from an arbitrary location) is emitted as its absolute path
86     * behind the dedicated opt-in prefix.
87     */
88    public function test_arbitrary_file_uses_escape_hatch()
89    {
90        $file = '/opt/secret-downloads/report.pdf';
91        $this->assertEquals(
92            DOKU_REL . '_x_accel_redirect/opt/secret-downloads/report.pdf',
93            http_xaccel_url($file)
94        );
95    }
96
97    /**
98     * A relocated directory configured with a non-canonical path (containing
99     * '..' or '.' segments) must still be recognised. The comparison file is
100     * canonicalized via fullpath(), so the configured roots have to be too --
101     * this is the same canonicalization the DOKU_INC branch relies on, where
102     * the lib/exe entry points define DOKU_INC as __DIR__.'/../../'.
103     */
104    public function test_noncanonical_root_is_resolved()
105    {
106        global $conf;
107        $conf['savedir'] = '/srv/dwdata/sub/../';
108        $file = '/srv/dwdata/attic/wiki/start.1.txt.gz';
109        $this->assertEquals(
110            DOKU_REL . 'data/attic/wiki/start.1.txt.gz',
111            http_xaccel_url($file)
112        );
113    }
114
115    /**
116     * File names with spaces or other special characters must be URL-encoded,
117     * because nginx URL-decodes the X-Accel-Redirect target.
118     */
119    public function test_special_characters_are_encoded()
120    {
121        $file = DOKU_INC . 'data/media/wiki/some file & more.png';
122        $this->assertEquals(
123            DOKU_REL . 'data/media/wiki/some%20file%20%26%20more.png',
124            http_xaccel_url($file)
125        );
126    }
127}
128