xref: /unit/test/test_static.py (revision 1960)
11184Szelenkov@nginx.comimport os
21204Szelenkov@nginx.comimport socket
31477Szelenkov@nginx.com
41635Szelenkov@nginx.comimport pytest
51848Szelenkov@nginx.com
61184Szelenkov@nginx.comfrom unit.applications.proto import TestApplicationProto
71730Szelenkov@nginx.comfrom unit.option import option
81735Szelenkov@nginx.comfrom unit.utils import waitforfiles
91184Szelenkov@nginx.com
101184Szelenkov@nginx.com
111184Szelenkov@nginx.comclass TestStatic(TestApplicationProto):
121184Szelenkov@nginx.com    prerequisites = {}
131184Szelenkov@nginx.com
141596Szelenkov@nginx.com    def setup_method(self):
151654Szelenkov@nginx.com        os.makedirs(option.temp_dir + '/assets/dir')
161654Szelenkov@nginx.com        with open(option.temp_dir + '/assets/index.html', 'w') as index, open(
171654Szelenkov@nginx.com            option.temp_dir + '/assets/README', 'w'
181654Szelenkov@nginx.com        ) as readme, open(
191654Szelenkov@nginx.com            option.temp_dir + '/assets/log.log', 'w'
201654Szelenkov@nginx.com        ) as log, open(
211654Szelenkov@nginx.com            option.temp_dir + '/assets/dir/file', 'w'
221596Szelenkov@nginx.com        ) as file:
231184Szelenkov@nginx.com            index.write('0123456789')
241184Szelenkov@nginx.com            readme.write('readme')
251184Szelenkov@nginx.com            log.write('[debug]')
261184Szelenkov@nginx.com            file.write('blah')
271184Szelenkov@nginx.com
281184Szelenkov@nginx.com        self._load_conf(
291184Szelenkov@nginx.com            {
301184Szelenkov@nginx.com                "listeners": {"*:7080": {"pass": "routes"}},
31*1960Sz.hong@f5.com                "routes": [
32*1960Sz.hong@f5.com                    {"action": {"share": option.temp_dir + "/assets$uri"}}
33*1960Sz.hong@f5.com                ],
341184Szelenkov@nginx.com                "settings": {
351184Szelenkov@nginx.com                    "http": {
361184Szelenkov@nginx.com                        "static": {
371184Szelenkov@nginx.com                            "mime_types": {"text/plain": [".log", "README"]}
381184Szelenkov@nginx.com                        }
391184Szelenkov@nginx.com                    }
401184Szelenkov@nginx.com                },
411184Szelenkov@nginx.com            }
421184Szelenkov@nginx.com        )
431184Szelenkov@nginx.com
441184Szelenkov@nginx.com    def test_static_index(self):
451596Szelenkov@nginx.com        assert self.get(url='/index.html')['body'] == '0123456789', 'index'
461596Szelenkov@nginx.com        assert self.get(url='/')['body'] == '0123456789', 'index 2'
471596Szelenkov@nginx.com        assert self.get(url='//')['body'] == '0123456789', 'index 3'
481596Szelenkov@nginx.com        assert self.get(url='/.')['body'] == '0123456789', 'index 4'
491596Szelenkov@nginx.com        assert self.get(url='/./')['body'] == '0123456789', 'index 5'
501596Szelenkov@nginx.com        assert self.get(url='/?blah')['body'] == '0123456789', 'index vars'
511596Szelenkov@nginx.com        assert self.get(url='/#blah')['body'] == '0123456789', 'index anchor'
521596Szelenkov@nginx.com        assert self.get(url='/dir/')['status'] == 404, 'index not found'
531184Szelenkov@nginx.com
541184Szelenkov@nginx.com        resp = self.get(url='/index.html/')
551596Szelenkov@nginx.com        assert resp['status'] == 404, 'index not found 2 status'
561596Szelenkov@nginx.com        assert (
571596Szelenkov@nginx.com            resp['headers']['Content-Type'] == 'text/html'
581596Szelenkov@nginx.com        ), 'index not found 2 Content-Type'
591184Szelenkov@nginx.com
601654Szelenkov@nginx.com    def test_static_large_file(self, temp_dir):
611184Szelenkov@nginx.com        file_size = 32 * 1024 * 1024
621654Szelenkov@nginx.com        with open(temp_dir + '/assets/large', 'wb') as f:
631184Szelenkov@nginx.com            f.seek(file_size - 1)
641184Szelenkov@nginx.com            f.write(b'\0')
651184Szelenkov@nginx.com
661596Szelenkov@nginx.com        assert (
671596Szelenkov@nginx.com            len(self.get(url='/large', read_buffer_size=1024 * 1024)['body'])
681596Szelenkov@nginx.com            == file_size
691596Szelenkov@nginx.com        ), 'large file'
701184Szelenkov@nginx.com
711654Szelenkov@nginx.com    def test_static_etag(self, temp_dir):
721184Szelenkov@nginx.com        etag = self.get(url='/')['headers']['ETag']
731184Szelenkov@nginx.com        etag_2 = self.get(url='/README')['headers']['ETag']
741184Szelenkov@nginx.com
751596Szelenkov@nginx.com        assert etag != etag_2, 'different ETag'
761596Szelenkov@nginx.com        assert etag == self.get(url='/')['headers']['ETag'], 'same ETag'
771184Szelenkov@nginx.com
781654Szelenkov@nginx.com        with open(temp_dir + '/assets/index.html', 'w') as f:
791184Szelenkov@nginx.com            f.write('blah')
801184Szelenkov@nginx.com
811596Szelenkov@nginx.com        assert etag != self.get(url='/')['headers']['ETag'], 'new ETag'
821184Szelenkov@nginx.com
831184Szelenkov@nginx.com    def test_static_redirect(self):
841184Szelenkov@nginx.com        resp = self.get(url='/dir')
851596Szelenkov@nginx.com        assert resp['status'] == 301, 'redirect status'
861596Szelenkov@nginx.com        assert resp['headers']['Location'] == '/dir/', 'redirect Location'
871596Szelenkov@nginx.com        assert 'Content-Type' not in resp['headers'], 'redirect Content-Type'
881184Szelenkov@nginx.com
891654Szelenkov@nginx.com    def test_static_space_in_name(self, temp_dir):
901184Szelenkov@nginx.com        os.rename(
911848Szelenkov@nginx.com            temp_dir + '/assets/dir/file', temp_dir + '/assets/dir/fi le',
921184Szelenkov@nginx.com        )
931654Szelenkov@nginx.com        assert waitforfiles(temp_dir + '/assets/dir/fi le')
941596Szelenkov@nginx.com        assert self.get(url='/dir/fi le')['body'] == 'blah', 'file name'
951184Szelenkov@nginx.com
961654Szelenkov@nginx.com        os.rename(temp_dir + '/assets/dir', temp_dir + '/assets/di r')
971654Szelenkov@nginx.com        assert waitforfiles(temp_dir + '/assets/di r/fi le')
981596Szelenkov@nginx.com        assert self.get(url='/di r/fi le')['body'] == 'blah', 'dir name'
991184Szelenkov@nginx.com
1001848Szelenkov@nginx.com        os.rename(temp_dir + '/assets/di r', temp_dir + '/assets/ di r ')
1011654Szelenkov@nginx.com        assert waitforfiles(temp_dir + '/assets/ di r /fi le')
1021596Szelenkov@nginx.com        assert (
1031596Szelenkov@nginx.com            self.get(url='/ di r /fi le')['body'] == 'blah'
1041596Szelenkov@nginx.com        ), 'dir name enclosing'
1051596Szelenkov@nginx.com
1061596Szelenkov@nginx.com        assert (
1071596Szelenkov@nginx.com            self.get(url='/%20di%20r%20/fi le')['body'] == 'blah'
1081596Szelenkov@nginx.com        ), 'dir encoded'
1091596Szelenkov@nginx.com        assert (
1101596Szelenkov@nginx.com            self.get(url='/ di r %2Ffi le')['body'] == 'blah'
1111596Szelenkov@nginx.com        ), 'slash encoded'
1121596Szelenkov@nginx.com        assert (
1131596Szelenkov@nginx.com            self.get(url='/ di r /fi%20le')['body'] == 'blah'
1141596Szelenkov@nginx.com        ), 'file encoded'
1151596Szelenkov@nginx.com        assert (
1161596Szelenkov@nginx.com            self.get(url='/%20di%20r%20%2Ffi%20le')['body'] == 'blah'
1171596Szelenkov@nginx.com        ), 'encoded'
1181596Szelenkov@nginx.com        assert (
1191596Szelenkov@nginx.com            self.get(url='/%20%64%69%20%72%20%2F%66%69%20%6C%65')['body']
1201596Szelenkov@nginx.com            == 'blah'
1211596Szelenkov@nginx.com        ), 'encoded 2'
1221184Szelenkov@nginx.com
1231184Szelenkov@nginx.com        os.rename(
1241654Szelenkov@nginx.com            temp_dir + '/assets/ di r /fi le',
1251654Szelenkov@nginx.com            temp_dir + '/assets/ di r / fi le ',
1261184Szelenkov@nginx.com        )
1271654Szelenkov@nginx.com        assert waitforfiles(temp_dir + '/assets/ di r / fi le ')
1281596Szelenkov@nginx.com        assert (
1291596Szelenkov@nginx.com            self.get(url='/%20di%20r%20/%20fi%20le%20')['body'] == 'blah'
1301596Szelenkov@nginx.com        ), 'file name enclosing'
1311184Szelenkov@nginx.com
1321184Szelenkov@nginx.com        try:
1331654Szelenkov@nginx.com            open(temp_dir + '/ф а', 'a').close()
1341184Szelenkov@nginx.com            utf8 = True
1351184Szelenkov@nginx.com
1361706Smax.romanov@nginx.com        except KeyboardInterrupt:
1371706Smax.romanov@nginx.com            raise
1381706Smax.romanov@nginx.com
1391184Szelenkov@nginx.com        except:
1401184Szelenkov@nginx.com            utf8 = False
1411184Szelenkov@nginx.com
1421184Szelenkov@nginx.com        if utf8:
1431184Szelenkov@nginx.com            os.rename(
1441654Szelenkov@nginx.com                temp_dir + '/assets/ di r / fi le ',
1451654Szelenkov@nginx.com                temp_dir + '/assets/ di r /фа йл',
1461184Szelenkov@nginx.com            )
1471654Szelenkov@nginx.com            assert waitforfiles(temp_dir + '/assets/ di r /фа йл')
1481596Szelenkov@nginx.com            assert (
1491596Szelenkov@nginx.com                self.get(url='/ di r /фа йл')['body'] == 'blah'
1501596Szelenkov@nginx.com            ), 'file name 2'
1511184Szelenkov@nginx.com
1521184Szelenkov@nginx.com            os.rename(
1531848Szelenkov@nginx.com                temp_dir + '/assets/ di r ', temp_dir + '/assets/ди ректория',
1541184Szelenkov@nginx.com            )
1551654Szelenkov@nginx.com            assert waitforfiles(temp_dir + '/assets/ди ректория/фа йл')
1561596Szelenkov@nginx.com            assert (
1571596Szelenkov@nginx.com                self.get(url='/ди ректория/фа йл')['body'] == 'blah'
1581596Szelenkov@nginx.com            ), 'dir name 2'
1591184Szelenkov@nginx.com
1601654Szelenkov@nginx.com    def test_static_unix_socket(self, temp_dir):
1611204Szelenkov@nginx.com        sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
1621654Szelenkov@nginx.com        sock.bind(temp_dir + '/assets/unix_socket')
1631204Szelenkov@nginx.com
1641596Szelenkov@nginx.com        assert self.get(url='/unix_socket')['status'] == 404, 'socket'
1651204Szelenkov@nginx.com
1661204Szelenkov@nginx.com        sock.close()
1671204Szelenkov@nginx.com
1681654Szelenkov@nginx.com    def test_static_unix_fifo(self, temp_dir):
1691654Szelenkov@nginx.com        os.mkfifo(temp_dir + '/assets/fifo')
1701204Szelenkov@nginx.com
1711596Szelenkov@nginx.com        assert self.get(url='/fifo')['status'] == 404, 'fifo'
1721204Szelenkov@nginx.com
1731368Szelenkov@nginx.com    def test_static_method(self):
1741368Szelenkov@nginx.com        resp = self.head()
1751596Szelenkov@nginx.com        assert resp['status'] == 200, 'HEAD status'
1761596Szelenkov@nginx.com        assert resp['body'] == '', 'HEAD empty body'
1771368Szelenkov@nginx.com
1781596Szelenkov@nginx.com        assert self.delete()['status'] == 405, 'DELETE'
1791596Szelenkov@nginx.com        assert self.post()['status'] == 405, 'POST'
1801596Szelenkov@nginx.com        assert self.put()['status'] == 405, 'PUT'
1811368Szelenkov@nginx.com
1821368Szelenkov@nginx.com    def test_static_path(self):
1831596Szelenkov@nginx.com        assert self.get(url='/dir/../dir/file')['status'] == 200, 'relative'
1841368Szelenkov@nginx.com
1851596Szelenkov@nginx.com        assert self.get(url='./')['status'] == 400, 'path invalid'
1861596Szelenkov@nginx.com        assert self.get(url='../')['status'] == 400, 'path invalid 2'
1871596Szelenkov@nginx.com        assert self.get(url='/..')['status'] == 400, 'path invalid 3'
1881596Szelenkov@nginx.com        assert self.get(url='../assets/')['status'] == 400, 'path invalid 4'
1891596Szelenkov@nginx.com        assert self.get(url='/../assets/')['status'] == 400, 'path invalid 5'
1901184Szelenkov@nginx.com
1911184Szelenkov@nginx.com    def test_static_two_clients(self):
1921184Szelenkov@nginx.com        _, sock = self.get(url='/', start=True, no_recv=True)
1931184Szelenkov@nginx.com        _, sock2 = self.get(url='/', start=True, no_recv=True)
1941184Szelenkov@nginx.com
1951596Szelenkov@nginx.com        assert sock.recv(1) == b'H', 'client 1'
1961596Szelenkov@nginx.com        assert sock2.recv(1) == b'H', 'client 2'
1971596Szelenkov@nginx.com        assert sock.recv(1) == b'T', 'client 1 again'
1981596Szelenkov@nginx.com        assert sock2.recv(1) == b'T', 'client 2 again'
1991184Szelenkov@nginx.com
2001184Szelenkov@nginx.com        sock.close()
2011184Szelenkov@nginx.com        sock2.close()
2021184Szelenkov@nginx.com
2031184Szelenkov@nginx.com    def test_static_mime_types(self):
2041596Szelenkov@nginx.com        assert 'success' in self.conf(
2051596Szelenkov@nginx.com            {
2061596Szelenkov@nginx.com                "text/x-code/x-blah/x-blah": "readme",
2071596Szelenkov@nginx.com                "text/plain": [".html", ".log", "file"],
2081596Szelenkov@nginx.com            },
2091596Szelenkov@nginx.com            'settings/http/static/mime_types',
2101596Szelenkov@nginx.com        ), 'configure mime_types'
2111184Szelenkov@nginx.com
2121596Szelenkov@nginx.com        assert (
2131596Szelenkov@nginx.com            self.get(url='/README')['headers']['Content-Type']
2141596Szelenkov@nginx.com            == 'text/x-code/x-blah/x-blah'
2151596Szelenkov@nginx.com        ), 'mime_types string case insensitive'
2161596Szelenkov@nginx.com        assert (
2171596Szelenkov@nginx.com            self.get(url='/index.html')['headers']['Content-Type']
2181596Szelenkov@nginx.com            == 'text/plain'
2191596Szelenkov@nginx.com        ), 'mime_types html'
2201596Szelenkov@nginx.com        assert (
2211596Szelenkov@nginx.com            self.get(url='/')['headers']['Content-Type'] == 'text/plain'
2221596Szelenkov@nginx.com        ), 'mime_types index default'
2231596Szelenkov@nginx.com        assert (
2241596Szelenkov@nginx.com            self.get(url='/dir/file')['headers']['Content-Type']
2251596Szelenkov@nginx.com            == 'text/plain'
2261596Szelenkov@nginx.com        ), 'mime_types file in dir'
2271184Szelenkov@nginx.com
2281184Szelenkov@nginx.com    def test_static_mime_types_partial_match(self):
2291596Szelenkov@nginx.com        assert 'success' in self.conf(
2301596Szelenkov@nginx.com            {"text/x-blah": ["ile", "fil", "f", "e", ".file"],},
2311596Szelenkov@nginx.com            'settings/http/static/mime_types',
2321596Szelenkov@nginx.com        ), 'configure mime_types'
2331596Szelenkov@nginx.com        assert 'Content-Type' not in self.get(url='/dir/file'), 'partial match'
2341184Szelenkov@nginx.com
2351184Szelenkov@nginx.com    def test_static_mime_types_reconfigure(self):
2361596Szelenkov@nginx.com        assert 'success' in self.conf(
2371596Szelenkov@nginx.com            {
2381596Szelenkov@nginx.com                "text/x-code": "readme",
2391596Szelenkov@nginx.com                "text/plain": [".html", ".log", "file"],
2401596Szelenkov@nginx.com            },
2411596Szelenkov@nginx.com            'settings/http/static/mime_types',
2421596Szelenkov@nginx.com        ), 'configure mime_types'
2431184Szelenkov@nginx.com
2441596Szelenkov@nginx.com        assert self.conf_get('settings/http/static/mime_types') == {
2451596Szelenkov@nginx.com            'text/x-code': 'readme',
2461596Szelenkov@nginx.com            'text/plain': ['.html', '.log', 'file'],
2471596Szelenkov@nginx.com        }, 'mime_types get'
2481596Szelenkov@nginx.com        assert (
2491596Szelenkov@nginx.com            self.conf_get('settings/http/static/mime_types/text%2Fx-code')
2501596Szelenkov@nginx.com            == 'readme'
2511596Szelenkov@nginx.com        ), 'mime_types get string'
2521596Szelenkov@nginx.com        assert self.conf_get(
2531596Szelenkov@nginx.com            'settings/http/static/mime_types/text%2Fplain'
2541596Szelenkov@nginx.com        ) == ['.html', '.log', 'file'], 'mime_types get array'
2551596Szelenkov@nginx.com        assert (
2561596Szelenkov@nginx.com            self.conf_get('settings/http/static/mime_types/text%2Fplain/1')
2571596Szelenkov@nginx.com            == '.log'
2581596Szelenkov@nginx.com        ), 'mime_types get array element'
2591184Szelenkov@nginx.com
2601596Szelenkov@nginx.com        assert 'success' in self.conf_delete(
2611596Szelenkov@nginx.com            'settings/http/static/mime_types/text%2Fplain/2'
2621596Szelenkov@nginx.com        ), 'mime_types remove array element'
2631596Szelenkov@nginx.com        assert (
2641596Szelenkov@nginx.com            'Content-Type' not in self.get(url='/dir/file')['headers']
2651596Szelenkov@nginx.com        ), 'mime_types removed'
2661596Szelenkov@nginx.com
2671596Szelenkov@nginx.com        assert 'success' in self.conf_post(
2681596Szelenkov@nginx.com            '"file"', 'settings/http/static/mime_types/text%2Fplain'
2691596Szelenkov@nginx.com        ), 'mime_types add array element'
2701596Szelenkov@nginx.com        assert (
2711596Szelenkov@nginx.com            self.get(url='/dir/file')['headers']['Content-Type']
2721596Szelenkov@nginx.com            == 'text/plain'
2731596Szelenkov@nginx.com        ), 'mime_types reverted'
2741184Szelenkov@nginx.com
2751596Szelenkov@nginx.com        assert 'success' in self.conf(
2761596Szelenkov@nginx.com            '"file"', 'settings/http/static/mime_types/text%2Fplain'
2771596Szelenkov@nginx.com        ), 'configure mime_types update'
2781596Szelenkov@nginx.com        assert (
2791596Szelenkov@nginx.com            self.get(url='/dir/file')['headers']['Content-Type']
2801596Szelenkov@nginx.com            == 'text/plain'
2811596Szelenkov@nginx.com        ), 'mime_types updated'
2821596Szelenkov@nginx.com        assert (
2831596Szelenkov@nginx.com            'Content-Type' not in self.get(url='/log.log')['headers']
2841596Szelenkov@nginx.com        ), 'mime_types updated 2'
2851184Szelenkov@nginx.com
2861596Szelenkov@nginx.com        assert 'success' in self.conf(
2871596Szelenkov@nginx.com            '".log"', 'settings/http/static/mime_types/text%2Fblahblahblah'
2881596Szelenkov@nginx.com        ), 'configure mime_types create'
2891596Szelenkov@nginx.com        assert (
2901596Szelenkov@nginx.com            self.get(url='/log.log')['headers']['Content-Type']
2911596Szelenkov@nginx.com            == 'text/blahblahblah'
2921596Szelenkov@nginx.com        ), 'mime_types create'
2931184Szelenkov@nginx.com
2941184Szelenkov@nginx.com    def test_static_mime_types_correct(self):
2951596Szelenkov@nginx.com        assert 'error' in self.conf(
2961596Szelenkov@nginx.com            {"text/x-code": "readme", "text/plain": "readme"},
2971596Szelenkov@nginx.com            'settings/http/static/mime_types',
2981596Szelenkov@nginx.com        ), 'mime_types same extensions'
2991596Szelenkov@nginx.com        assert 'error' in self.conf(
3001596Szelenkov@nginx.com            {"text/x-code": [".h", ".c"], "text/plain": ".c"},
3011596Szelenkov@nginx.com            'settings/http/static/mime_types',
3021596Szelenkov@nginx.com        ), 'mime_types same extensions array'
3031596Szelenkov@nginx.com        assert 'error' in self.conf(
3041596Szelenkov@nginx.com            {"text/x-code": [".h", ".c", "readme"], "text/plain": "README",},
3051596Szelenkov@nginx.com            'settings/http/static/mime_types',
3061596Szelenkov@nginx.com        ), 'mime_types same extensions case insensitive'
3071184Szelenkov@nginx.com
3081596Szelenkov@nginx.com    @pytest.mark.skip('not yet')
3091654Szelenkov@nginx.com    def test_static_mime_types_invalid(self, temp_dir):
3101596Szelenkov@nginx.com        assert 'error' in self.http(
3111596Szelenkov@nginx.com            b"""PUT /config/settings/http/static/mime_types/%0%00% HTTP/1.1\r
3121184Szelenkov@nginx.comHost: localhost\r
3131184Szelenkov@nginx.comConnection: close\r
3141184Szelenkov@nginx.comContent-Length: 6\r
3151184Szelenkov@nginx.com\r
3161184Szelenkov@nginx.com\"blah\"""",
3171596Szelenkov@nginx.com            raw_resp=True,
3181596Szelenkov@nginx.com            raw=True,
3191596Szelenkov@nginx.com            sock_type='unix',
3201654Szelenkov@nginx.com            addr=temp_dir + '/control.unit.sock',
3211596Szelenkov@nginx.com        ), 'mime_types invalid'
322