xref: /unit/test/test_php_application.py (revision 1367:dd5d155c2685)
1import os
2import re
3import shutil
4import unittest
5from unit.applications.lang.php import TestApplicationPHP
6
7class TestPHPApplication(TestApplicationPHP):
8    prerequisites = {'modules': ['php']}
9
10    def before_disable_functions(self):
11        body = self.get()['body']
12
13        self.assertRegex(body, r'time: \d+', 'disable_functions before time')
14        self.assertRegex(body, r'exec: \/\w+', 'disable_functions before exec')
15
16    def test_php_application_variables(self):
17        self.load('variables')
18
19        body = 'Test body string.'
20
21        resp = self.post(
22            headers={
23                'Host': 'localhost',
24                'Content-Type': 'text/html',
25                'Custom-Header': 'blah',
26                'Connection': 'close',
27            },
28            body=body,
29            url='/index.php/blah?var=val'
30        )
31
32        self.assertEqual(resp['status'], 200, 'status')
33        headers = resp['headers']
34        header_server = headers.pop('Server')
35        self.assertRegex(header_server, r'Unit/[\d\.]+', 'server header')
36        self.assertEqual(
37            headers.pop('Server-Software'),
38            header_server,
39            'server software header',
40        )
41
42        date = headers.pop('Date')
43        self.assertEqual(date[-4:], ' GMT', 'date header timezone')
44        self.assertLess(
45            abs(self.date_to_sec_epoch(date) - self.sec_epoch()),
46            5,
47            'date header',
48        )
49
50        if 'X-Powered-By' in headers:
51            headers.pop('X-Powered-By')
52
53        headers.pop('Content-type')
54        self.assertDictEqual(
55            headers,
56            {
57                'Connection': 'close',
58                'Content-Length': str(len(body)),
59                'Request-Method': 'POST',
60                'Path-Info': '/blah',
61                'Request-Uri': '/index.php/blah?var=val',
62                'Http-Host': 'localhost',
63                'Server-Protocol': 'HTTP/1.1',
64                'Custom-Header': 'blah',
65            },
66            'headers',
67        )
68        self.assertEqual(resp['body'], body, 'body')
69
70    def test_php_application_query_string(self):
71        self.load('query_string')
72
73        resp = self.get(url='/?var1=val1&var2=val2')
74
75        self.assertEqual(
76            resp['headers']['Query-String'],
77            'var1=val1&var2=val2',
78            'query string',
79        )
80
81    def test_php_application_query_string_empty(self):
82        self.load('query_string')
83
84        resp = self.get(url='/?')
85
86        self.assertEqual(resp['status'], 200, 'query string empty status')
87        self.assertEqual(
88            resp['headers']['Query-String'], '', 'query string empty'
89        )
90
91    def test_php_application_query_string_absent(self):
92        self.load('query_string')
93
94        resp = self.get()
95
96        self.assertEqual(resp['status'], 200, 'query string absent status')
97        self.assertEqual(
98            resp['headers']['Query-String'], '', 'query string absent'
99        )
100
101    def test_php_application_phpinfo(self):
102        self.load('phpinfo')
103
104        resp = self.get()
105
106        self.assertEqual(resp['status'], 200, 'status')
107        self.assertNotEqual(resp['body'], '', 'body not empty')
108
109    def test_php_application_header_status(self):
110        self.load('header')
111
112        self.assertEqual(
113            self.get(
114                headers={
115                    'Host': 'localhost',
116                    'Connection': 'close',
117                    'X-Header': 'HTTP/1.1 404 Not Found',
118                }
119            )['status'],
120            404,
121            'status',
122        )
123
124        self.assertEqual(
125            self.get(
126                headers={
127                    'Host': 'localhost',
128                    'Connection': 'close',
129                    'X-Header': 'http/1.1 404 Not Found',
130                }
131            )['status'],
132            404,
133            'status case insensitive',
134        )
135
136        self.assertEqual(
137            self.get(
138                headers={
139                    'Host': 'localhost',
140                    'Connection': 'close',
141                    'X-Header': 'HTTP/ 404 Not Found',
142                }
143            )['status'],
144            404,
145            'status version empty',
146        )
147
148
149    def test_php_application_404(self):
150        self.load('404')
151
152        resp = self.get()
153
154        self.assertEqual(resp['status'], 404, '404 status')
155        self.assertRegex(
156            resp['body'], r'<title>404 Not Found</title>', '404 body'
157        )
158
159    def test_php_application_keepalive_body(self):
160        self.load('mirror')
161
162        self.assertEqual(self.get()['status'], 200, 'init')
163
164        (resp, sock) = self.post(
165            headers={
166                'Host': 'localhost',
167                'Connection': 'keep-alive',
168                'Content-Type': 'text/html',
169            },
170            start=True,
171            body='0123456789' * 500,
172            read_timeout=1,
173        )
174
175        self.assertEqual(resp['body'], '0123456789' * 500, 'keep-alive 1')
176
177        resp = self.post(
178            headers={
179                'Host': 'localhost',
180                'Connection': 'close',
181                'Content-Type': 'text/html',
182            },
183            sock=sock,
184            body='0123456789',
185        )
186
187        self.assertEqual(resp['body'], '0123456789', 'keep-alive 2')
188
189    def test_php_application_conditional(self):
190        self.load('conditional')
191
192        self.assertRegex(self.get()['body'], r'True', 'conditional true')
193        self.assertRegex(self.post()['body'], r'False', 'conditional false')
194
195    def test_php_application_get_variables(self):
196        self.load('get_variables')
197
198        resp = self.get(url='/?var1=val1&var2=&var3')
199        self.assertEqual(resp['headers']['X-Var-1'], 'val1', 'GET variables')
200        self.assertEqual(resp['headers']['X-Var-2'], '1', 'GET variables 2')
201        self.assertEqual(resp['headers']['X-Var-3'], '1', 'GET variables 3')
202        self.assertEqual(resp['headers']['X-Var-4'], '', 'GET variables 4')
203
204    def test_php_application_post_variables(self):
205        self.load('post_variables')
206
207        resp = self.post(
208            headers={
209                'Content-Type': 'application/x-www-form-urlencoded',
210                'Host': 'localhost',
211                'Connection': 'close',
212            },
213            body='var1=val1&var2=',
214        )
215        self.assertEqual(resp['headers']['X-Var-1'], 'val1', 'POST variables')
216        self.assertEqual(resp['headers']['X-Var-2'], '1', 'POST variables 2')
217        self.assertEqual(resp['headers']['X-Var-3'], '', 'POST variables 3')
218
219    def test_php_application_cookies(self):
220        self.load('cookies')
221
222        resp = self.get(
223            headers={
224                'Cookie': 'var=val; var2=val2',
225                'Host': 'localhost',
226                'Connection': 'close',
227            }
228        )
229
230        self.assertEqual(resp['headers']['X-Cookie-1'], 'val', 'cookie')
231        self.assertEqual(resp['headers']['X-Cookie-2'], 'val2', 'cookie')
232
233    def test_php_application_ini_precision(self):
234        self.load('ini_precision')
235
236        self.assertNotEqual(
237            self.get()['headers']['X-Precision'], '4', 'ini value default'
238        )
239
240        self.conf(
241            {"file": "ini/php.ini"}, 'applications/ini_precision/options'
242        )
243
244        self.assertEqual(
245            self.get()['headers']['X-File'],
246            self.current_dir + '/php/ini_precision/ini/php.ini',
247            'ini file',
248        )
249        self.assertEqual(
250            self.get()['headers']['X-Precision'], '4', 'ini value'
251        )
252
253    @unittest.skip('not yet')
254    def test_php_application_ini_admin_user(self):
255        self.load('ini_precision')
256
257        self.assertIn(
258            'error',
259            self.conf(
260                {"user": {"precision": "4"}, "admin": {"precision": "5"}},
261                'applications/ini_precision/options',
262            ),
263            'ini admin user',
264        )
265
266    def test_php_application_ini_admin(self):
267        self.load('ini_precision')
268
269        self.conf(
270            {"file": "php.ini", "admin": {"precision": "5"}},
271            'applications/ini_precision/options',
272        )
273
274        self.assertEqual(
275            self.get()['headers']['X-Precision'], '5', 'ini value admin'
276        )
277
278    def test_php_application_ini_user(self):
279        self.load('ini_precision')
280
281        self.conf(
282            {"file": "php.ini", "user": {"precision": "5"}},
283            'applications/ini_precision/options',
284        )
285
286        self.assertEqual(
287            self.get()['headers']['X-Precision'], '5', 'ini value user'
288        )
289
290    def test_php_application_ini_user_2(self):
291        self.load('ini_precision')
292
293        self.conf(
294            {"file": "ini/php.ini"}, 'applications/ini_precision/options'
295        )
296
297        self.assertEqual(
298            self.get()['headers']['X-Precision'], '4', 'ini user file'
299        )
300
301        self.conf(
302            {"precision": "5"}, 'applications/ini_precision/options/user'
303        )
304
305        self.assertEqual(
306            self.get()['headers']['X-Precision'], '5', 'ini value user'
307        )
308
309    def test_php_application_ini_set_admin(self):
310        self.load('ini_precision')
311
312        self.conf(
313            {"admin": {"precision": "5"}}, 'applications/ini_precision/options'
314        )
315
316        self.assertEqual(
317            self.get(url='/?precision=6')['headers']['X-Precision'],
318            '5',
319            'ini set admin',
320        )
321
322    def test_php_application_ini_set_user(self):
323        self.load('ini_precision')
324
325        self.conf(
326            {"user": {"precision": "5"}}, 'applications/ini_precision/options'
327        )
328
329        self.assertEqual(
330            self.get(url='/?precision=6')['headers']['X-Precision'],
331            '6',
332            'ini set user',
333        )
334
335    def test_php_application_ini_repeat(self):
336        self.load('ini_precision')
337
338        self.conf(
339            {"user": {"precision": "5"}}, 'applications/ini_precision/options'
340        )
341
342        self.assertEqual(
343            self.get()['headers']['X-Precision'], '5', 'ini value'
344        )
345
346        self.assertEqual(
347            self.get()['headers']['X-Precision'], '5', 'ini value repeat'
348        )
349
350    def test_php_application_disable_functions_exec(self):
351        self.load('time_exec')
352
353        self.before_disable_functions()
354
355        self.conf(
356            {"admin": {"disable_functions": "exec"}},
357            'applications/time_exec/options',
358        )
359
360        body = self.get()['body']
361
362        self.assertRegex(body, r'time: \d+', 'disable_functions time')
363        self.assertNotRegex(body, r'exec: \/\w+', 'disable_functions exec')
364
365    def test_php_application_disable_functions_comma(self):
366        self.load('time_exec')
367
368        self.before_disable_functions()
369
370        self.conf(
371            {"admin": {"disable_functions": "exec,time"}},
372            'applications/time_exec/options',
373        )
374
375        body = self.get()['body']
376
377        self.assertNotRegex(body, r'time: \d+', 'disable_functions comma time')
378        self.assertNotRegex(
379            body, r'exec: \/\w+', 'disable_functions comma exec'
380        )
381
382    def test_php_application_disable_functions_space(self):
383        self.load('time_exec')
384
385        self.before_disable_functions()
386
387        self.conf(
388            {"admin": {"disable_functions": "exec time"}},
389            'applications/time_exec/options',
390        )
391
392        body = self.get()['body']
393
394        self.assertNotRegex(body, r'time: \d+', 'disable_functions space time')
395        self.assertNotRegex(
396            body, r'exec: \/\w+', 'disable_functions space exec'
397        )
398
399    def test_php_application_disable_functions_user(self):
400        self.load('time_exec')
401
402        self.before_disable_functions()
403
404        self.conf(
405            {"user": {"disable_functions": "exec"}},
406            'applications/time_exec/options',
407        )
408
409        body = self.get()['body']
410
411        self.assertRegex(body, r'time: \d+', 'disable_functions user time')
412        self.assertNotRegex(
413            body, r'exec: \/\w+', 'disable_functions user exec'
414        )
415
416    def test_php_application_disable_functions_nonexistent(self):
417        self.load('time_exec')
418
419        self.before_disable_functions()
420
421        self.conf(
422            {"admin": {"disable_functions": "blah"}},
423            'applications/time_exec/options',
424        )
425
426        body = self.get()['body']
427
428        self.assertRegex(
429            body, r'time: \d+', 'disable_functions nonexistent time'
430        )
431        self.assertRegex(
432            body, r'exec: \/\w+', 'disable_functions nonexistent exec'
433        )
434
435    def test_php_application_disable_classes(self):
436        self.load('date_time')
437
438        self.assertRegex(
439            self.get()['body'], r'012345', 'disable_classes before'
440        )
441
442        self.conf(
443            {"admin": {"disable_classes": "DateTime"}},
444            'applications/date_time/options',
445        )
446
447        self.assertNotRegex(
448            self.get()['body'], r'012345', 'disable_classes before'
449        )
450
451    def test_php_application_disable_classes_user(self):
452        self.load('date_time')
453
454        self.assertRegex(
455            self.get()['body'], r'012345', 'disable_classes before'
456        )
457
458        self.conf(
459            {"user": {"disable_classes": "DateTime"}},
460            'applications/date_time/options',
461        )
462
463        self.assertNotRegex(
464            self.get()['body'], r'012345', 'disable_classes before'
465        )
466
467    def test_php_application_script(self):
468        self.assertIn(
469            'success', self.conf(
470                {
471                    "listeners": {"*:7080": {"pass": "applications/script"}},
472                    "applications": {
473                        "script": {
474                            "type": "php",
475                            "processes": {"spare": 0},
476                            "root": self.current_dir + "/php/script",
477                            "script": "phpinfo.php",
478                        }
479                    },
480                }
481            ), 'configure script'
482        )
483
484        resp = self.get()
485
486        self.assertEqual(resp['status'], 200, 'status')
487        self.assertNotEqual(resp['body'], '', 'body not empty')
488
489    def test_php_application_index_default(self):
490        self.assertIn(
491            'success', self.conf(
492                {
493                    "listeners": {"*:7080": {"pass": "applications/phpinfo"}},
494                    "applications": {
495                        "phpinfo": {
496                            "type": "php",
497                            "processes": {"spare": 0},
498                            "root": self.current_dir + "/php/phpinfo",
499                        }
500                    },
501                }
502            ), 'configure index default'
503        )
504
505        resp = self.get()
506
507        self.assertEqual(resp['status'], 200, 'status')
508        self.assertNotEqual(resp['body'], '', 'body not empty')
509
510    def test_php_application_extension_check(self):
511        self.load('phpinfo')
512
513        self.assertNotEqual(
514            self.get(url='/index.wrong')['status'], 200, 'status'
515        )
516
517        new_root = self.testdir + "/php"
518        os.mkdir(new_root)
519        shutil.copy(self.current_dir + '/php/phpinfo/index.wrong', new_root)
520
521        self.assertIn(
522            'success',
523            self.conf(
524                {
525                    "listeners": {"*:7080": {"pass": "applications/phpinfo"}},
526                    "applications": {
527                        "phpinfo": {
528                            "type": "php",
529                            "processes": {"spare": 0},
530                            "root": new_root,
531                            "working_directory": new_root,
532                        }
533                    },
534                }
535            ),
536            'configure new root',
537        )
538
539        resp = self.get()
540        self.assertNotEqual(
541            str(resp['status']) + resp['body'], '200', 'status new root'
542        )
543
544
545if __name__ == '__main__':
546    TestPHPApplication.main()
547