diff options
Diffstat (limited to 'test/test_php_application.py')
-rw-r--r-- | test/test_php_application.py | 1279 |
1 files changed, 655 insertions, 624 deletions
diff --git a/test/test_php_application.py b/test/test_php_application.py index 6e1d190a..6c1f227b 100644 --- a/test/test_php_application.py +++ b/test/test_php_application.py @@ -7,822 +7,853 @@ import time from pathlib import Path import pytest -from unit.applications.lang.php import TestApplicationPHP +from unit.applications.lang.php import ApplicationPHP from unit.option import option +prerequisites = {'modules': {'php': 'all'}} -class TestPHPApplication(TestApplicationPHP): - prerequisites = {'modules': {'php': 'all'}} +client = ApplicationPHP() - def before_disable_functions(self): - body = self.get()['body'] - assert re.search(r'time: \d+', body), 'disable_functions before time' - assert re.search(r'exec: \/\w+', body), 'disable_functions before exec' +def before_disable_functions(): + body = client.get()['body'] - def check_opcache(self): - resp = self.get() - assert resp['status'] == 200, 'status' + assert re.search(r'time: \d+', body), 'disable_functions before time' + assert re.search(r'exec: \/\w+', body), 'disable_functions before exec' - headers = resp['headers'] - if 'X-OPcache' in headers and headers['X-OPcache'] == '-1': - pytest.skip('opcache is not supported') - return resp +def check_opcache(): + resp = client.get() + assert resp['status'] == 200, 'status' - def set_opcache(self, app, val): - assert 'success' in self.conf( - {"admin": {"opcache.enable": val, "opcache.enable_cli": val}}, - f'applications/{app}/options', - ) + headers = resp['headers'] + if 'X-OPcache' in headers and headers['X-OPcache'] == '-1': + pytest.skip('opcache is not supported') - r = self.check_opcache() - assert r['headers']['X-OPcache'] == val, 'opcache value' + return resp - def set_preload(self, preload): - with open(f'{option.temp_dir}/php.ini', 'w') as f: - f.write( - f"""opcache.preload = {option.test_dir}/php/opcache/preload\ -/{preload} -opcache.preload_user = {option.user or getpass.getuser()} -""" - ) - assert 'success' in self.conf( - {"file": f"{option.temp_dir}/php.ini"}, - 'applications/opcache/options', - ) +def run_php_application_cwd_root_tests(): + assert 'success' in client.conf_delete('applications/cwd/working_directory') - def test_php_application_variables(self): - self.load('variables') + script_cwd = f'{option.test_dir}/php/cwd' - body = 'Test body string.' + resp = client.get() + assert resp['status'] == 200, 'status ok' + assert resp['body'] == script_cwd, 'default cwd' - resp = self.post( - headers={ - 'Host': 'localhost', - 'Content-Type': 'text/html', - 'Custom-Header': 'blah', - 'Connection': 'close', - }, - body=body, - url='/index.php/blah?var=val', - ) + assert 'success' in client.conf( + f'"{option.test_dir}"', + 'applications/cwd/working_directory', + ) - assert resp['status'] == 200, 'status' - headers = resp['headers'] - header_server = headers.pop('Server') - assert re.search(r'Unit/[\d\.]+', header_server), 'server header' - assert ( - headers.pop('Server-Software') == header_server - ), 'server software header' - - date = headers.pop('Date') - assert date[-4:] == ' GMT', 'date header timezone' - assert ( - abs(self.date_to_sec_epoch(date) - self.sec_epoch()) < 5 - ), 'date header' - - if 'X-Powered-By' in headers: - headers.pop('X-Powered-By') - - headers.pop('Content-type') - assert headers == { - 'Connection': 'close', - 'Content-Length': str(len(body)), - 'Request-Method': 'POST', - 'Path-Info': '/blah', - 'Request-Uri': '/index.php/blah?var=val', - 'Http-Host': 'localhost', - 'Server-Protocol': 'HTTP/1.1', - 'Custom-Header': 'blah', - }, 'headers' - assert resp['body'] == body, 'body' + resp = client.get() + assert resp['status'] == 200, 'status ok' + assert resp['body'] == script_cwd, 'wdir cwd' - def test_php_application_query_string(self): - self.load('query_string') + resp = client.get(url='/?chdir=/') + assert resp['status'] == 200, 'status ok' + assert resp['body'] == '/', 'cwd after chdir' - resp = self.get(url='/?var1=val1&var2=val2') + # cwd must be restored - assert ( - resp['headers']['Query-String'] == 'var1=val1&var2=val2' - ), 'query string' + resp = client.get() + assert resp['status'] == 200, 'status ok' + assert resp['body'] == script_cwd, 'cwd restored' - def test_php_application_query_string_empty(self): - self.load('query_string') + resp = client.get(url='/subdir/') + assert resp['body'] == f'{script_cwd}/subdir', 'cwd subdir' - resp = self.get(url='/?') - assert resp['status'] == 200, 'query string empty status' - assert resp['headers']['Query-String'] == '', 'query string empty' +def run_php_application_cwd_script_tests(): + client.load('cwd') - def test_php_application_fastcgi_finish_request(self, unit_pid): - self.load('fastcgi_finish_request') + script_cwd = f'{option.test_dir}/php/cwd' - assert 'success' in self.conf( - {"admin": {"auto_globals_jit": "1"}}, - 'applications/fastcgi_finish_request/options', - ) + assert 'success' in client.conf_delete('applications/cwd/working_directory') - assert self.get()['body'] == '0123' + assert 'success' in client.conf('"index.php"', 'applications/cwd/script') - os.kill(unit_pid, signal.SIGUSR1) + assert client.get()['body'] == script_cwd, 'default cwd' - errs = self.findall(r'Error in fastcgi_finish_request') + assert client.get(url='/?chdir=/')['body'] == '/', 'cwd after chdir' - assert len(errs) == 0, 'no error' + # cwd must be restored + assert client.get()['body'] == script_cwd, 'cwd restored' - def test_php_application_fastcgi_finish_request_2(self, unit_pid): - self.load('fastcgi_finish_request') - assert 'success' in self.conf( - {"admin": {"auto_globals_jit": "1"}}, - 'applications/fastcgi_finish_request/options', +def set_opcache(app, val): + assert 'success' in client.conf( + {"admin": {"opcache.enable": val, "opcache.enable_cli": val}}, + f'applications/{app}/options', + ) + + r = check_opcache() + assert r['headers']['X-OPcache'] == val, 'opcache value' + + +def set_preload(preload): + with open(f'{option.temp_dir}/php.ini', 'w') as ini: + ini.write( + f"""opcache.preload = {option.test_dir}/php/opcache/preload\ +/{preload} +opcache.preload_user = {option.user or getpass.getuser()} +""" ) - resp = self.get(url='/?skip') - assert resp['status'] == 200 - assert resp['body'] == '' + assert 'success' in client.conf( + {"file": f"{option.temp_dir}/php.ini"}, + 'applications/opcache/options', + ) - os.kill(unit_pid, signal.SIGUSR1) - errs = self.findall(r'Error in fastcgi_finish_request') +def test_php_application_variables(date_to_sec_epoch, sec_epoch): + client.load('variables') - assert len(errs) == 0, 'no error' + body = 'Test body string.' - def test_php_application_query_string_absent(self): - self.load('query_string') + resp = client.post( + headers={ + 'Host': 'localhost', + 'Content-Type': 'text/html', + 'Custom-Header': 'blah', + 'Connection': 'close', + }, + body=body, + url='/index.php/blah?var=val', + ) - resp = self.get() + assert resp['status'] == 200, 'status' + headers = resp['headers'] + header_server = headers.pop('Server') + assert re.search(r'Unit/[\d\.]+', header_server), 'server header' + assert ( + headers.pop('Server-Software') == header_server + ), 'server software header' - assert resp['status'] == 200, 'query string absent status' - assert resp['headers']['Query-String'] == '', 'query string absent' + date = headers.pop('Date') + assert date[-4:] == ' GMT', 'date header timezone' + assert abs(date_to_sec_epoch(date) - sec_epoch) < 5, 'date header' - def test_php_application_phpinfo(self): - self.load('phpinfo') + if 'X-Powered-By' in headers: + headers.pop('X-Powered-By') - resp = self.get() + headers.pop('Content-type') + assert headers == { + 'Connection': 'close', + 'Content-Length': str(len(body)), + 'Request-Method': 'POST', + 'Path-Info': '/blah', + 'Request-Uri': '/index.php/blah?var=val', + 'Http-Host': 'localhost', + 'Server-Protocol': 'HTTP/1.1', + 'Custom-Header': 'blah', + }, 'headers' + assert resp['body'] == body, 'body' - assert resp['status'] == 200, 'status' - assert resp['body'] != '', 'body not empty' - def test_php_application_header_status(self): - self.load('header') +def test_php_application_query_string(): + client.load('query_string') - assert ( - self.get( - headers={ - 'Host': 'localhost', - 'Connection': 'close', - 'X-Header': 'HTTP/1.1 404 Not Found', - } - )['status'] - == 404 - ), 'status' - - assert ( - self.get( - headers={ - 'Host': 'localhost', - 'Connection': 'close', - 'X-Header': 'http/1.1 404 Not Found', - } - )['status'] - == 404 - ), 'status case insensitive' - - assert ( - self.get( - headers={ - 'Host': 'localhost', - 'Connection': 'close', - 'X-Header': 'HTTP/ 404 Not Found', - } - )['status'] - == 404 - ), 'status version empty' + resp = client.get(url='/?var1=val1&var2=val2') - def test_php_application_404(self): - self.load('404') + assert ( + resp['headers']['Query-String'] == 'var1=val1&var2=val2' + ), 'query string' - resp = self.get() - assert resp['status'] == 404, '404 status' - assert re.search( - r'<title>404 Not Found</title>', resp['body'] - ), '404 body' +def test_php_application_query_string_empty(): + client.load('query_string') - def test_php_application_keepalive_body(self): - self.load('mirror') + resp = client.get(url='/?') - assert self.get()['status'] == 200, 'init' + assert resp['status'] == 200, 'query string empty status' + assert resp['headers']['Query-String'] == '', 'query string empty' + + +def test_php_application_fastcgi_finish_request(findall, unit_pid): + client.load('fastcgi_finish_request') + + assert 'success' in client.conf( + {"admin": {"auto_globals_jit": "1"}}, + 'applications/fastcgi_finish_request/options', + ) + + assert client.get()['body'] == '0123' + + os.kill(unit_pid, signal.SIGUSR1) + + errs = findall(r'Error in fastcgi_finish_request') + + assert len(errs) == 0, 'no error' - body = '0123456789' * 500 - (resp, sock) = self.post( - headers={ - 'Host': 'localhost', - 'Connection': 'keep-alive', - }, - start=True, - body=body, - read_timeout=1, - ) - assert resp['body'] == body, 'keep-alive 1' +def test_php_application_fastcgi_finish_request_2(findall, unit_pid): + client.load('fastcgi_finish_request') - body = '0123456789' - resp = self.post(sock=sock, body=body) + assert 'success' in client.conf( + {"admin": {"auto_globals_jit": "1"}}, + 'applications/fastcgi_finish_request/options', + ) - assert resp['body'] == body, 'keep-alive 2' + resp = client.get(url='/?skip') + assert resp['status'] == 200 + assert resp['body'] == '' - def test_php_application_conditional(self): - self.load('conditional') + os.kill(unit_pid, signal.SIGUSR1) - assert re.search(r'True', self.get()['body']), 'conditional true' - assert re.search(r'False', self.post()['body']), 'conditional false' + errs = findall(r'Error in fastcgi_finish_request') - def test_php_application_get_variables(self): - self.load('get_variables') + assert len(errs) == 0, 'no error' - resp = self.get(url='/?var1=val1&var2=&var3') - assert resp['headers']['X-Var-1'] == 'val1', 'GET variables' - assert resp['headers']['X-Var-2'] == '', 'GET variables 2' - assert resp['headers']['X-Var-3'] == '', 'GET variables 3' - assert resp['headers']['X-Var-4'] == 'not set', 'GET variables 4' - def test_php_application_post_variables(self): - self.load('post_variables') +def test_php_application_query_string_absent(): + client.load('query_string') - resp = self.post( + resp = client.get() + + assert resp['status'] == 200, 'query string absent status' + assert resp['headers']['Query-String'] == '', 'query string absent' + + +def test_php_application_phpinfo(): + client.load('phpinfo') + + resp = client.get() + + assert resp['status'] == 200, 'status' + assert resp['body'] != '', 'body not empty' + + +def test_php_application_header_status(): + client.load('header') + + assert ( + client.get( headers={ - 'Content-Type': 'application/x-www-form-urlencoded', 'Host': 'localhost', 'Connection': 'close', - }, - body='var1=val1&var2=', - ) - assert resp['headers']['X-Var-1'] == 'val1', 'POST variables' - assert resp['headers']['X-Var-2'] == '', 'POST variables 2' - assert resp['headers']['X-Var-3'] == 'not set', 'POST variables 3' + 'X-Header': 'HTTP/1.1 404 Not Found', + } + )['status'] + == 404 + ), 'status' - def test_php_application_cookies(self): - self.load('cookies') + assert ( + client.get( + headers={ + 'Host': 'localhost', + 'Connection': 'close', + 'X-Header': 'http/1.1 404 Not Found', + } + )['status'] + == 404 + ), 'status case insensitive' - resp = self.get( + assert ( + client.get( headers={ - 'Cookie': 'var=val; var2=val2', 'Host': 'localhost', 'Connection': 'close', + 'X-Header': 'HTTP/ 404 Not Found', } - ) + )['status'] + == 404 + ), 'status version empty' - assert resp['headers']['X-Cookie-1'] == 'val', 'cookie' - assert resp['headers']['X-Cookie-2'] == 'val2', 'cookie' - def test_php_application_ini_precision(self): - self.load('ini_precision') +def test_php_application_404(): + client.load('404') - assert self.get()['headers']['X-Precision'] != '4', 'ini value default' + resp = client.get() - assert 'success' in self.conf( - {"file": "ini/php.ini"}, 'applications/ini_precision/options' - ) + assert resp['status'] == 404, '404 status' + assert re.search(r'<title>404 Not Found</title>', resp['body']), '404 body' - assert ( - self.get()['headers']['X-File'] - == f'{option.test_dir}/php/ini_precision/ini/php.ini' - ), 'ini file' - assert self.get()['headers']['X-Precision'] == '4', 'ini value' - @pytest.mark.skip('not yet') - def test_php_application_ini_admin_user(self): - self.load('ini_precision') +def test_php_application_keepalive_body(): + client.load('mirror') - assert 'error' in self.conf( - {"user": {"precision": "4"}, "admin": {"precision": "5"}}, - 'applications/ini_precision/options', - ), 'ini admin user' + assert client.get()['status'] == 200, 'init' - def test_php_application_ini_admin(self): - self.load('ini_precision') + body = '0123456789' * 500 + (resp, sock) = client.post( + headers={ + 'Host': 'localhost', + 'Connection': 'keep-alive', + }, + start=True, + body=body, + read_timeout=1, + ) - assert 'success' in self.conf( - {"file": "ini/php.ini", "admin": {"precision": "5"}}, - 'applications/ini_precision/options', - ) + assert resp['body'] == body, 'keep-alive 1' - assert ( - self.get()['headers']['X-File'] - == f'{option.test_dir}/php/ini_precision/ini/php.ini' - ), 'ini file' - assert self.get()['headers']['X-Precision'] == '5', 'ini value admin' + body = '0123456789' + resp = client.post(sock=sock, body=body) - def test_php_application_ini_user(self): - self.load('ini_precision') + assert resp['body'] == body, 'keep-alive 2' - assert 'success' in self.conf( - {"file": "ini/php.ini", "user": {"precision": "5"}}, - 'applications/ini_precision/options', - ) - assert ( - self.get()['headers']['X-File'] - == f'{option.test_dir}/php/ini_precision/ini/php.ini' - ), 'ini file' - assert self.get()['headers']['X-Precision'] == '5', 'ini value user' +def test_php_application_conditional(): + client.load('conditional') - def test_php_application_ini_user_2(self): - self.load('ini_precision') + assert re.search(r'True', client.get()['body']), 'conditional true' + assert re.search(r'False', client.post()['body']), 'conditional false' - assert 'success' in self.conf( - {"file": "ini/php.ini"}, 'applications/ini_precision/options' - ) - assert self.get()['headers']['X-Precision'] == '4', 'ini user file' +def test_php_application_get_variables(): + client.load('get_variables') - assert 'success' in self.conf( - {"precision": "5"}, 'applications/ini_precision/options/user' - ) + resp = client.get(url='/?var1=val1&var2=&var3') + assert resp['headers']['X-Var-1'] == 'val1', 'GET variables' + assert resp['headers']['X-Var-2'] == '', 'GET variables 2' + assert resp['headers']['X-Var-3'] == '', 'GET variables 3' + assert resp['headers']['X-Var-4'] == 'not set', 'GET variables 4' - assert self.get()['headers']['X-Precision'] == '5', 'ini value user' - def test_php_application_ini_set_admin(self): - self.load('ini_precision') +def test_php_application_post_variables(): + client.load('post_variables') - assert 'success' in self.conf( - {"admin": {"precision": "5"}}, 'applications/ini_precision/options' - ) + resp = client.post( + headers={ + 'Content-Type': 'application/x-www-form-urlencoded', + 'Host': 'localhost', + 'Connection': 'close', + }, + body='var1=val1&var2=', + ) + assert resp['headers']['X-Var-1'] == 'val1', 'POST variables' + assert resp['headers']['X-Var-2'] == '', 'POST variables 2' + assert resp['headers']['X-Var-3'] == 'not set', 'POST variables 3' - assert ( - self.get(url='/?precision=6')['headers']['X-Precision'] == '5' - ), 'ini set admin' - def test_php_application_ini_set_user(self): - self.load('ini_precision') +def test_php_application_cookies(): + client.load('cookies') - assert 'success' in self.conf( - {"user": {"precision": "5"}}, 'applications/ini_precision/options' - ) + resp = client.get( + headers={ + 'Cookie': 'var=val; var2=val2', + 'Host': 'localhost', + 'Connection': 'close', + } + ) - assert ( - self.get(url='/?precision=6')['headers']['X-Precision'] == '6' - ), 'ini set user' + assert resp['headers']['X-Cookie-1'] == 'val', 'cookie' + assert resp['headers']['X-Cookie-2'] == 'val2', 'cookie' - def test_php_application_ini_repeat(self): - self.load('ini_precision') - assert 'success' in self.conf( - {"user": {"precision": "5"}}, 'applications/ini_precision/options' - ) +def test_php_application_ini_precision(): + client.load('ini_precision') - assert self.get()['headers']['X-Precision'] == '5', 'ini value' + assert client.get()['headers']['X-Precision'] != '4', 'ini value default' - assert self.get()['headers']['X-Precision'] == '5', 'ini value repeat' + assert 'success' in client.conf( + {"file": "ini/php.ini"}, 'applications/ini_precision/options' + ) - def test_php_application_disable_functions_exec(self): - self.load('time_exec') + assert ( + client.get()['headers']['X-File'] + == f'{option.test_dir}/php/ini_precision/ini/php.ini' + ), 'ini file' + assert client.get()['headers']['X-Precision'] == '4', 'ini value' - self.before_disable_functions() - assert 'success' in self.conf( - {"admin": {"disable_functions": "exec"}}, - 'applications/time_exec/options', - ) +@pytest.mark.skip('not yet') +def test_php_application_ini_admin_user(): + client.load('ini_precision') - body = self.get()['body'] + assert 'error' in client.conf( + {"user": {"precision": "4"}, "admin": {"precision": "5"}}, + 'applications/ini_precision/options', + ), 'ini admin user' - assert re.search(r'time: \d+', body), 'disable_functions time' - assert not re.search(r'exec: \/\w+', body), 'disable_functions exec' - def test_php_application_disable_functions_comma(self): - self.load('time_exec') +def test_php_application_ini_admin(): + client.load('ini_precision') - self.before_disable_functions() + assert 'success' in client.conf( + {"file": "ini/php.ini", "admin": {"precision": "5"}}, + 'applications/ini_precision/options', + ) - assert 'success' in self.conf( - {"admin": {"disable_functions": "exec,time"}}, - 'applications/time_exec/options', - ) + assert ( + client.get()['headers']['X-File'] + == f'{option.test_dir}/php/ini_precision/ini/php.ini' + ), 'ini file' + assert client.get()['headers']['X-Precision'] == '5', 'ini value admin' - body = self.get()['body'] - assert not re.search(r'time: \d+', body), 'disable_functions comma time' - assert not re.search( - r'exec: \/\w+', body - ), 'disable_functions comma exec' +def test_php_application_ini_user(): + client.load('ini_precision') - def test_php_application_auth(self): - self.load('auth') + assert 'success' in client.conf( + {"file": "ini/php.ini", "user": {"precision": "5"}}, + 'applications/ini_precision/options', + ) - resp = self.get() - assert resp['status'] == 200, 'status' - assert resp['headers']['X-Digest'] == 'not set', 'digest' - assert resp['headers']['X-User'] == 'not set', 'user' - assert resp['headers']['X-Password'] == 'not set', 'password' + assert ( + client.get()['headers']['X-File'] + == f'{option.test_dir}/php/ini_precision/ini/php.ini' + ), 'ini file' + assert client.get()['headers']['X-Precision'] == '5', 'ini value user' - resp = self.get( - headers={ - 'Host': 'localhost', - 'Authorization': 'Basic dXNlcjpwYXNzd29yZA==', - 'Connection': 'close', - } - ) - assert resp['status'] == 200, 'basic status' - assert resp['headers']['X-Digest'] == 'not set', 'basic digest' - assert resp['headers']['X-User'] == 'user', 'basic user' - assert resp['headers']['X-Password'] == 'password', 'basic password' - resp = self.get( +def test_php_application_ini_user_2(): + client.load('ini_precision') + + assert 'success' in client.conf( + {"file": "ini/php.ini"}, 'applications/ini_precision/options' + ) + + assert client.get()['headers']['X-Precision'] == '4', 'ini user file' + + assert 'success' in client.conf( + {"precision": "5"}, 'applications/ini_precision/options/user' + ) + + assert client.get()['headers']['X-Precision'] == '5', 'ini value user' + + +def test_php_application_ini_set_admin(): + client.load('ini_precision') + + assert 'success' in client.conf( + {"admin": {"precision": "5"}}, 'applications/ini_precision/options' + ) + + assert ( + client.get(url='/?precision=6')['headers']['X-Precision'] == '5' + ), 'ini set admin' + + +def test_php_application_ini_set_user(): + client.load('ini_precision') + + assert 'success' in client.conf( + {"user": {"precision": "5"}}, 'applications/ini_precision/options' + ) + + assert ( + client.get(url='/?precision=6')['headers']['X-Precision'] == '6' + ), 'ini set user' + + +def test_php_application_ini_repeat(): + client.load('ini_precision') + + assert 'success' in client.conf( + {"user": {"precision": "5"}}, 'applications/ini_precision/options' + ) + + assert client.get()['headers']['X-Precision'] == '5', 'ini value' + + assert client.get()['headers']['X-Precision'] == '5', 'ini value repeat' + + +def test_php_application_disable_functions_exec(): + client.load('time_exec') + + before_disable_functions() + + assert 'success' in client.conf( + {"admin": {"disable_functions": "exec"}}, + 'applications/time_exec/options', + ) + + body = client.get()['body'] + + assert re.search(r'time: \d+', body), 'disable_functions time' + assert not re.search(r'exec: \/\w+', body), 'disable_functions exec' + + +def test_php_application_disable_functions_comma(): + client.load('time_exec') + + before_disable_functions() + + assert 'success' in client.conf( + {"admin": {"disable_functions": "exec,time"}}, + 'applications/time_exec/options', + ) + + body = client.get()['body'] + + assert not re.search(r'time: \d+', body), 'disable_functions comma time' + assert not re.search(r'exec: \/\w+', body), 'disable_functions comma exec' + + +def test_php_application_auth(): + client.load('auth') + + resp = client.get() + assert resp['status'] == 200, 'status' + assert resp['headers']['X-Digest'] == 'not set', 'digest' + assert resp['headers']['X-User'] == 'not set', 'user' + assert resp['headers']['X-Password'] == 'not set', 'password' + + resp = client.get( + headers={ + 'Host': 'localhost', + 'Authorization': 'Basic dXNlcjpwYXNzd29yZA==', + 'Connection': 'close', + } + ) + assert resp['status'] == 200, 'basic status' + assert resp['headers']['X-Digest'] == 'not set', 'basic digest' + assert resp['headers']['X-User'] == 'user', 'basic user' + assert resp['headers']['X-Password'] == 'password', 'basic password' + + resp = client.get( + headers={ + 'Host': 'localhost', + 'Authorization': 'Digest username="blah", realm="", uri="/"', + 'Connection': 'close', + } + ) + assert resp['status'] == 200, 'digest status' + assert ( + resp['headers']['X-Digest'] == 'username="blah", realm="", uri="/"' + ), 'digest digest' + assert resp['headers']['X-User'] == 'not set', 'digest user' + assert resp['headers']['X-Password'] == 'not set', 'digest password' + + +def test_php_application_auth_invalid(): + client.load('auth') + + def check_auth(auth): + resp = client.get( headers={ 'Host': 'localhost', - 'Authorization': 'Digest username="blah", realm="", uri="/"', + 'Authorization': auth, 'Connection': 'close', } ) - assert resp['status'] == 200, 'digest status' - assert ( - resp['headers']['X-Digest'] == 'username="blah", realm="", uri="/"' - ), 'digest digest' - assert resp['headers']['X-User'] == 'not set', 'digest user' - assert resp['headers']['X-Password'] == 'not set', 'digest password' - - def test_php_application_auth_invalid(self): - self.load('auth') - - def check_auth(auth): - resp = self.get( - headers={ - 'Host': 'localhost', - 'Authorization': auth, - 'Connection': 'close', - } - ) - assert resp['status'] == 200, 'status' - assert resp['headers']['X-Digest'] == 'not set', 'Digest' - assert resp['headers']['X-User'] == 'not set', 'User' - assert resp['headers']['X-Password'] == 'not set', 'Password' + assert resp['status'] == 200, 'status' + assert resp['headers']['X-Digest'] == 'not set', 'Digest' + assert resp['headers']['X-User'] == 'not set', 'User' + assert resp['headers']['X-Password'] == 'not set', 'Password' - check_auth('Basic dXN%cjpwYXNzd29yZA==') - check_auth('Basic XNlcjpwYXNzd29yZA==') - check_auth('Basic DdXNlcjpwYXNzd29yZA==') - check_auth('Basic blah') - check_auth('Basic') - check_auth('Digest') - check_auth('blah') + check_auth('Basic dXN%cjpwYXNzd29yZA==') + check_auth('Basic XNlcjpwYXNzd29yZA==') + check_auth('Basic DdXNlcjpwYXNzd29yZA==') + check_auth('Basic blah') + check_auth('Basic') + check_auth('Digest') + check_auth('blah') - def test_php_application_disable_functions_space(self): - self.load('time_exec') - self.before_disable_functions() +def test_php_application_disable_functions_space(): + client.load('time_exec') - assert 'success' in self.conf( - {"admin": {"disable_functions": "exec time"}}, - 'applications/time_exec/options', - ) + before_disable_functions() - body = self.get()['body'] + assert 'success' in client.conf( + {"admin": {"disable_functions": "exec time"}}, + 'applications/time_exec/options', + ) - assert not re.search(r'time: \d+', body), 'disable_functions space time' - assert not re.search( - r'exec: \/\w+', body - ), 'disable_functions space exec' + body = client.get()['body'] - def test_php_application_disable_functions_user(self): - self.load('time_exec') + assert not re.search(r'time: \d+', body), 'disable_functions space time' + assert not re.search(r'exec: \/\w+', body), 'disable_functions space exec' - self.before_disable_functions() - assert 'success' in self.conf( - {"user": {"disable_functions": "exec"}}, - 'applications/time_exec/options', - ) +def test_php_application_disable_functions_user(): + client.load('time_exec') - body = self.get()['body'] + before_disable_functions() - assert re.search(r'time: \d+', body), 'disable_functions user time' - assert not re.search( - r'exec: \/\w+', body - ), 'disable_functions user exec' + assert 'success' in client.conf( + {"user": {"disable_functions": "exec"}}, + 'applications/time_exec/options', + ) - def test_php_application_disable_functions_nonexistent(self): - self.load('time_exec') + body = client.get()['body'] - self.before_disable_functions() + assert re.search(r'time: \d+', body), 'disable_functions user time' + assert not re.search(r'exec: \/\w+', body), 'disable_functions user exec' - assert 'success' in self.conf( - {"admin": {"disable_functions": "blah"}}, - 'applications/time_exec/options', - ) - body = self.get()['body'] +def test_php_application_disable_functions_nonexistent(): + client.load('time_exec') - assert re.search( - r'time: \d+', body - ), 'disable_functions nonexistent time' - assert re.search( - r'exec: \/\w+', body - ), 'disable_functions nonexistent exec' + before_disable_functions() - def test_php_application_disable_classes(self): - self.load('date_time') + assert 'success' in client.conf( + {"admin": {"disable_functions": "blah"}}, + 'applications/time_exec/options', + ) - assert re.search( - r'012345', self.get()['body'] - ), 'disable_classes before' + body = client.get()['body'] - assert 'success' in self.conf( - {"admin": {"disable_classes": "DateTime"}}, - 'applications/date_time/options', - ) + assert re.search(r'time: \d+', body), 'disable_functions nonexistent time' + assert re.search(r'exec: \/\w+', body), 'disable_functions nonexistent exec' - assert not re.search( - r'012345', self.get()['body'] - ), 'disable_classes before' - def test_php_application_disable_classes_user(self): - self.load('date_time') +def test_php_application_disable_classes(): + client.load('date_time') - assert re.search( - r'012345', self.get()['body'] - ), 'disable_classes before' + assert re.search(r'012345', client.get()['body']), 'disable_classes before' - assert 'success' in self.conf( - {"user": {"disable_classes": "DateTime"}}, - 'applications/date_time/options', - ) + assert 'success' in client.conf( + {"admin": {"disable_classes": "DateTime"}}, + 'applications/date_time/options', + ) - assert not re.search( - r'012345', self.get()['body'] - ), 'disable_classes before' + assert not re.search( + r'012345', client.get()['body'] + ), 'disable_classes before' - def test_php_application_error_log(self): - self.load('error_log') - assert self.get()['status'] == 200, 'status' +def test_php_application_disable_classes_user(): + client.load('date_time') - time.sleep(1) + assert re.search(r'012345', client.get()['body']), 'disable_classes before' - assert self.get()['status'] == 200, 'status 2' + assert 'success' in client.conf( + {"user": {"disable_classes": "DateTime"}}, + 'applications/date_time/options', + ) - pattern = r'\d{4}\/\d\d\/\d\d\s\d\d:.+\[notice\].+Error in application' + assert not re.search( + r'012345', client.get()['body'] + ), 'disable_classes before' - assert self.wait_for_record(pattern) is not None, 'errors print' - errs = self.findall(pattern) +def test_php_application_error_log(findall, wait_for_record): + client.load('error_log') - assert len(errs) == 2, 'error_log count' + assert client.get()['status'] == 200, 'status' - date = errs[0].split('[')[0] - date2 = errs[1].split('[')[0] - assert date != date2, 'date diff' + time.sleep(1) - def test_php_application_script(self): - assert 'success' in self.conf( - { - "listeners": {"*:7080": {"pass": "applications/script"}}, - "applications": { - "script": { - "type": self.get_application_type(), - "processes": {"spare": 0}, - "root": f"{option.test_dir}/php/script", - "script": "phpinfo.php", - } - }, - } - ), 'configure script' + assert client.get()['status'] == 200, 'status 2' - resp = self.get() + pattern = r'\d{4}\/\d\d\/\d\d\s\d\d:.+\[notice\].+Error in application' - assert resp['status'] == 200, 'status' - assert resp['body'] != '', 'body not empty' - - def test_php_application_index_default(self): - assert 'success' in self.conf( - { - "listeners": {"*:7080": {"pass": "applications/phpinfo"}}, - "applications": { - "phpinfo": { - "type": self.get_application_type(), - "processes": {"spare": 0}, - "root": f"{option.test_dir}/php/phpinfo", - } - }, - } - ), 'configure index default' + assert wait_for_record(pattern) is not None, 'errors print' - resp = self.get() + errs = findall(pattern) - assert resp['status'] == 200, 'status' - assert resp['body'] != '', 'body not empty' - - def test_php_application_trailing_slash(self, temp_dir): - new_root = f'{temp_dir}/php-root' - os.makedirs(f'{new_root}/path') - - Path(f'{new_root}/path/index.php').write_text('<?php echo "OK\n"; ?>') - - addr = f'{temp_dir}/sock' - - assert 'success' in self.conf( - { - "listeners": { - "*:7080": {"pass": "applications/php-path"}, - f'unix:{addr}': {"pass": "applications/php-path"}, - }, - "applications": { - "php-path": { - "type": self.get_application_type(), - "processes": {"spare": 0}, - "root": new_root, - } - }, - } - ), 'configure trailing slash' + assert len(errs) == 2, 'error_log count' - assert self.get(url='/path/')['status'] == 200, 'uri with trailing /' + date = errs[0].split('[')[0] + date2 = errs[1].split('[')[0] + assert date != date2, 'date diff' - resp = self.get(url='/path?q=a') - assert resp['status'] == 301, 'uri without trailing /' - assert ( - resp['headers']['Location'] == 'http://localhost:7080/path/?q=a' - ), 'Location with query string' - resp = self.get( - sock_type='unix', - addr=addr, - url='/path', - headers={'Host': 'foo', 'Connection': 'close'}, - ) - assert resp['status'] == 301, 'uri without trailing /' - assert ( - resp['headers']['Location'] == 'http://foo/path/' - ), 'Location with custom Host over UDS' - - def test_php_application_forbidden(self, temp_dir): - new_root = f'{temp_dir}/php-root/path' - os.makedirs(new_root) - os.chmod(new_root, 0o000) - - assert 'success' in self.conf( - { - "listeners": {"*:7080": {"pass": "applications/php-path"}}, - "applications": { - "php-path": { - "type": self.get_application_type(), - "processes": {"spare": 0}, - "root": f'{temp_dir}/php-root', - } - }, - } - ), 'forbidden directory' - - assert self.get(url='/path/')['status'] == 403, 'access forbidden' - - def test_php_application_extension_check(self, temp_dir): - self.load('phpinfo') - - assert self.get(url='/index.wrong')['status'] != 200, 'status' - - new_root = f'{temp_dir}/php' - os.mkdir(new_root) - shutil.copy(f'{option.test_dir}/php/phpinfo/index.wrong', new_root) - - assert 'success' in self.conf( - { - "listeners": {"*:7080": {"pass": "applications/phpinfo"}}, - "applications": { - "phpinfo": { - "type": self.get_application_type(), - "processes": {"spare": 0}, - "root": new_root, - "working_directory": new_root, - } - }, - } - ), 'configure new root' +def test_php_application_script(): + assert 'success' in client.conf( + { + "listeners": {"*:7080": {"pass": "applications/script"}}, + "applications": { + "script": { + "type": client.get_application_type(), + "processes": {"spare": 0}, + "root": f"{option.test_dir}/php/script", + "script": "phpinfo.php", + } + }, + } + ), 'configure script' - resp = self.get() - assert f'{resp["status"]}{resp["body"]}' != '200', 'status new root' + resp = client.get() - def run_php_application_cwd_root_tests(self): - assert 'success' in self.conf_delete( - 'applications/cwd/working_directory' - ) + assert resp['status'] == 200, 'status' + assert resp['body'] != '', 'body not empty' - script_cwd = f'{option.test_dir}/php/cwd' - resp = self.get() - assert resp['status'] == 200, 'status ok' - assert resp['body'] == script_cwd, 'default cwd' +def test_php_application_index_default(): + assert 'success' in client.conf( + { + "listeners": {"*:7080": {"pass": "applications/phpinfo"}}, + "applications": { + "phpinfo": { + "type": client.get_application_type(), + "processes": {"spare": 0}, + "root": f"{option.test_dir}/php/phpinfo", + } + }, + } + ), 'configure index default' - assert 'success' in self.conf( - f'"{option.test_dir}"', - 'applications/cwd/working_directory', - ) + resp = client.get() - resp = self.get() - assert resp['status'] == 200, 'status ok' - assert resp['body'] == script_cwd, 'wdir cwd' + assert resp['status'] == 200, 'status' + assert resp['body'] != '', 'body not empty' - resp = self.get(url='/?chdir=/') - assert resp['status'] == 200, 'status ok' - assert resp['body'] == '/', 'cwd after chdir' - # cwd must be restored +def test_php_application_trailing_slash(temp_dir): + new_root = f'{temp_dir}/php-root' + os.makedirs(f'{new_root}/path') - resp = self.get() - assert resp['status'] == 200, 'status ok' - assert resp['body'] == script_cwd, 'cwd restored' + Path(f'{new_root}/path/index.php').write_text('<?php echo "OK\n"; ?>') - resp = self.get(url='/subdir/') - assert resp['body'] == f'{script_cwd}/subdir', 'cwd subdir' + addr = f'{temp_dir}/sock' - def test_php_application_cwd_root(self): - self.load('cwd') - self.run_php_application_cwd_root_tests() + assert 'success' in client.conf( + { + "listeners": { + "*:7080": {"pass": "applications/php-path"}, + f'unix:{addr}': {"pass": "applications/php-path"}, + }, + "applications": { + "php-path": { + "type": client.get_application_type(), + "processes": {"spare": 0}, + "root": new_root, + } + }, + } + ), 'configure trailing slash' + + assert client.get(url='/path/')['status'] == 200, 'uri with trailing /' + + resp = client.get(url='/path?q=a') + assert resp['status'] == 301, 'uri without trailing /' + assert ( + resp['headers']['Location'] == 'http://localhost:7080/path/?q=a' + ), 'Location with query string' + + resp = client.get( + sock_type='unix', + addr=addr, + url='/path', + headers={'Host': 'foo', 'Connection': 'close'}, + ) + assert resp['status'] == 301, 'uri without trailing /' + assert ( + resp['headers']['Location'] == 'http://foo/path/' + ), 'Location with custom Host over UDS' + + +def test_php_application_forbidden(temp_dir): + new_root = f'{temp_dir}/php-root/path' + os.makedirs(new_root) + os.chmod(new_root, 0o000) + + assert 'success' in client.conf( + { + "listeners": {"*:7080": {"pass": "applications/php-path"}}, + "applications": { + "php-path": { + "type": client.get_application_type(), + "processes": {"spare": 0}, + "root": f'{temp_dir}/php-root', + } + }, + } + ), 'forbidden directory' - def test_php_application_cwd_opcache_disabled(self): - self.load('cwd') - self.set_opcache('cwd', '0') - self.run_php_application_cwd_root_tests() + assert client.get(url='/path/')['status'] == 403, 'access forbidden' - def test_php_application_cwd_opcache_enabled(self): - self.load('cwd') - self.set_opcache('cwd', '1') - self.run_php_application_cwd_root_tests() - def run_php_application_cwd_script_tests(self): - self.load('cwd') +def test_php_application_extension_check(temp_dir): + client.load('phpinfo') - script_cwd = f'{option.test_dir}/php/cwd' + assert client.get(url='/index.wrong')['status'] != 200, 'status' + + new_root = f'{temp_dir}/php' + os.mkdir(new_root) + shutil.copy(f'{option.test_dir}/php/phpinfo/index.wrong', new_root) + + assert 'success' in client.conf( + { + "listeners": {"*:7080": {"pass": "applications/phpinfo"}}, + "applications": { + "phpinfo": { + "type": client.get_application_type(), + "processes": {"spare": 0}, + "root": new_root, + "working_directory": new_root, + } + }, + } + ), 'configure new root' + + resp = client.get() + assert f'{resp["status"]}{resp["body"]}' != '200', 'status new root' + + +def test_php_application_cwd_root(): + client.load('cwd') + run_php_application_cwd_root_tests() + + +def test_php_application_cwd_opcache_disabled(): + client.load('cwd') + set_opcache('cwd', '0') + run_php_application_cwd_root_tests() + + +def test_php_application_cwd_opcache_enabled(): + client.load('cwd') + set_opcache('cwd', '1') + run_php_application_cwd_root_tests() + + +def test_php_application_cwd_script(): + client.load('cwd') + run_php_application_cwd_script_tests() - assert 'success' in self.conf_delete( - 'applications/cwd/working_directory' - ) - assert 'success' in self.conf('"index.php"', 'applications/cwd/script') +def test_php_application_cwd_script_opcache_disabled(): + client.load('cwd') + set_opcache('cwd', '0') + run_php_application_cwd_script_tests() - assert self.get()['body'] == script_cwd, 'default cwd' - assert self.get(url='/?chdir=/')['body'] == '/', 'cwd after chdir' +def test_php_application_cwd_script_opcache_enabled(): + client.load('cwd') + set_opcache('cwd', '1') + run_php_application_cwd_script_tests() - # cwd must be restored - assert self.get()['body'] == script_cwd, 'cwd restored' - def test_php_application_cwd_script(self): - self.load('cwd') - self.run_php_application_cwd_script_tests() +def test_php_application_path_relative(): + client.load('open') - def test_php_application_cwd_script_opcache_disabled(self): - self.load('cwd') - self.set_opcache('cwd', '0') - self.run_php_application_cwd_script_tests() + assert client.get()['body'] == 'test', 'relative path' - def test_php_application_cwd_script_opcache_enabled(self): - self.load('cwd') - self.set_opcache('cwd', '1') - self.run_php_application_cwd_script_tests() + assert ( + client.get(url='/?chdir=/')['body'] != 'test' + ), 'relative path w/ chdir' - def test_php_application_path_relative(self): - self.load('open') + assert client.get()['body'] == 'test', 'relative path 2' - assert self.get()['body'] == 'test', 'relative path' - assert ( - self.get(url='/?chdir=/')['body'] != 'test' - ), 'relative path w/ chdir' +def test_php_application_shared_opcache(): + client.load('opcache', limits={'requests': 1}) - assert self.get()['body'] == 'test', 'relative path 2' + r = check_opcache() + pid = r['headers']['X-Pid'] + assert r['headers']['X-Cached'] == '0', 'not cached' - def test_php_application_shared_opcache(self): - self.load('opcache', limits={'requests': 1}) + r = client.get() - r = self.check_opcache() - pid = r['headers']['X-Pid'] - assert r['headers']['X-Cached'] == '0', 'not cached' + assert r['headers']['X-Pid'] != pid, 'new instance' + assert r['headers']['X-Cached'] == '1', 'cached' - r = self.get() - assert r['headers']['X-Pid'] != pid, 'new instance' - assert r['headers']['X-Cached'] == '1', 'cached' +def test_php_application_opcache_preload_chdir(): + client.load('opcache') - def test_php_application_opcache_preload_chdir(self, temp_dir): - self.load('opcache') + check_opcache() - self.check_opcache() + set_preload('chdir.php') - self.set_preload('chdir.php') + assert client.get()['headers']['X-Cached'] == '0', 'not cached' + assert client.get()['headers']['X-Cached'] == '1', 'cached' - assert self.get()['headers']['X-Cached'] == '0', 'not cached' - assert self.get()['headers']['X-Cached'] == '1', 'cached' - def test_php_application_opcache_preload_ffr(self, temp_dir): - self.load('opcache') +def test_php_application_opcache_preload_ffr(): + client.load('opcache') - self.check_opcache() + check_opcache() - self.set_preload('fastcgi_finish_request.php') + set_preload('fastcgi_finish_request.php') - assert self.get()['headers']['X-Cached'] == '0', 'not cached' - assert self.get()['headers']['X-Cached'] == '1', 'cached' + assert client.get()['headers']['X-Cached'] == '0', 'not cached' + assert client.get()['headers']['X-Cached'] == '1', 'cached' |