xref: /unit/test/test_java_application.py (revision 2616:ab2896c980ab)
1import io
2import re
3import time
4from pathlib import Path
5
6from unit.applications.lang.java import ApplicationJava
7from unit.option import option
8from unit.utils import public_dir
9
10prerequisites = {'modules': {'java': 'all'}}
11
12client = ApplicationJava()
13
14
15def test_java_conf_error(temp_dir, skip_alert):
16    skip_alert(
17        r'realpath.*failed',
18        r'failed to apply new conf',
19        r'application setup failed',
20    )
21    assert 'error' in client.conf(
22        {
23            "listeners": {"*:8080": {"pass": "applications/app"}},
24            "applications": {
25                "app": {
26                    "type": client.get_application_type(),
27                    "processes": 1,
28                    "working_directory": f"{option.test_dir}/java/empty",
29                    "webapp": f"{temp_dir}/java",
30                    "unit_jars": f"{temp_dir}/no_such_dir",
31                }
32            },
33        }
34    ), 'conf error'
35
36
37def test_java_war(temp_dir):
38    client.load('empty_war')
39
40    assert 'success' in client.conf(
41        f'"{temp_dir}/java/empty.war"',
42        '/config/applications/empty_war/webapp',
43    ), 'configure war'
44
45    assert client.get()['status'] == 200, 'war'
46
47
48def test_java_application_cookies():
49    client.load('cookies')
50
51    headers = client.get(
52        headers={
53            'Cookie': 'var1=val1; var2=val2',
54            'Host': 'localhost',
55            'Connection': 'close',
56        }
57    )['headers']
58
59    assert headers['X-Cookie-1'] == 'val1', 'cookie 1'
60    assert headers['X-Cookie-2'] == 'val2', 'cookie 2'
61
62
63def test_java_application_filter():
64    client.load('filter')
65
66    headers = client.get()['headers']
67
68    assert headers['X-Filter-Before'] == '1', 'filter before'
69    assert headers['X-Filter-After'] == '1', 'filter after'
70
71    assert (
72        client.get(url='/test')['headers']['X-Filter-After'] == '0'
73    ), 'filter after 2'
74
75
76def test_java_application_get_variables():
77    client.load('get_params')
78
79    def check_header(header, expect):
80        values = header.split(' ')[:-1]
81        assert len(values) == len(expect)
82        assert set(values) == set(expect)
83
84    headers = client.get(url='/?var1=val1&var2=&var4=val4&var4=foo')['headers']
85
86    assert headers['X-Var-1'] == 'val1', 'GET variables'
87    assert headers['X-Var-2'] == 'true', 'GET variables 2'
88    assert headers['X-Var-3'] == 'false', 'GET variables 3'
89
90    check_header(headers['X-Param-Names'], ['var4', 'var2', 'var1'])
91    check_header(headers['X-Param-Values'], ['val4', 'foo'])
92    check_header(
93        headers['X-Param-Map'], ['var2=', 'var1=val1', 'var4=val4,foo']
94    )
95
96
97def test_java_application_post_variables():
98    client.load('post_params')
99
100    headers = client.post(
101        headers={
102            'Content-Type': 'application/x-www-form-urlencoded',
103            'Host': 'localhost',
104            'Connection': 'close',
105        },
106        body='var1=val1&var2=',
107    )['headers']
108
109    assert headers['X-Var-1'] == 'val1', 'POST variables'
110    assert headers['X-Var-2'] == 'true', 'POST variables 2'
111    assert headers['X-Var-3'] == 'false', 'POST variables 3'
112
113
114def test_java_application_session():
115    client.load('session')
116
117    headers = client.get(url='/?var1=val1')['headers']
118    session_id = headers['X-Session-Id']
119
120    assert headers['X-Var-1'] == 'null', 'variable empty'
121    assert headers['X-Session-New'] == 'true', 'session create'
122
123    headers = client.get(
124        headers={
125            'Host': 'localhost',
126            'Cookie': f'JSESSIONID={session_id}',
127            'Connection': 'close',
128        },
129        url='/?var1=val2',
130    )['headers']
131
132    assert headers['X-Var-1'] == 'val1', 'variable'
133    assert headers['X-Session-New'] == 'false', 'session resume'
134    assert session_id == headers['X-Session-Id'], 'session same id'
135
136
137def test_java_application_session_active(date_to_sec_epoch, sec_epoch):
138    client.load('session_inactive')
139
140    resp = client.get(
141        headers={
142            'X-Interval': '4',
143            'Host': 'localhost',
144            'Connection': 'close',
145        }
146    )
147    session_id = resp['headers']['X-Session-Id']
148
149    assert resp['status'] == 200, 'session init'
150    assert resp['headers']['X-Session-Interval'] == '4', 'session interval'
151    assert (
152        abs(
153            date_to_sec_epoch(resp['headers']['X-Session-Last-Access-Time'])
154            - sec_epoch
155        )
156        < 5
157    ), 'session last access time'
158
159    time.sleep(1)
160
161    resp = client.get(
162        headers={
163            'Host': 'localhost',
164            'Cookie': f'JSESSIONID={session_id}',
165            'Connection': 'close',
166        }
167    )
168
169    assert resp['headers']['X-Session-Id'] == session_id, 'session active'
170
171    session_id = resp['headers']['X-Session-Id']
172
173    time.sleep(1)
174
175    resp = client.get(
176        headers={
177            'Host': 'localhost',
178            'Cookie': f'JSESSIONID={session_id}',
179            'Connection': 'close',
180        }
181    )
182
183    assert resp['headers']['X-Session-Id'] == session_id, 'session active 2'
184
185    time.sleep(2)
186
187    resp = client.get(
188        headers={
189            'Host': 'localhost',
190            'Cookie': f'JSESSIONID={session_id}',
191            'Connection': 'close',
192        }
193    )
194
195    assert resp['headers']['X-Session-Id'] == session_id, 'session active 3'
196
197
198def test_java_application_session_inactive():
199    client.load('session_inactive')
200
201    resp = client.get(
202        headers={
203            'X-Interval': '1',
204            'Host': 'localhost',
205            'Connection': 'close',
206        }
207    )
208    session_id = resp['headers']['X-Session-Id']
209
210    time.sleep(3)
211
212    resp = client.get(
213        headers={
214            'Host': 'localhost',
215            'Cookie': f'JSESSIONID={session_id}',
216            'Connection': 'close',
217        }
218    )
219
220    assert resp['headers']['X-Session-Id'] != session_id, 'session inactive'
221
222
223def test_java_application_session_invalidate():
224    client.load('session_invalidate')
225
226    resp = client.get()
227    session_id = resp['headers']['X-Session-Id']
228
229    resp = client.get(
230        headers={
231            'Host': 'localhost',
232            'Cookie': f'JSESSIONID={session_id}',
233            'Connection': 'close',
234        }
235    )
236
237    assert resp['headers']['X-Session-Id'] != session_id, 'session invalidate'
238
239
240def test_java_application_session_listeners():
241    client.load('session_listeners')
242
243    headers = client.get(url='/test?var1=val1')['headers']
244    session_id = headers['X-Session-Id']
245
246    assert headers['X-Session-Created'] == session_id, 'session create'
247    assert headers['X-Attr-Added'] == 'var1=val1', 'attribute add'
248
249    headers = client.get(
250        headers={
251            'Host': 'localhost',
252            'Cookie': f'JSESSIONID={session_id}',
253            'Connection': 'close',
254        },
255        url='/?var1=val2',
256    )['headers']
257
258    assert session_id == headers['X-Session-Id'], 'session same id'
259    assert headers['X-Attr-Replaced'] == 'var1=val1', 'attribute replace'
260
261    headers = client.get(
262        headers={
263            'Host': 'localhost',
264            'Cookie': f'JSESSIONID={session_id}',
265            'Connection': 'close',
266        },
267        url='/',
268    )['headers']
269
270    assert session_id == headers['X-Session-Id'], 'session same id'
271    assert headers['X-Attr-Removed'] == 'var1=val2', 'attribute remove'
272
273
274def test_java_application_jsp():
275    client.load('jsp')
276
277    headers = client.get(url='/index.jsp')['headers']
278
279    assert headers['X-Unit-JSP'] == 'ok', 'JSP Ok header'
280
281
282def test_java_application_url_pattern():
283    client.load('url_pattern')
284
285    headers = client.get(url='/foo/bar/index.html')['headers']
286
287    assert headers['X-Id'] == 'servlet1', '#1 Servlet1 request'
288    assert headers['X-Request-URI'] == '/foo/bar/index.html', '#1 request URI'
289    assert headers['X-Servlet-Path'] == '/foo/bar', '#1 servlet path'
290    assert headers['X-Path-Info'] == '/index.html', '#1 path info'
291
292    headers = client.get(url='/foo/bar/index.bop')['headers']
293
294    assert headers['X-Id'] == 'servlet1', '#2 Servlet1 request'
295    assert headers['X-Request-URI'] == '/foo/bar/index.bop', '#2 request URI'
296    assert headers['X-Servlet-Path'] == '/foo/bar', '#2 servlet path'
297    assert headers['X-Path-Info'] == '/index.bop', '#2 path info'
298
299    headers = client.get(url='/baz')['headers']
300
301    assert headers['X-Id'] == 'servlet2', '#3 Servlet2 request'
302    assert headers['X-Request-URI'] == '/baz', '#3 request URI'
303    assert headers['X-Servlet-Path'] == '/baz', '#3 servlet path'
304    assert headers['X-Path-Info'] == 'null', '#3 path info'
305
306    headers = client.get(url='/baz/index.html')['headers']
307
308    assert headers['X-Id'] == 'servlet2', '#4 Servlet2 request'
309    assert headers['X-Request-URI'] == '/baz/index.html', '#4 request URI'
310    assert headers['X-Servlet-Path'] == '/baz', '#4 servlet path'
311    assert headers['X-Path-Info'] == '/index.html', '#4 path info'
312
313    headers = client.get(url='/catalog')['headers']
314
315    assert headers['X-Id'] == 'servlet3', '#5 Servlet3 request'
316    assert headers['X-Request-URI'] == '/catalog', '#5 request URI'
317    assert headers['X-Servlet-Path'] == '/catalog', '#5 servlet path'
318    assert headers['X-Path-Info'] == 'null', '#5 path info'
319
320    headers = client.get(url='/catalog/index.html')['headers']
321
322    assert headers['X-Id'] == 'default', '#6 default request'
323    assert headers['X-Request-URI'] == '/catalog/index.html', '#6 request URI'
324    assert headers['X-Servlet-Path'] == '/catalog/index.html', '#6 servlet path'
325    assert headers['X-Path-Info'] == 'null', '#6 path info'
326
327    headers = client.get(url='/catalog/racecar.bop')['headers']
328
329    assert headers['X-Id'] == 'servlet4', '#7 servlet4 request'
330    assert headers['X-Request-URI'] == '/catalog/racecar.bop', '#7 request URI'
331    assert (
332        headers['X-Servlet-Path'] == '/catalog/racecar.bop'
333    ), '#7 servlet path'
334    assert headers['X-Path-Info'] == 'null', '#7 path info'
335
336    headers = client.get(url='/index.bop')['headers']
337
338    assert headers['X-Id'] == 'servlet4', '#8 servlet4 request'
339    assert headers['X-Request-URI'] == '/index.bop', '#8 request URI'
340    assert headers['X-Servlet-Path'] == '/index.bop', '#8 servlet path'
341    assert headers['X-Path-Info'] == 'null', '#8 path info'
342
343    headers = client.get(url='/foo/baz')['headers']
344
345    assert headers['X-Id'] == 'servlet0', '#9 servlet0 request'
346    assert headers['X-Request-URI'] == '/foo/baz', '#9 request URI'
347    assert headers['X-Servlet-Path'] == '/foo', '#9 servlet path'
348    assert headers['X-Path-Info'] == '/baz', '#9 path info'
349
350    headers = client.get()['headers']
351
352    assert headers['X-Id'] == 'default', '#10 default request'
353    assert headers['X-Request-URI'] == '/', '#10 request URI'
354    assert headers['X-Servlet-Path'] == '/', '#10 servlet path'
355    assert headers['X-Path-Info'] == 'null', '#10 path info'
356
357    headers = client.get(url='/index.bop/')['headers']
358
359    assert headers['X-Id'] == 'default', '#11 default request'
360    assert headers['X-Request-URI'] == '/index.bop/', '#11 request URI'
361    assert headers['X-Servlet-Path'] == '/index.bop/', '#11 servlet path'
362    assert headers['X-Path-Info'] == 'null', '#11 path info'
363
364
365def test_java_application_header():
366    client.load('header')
367
368    headers = client.get()['headers']
369
370    assert headers['X-Set-Utf8-Value'] == '????', 'set Utf8 header value'
371    assert headers['X-Set-Utf8-Name-???'] == 'x', 'set Utf8 header name'
372    assert headers['X-Add-Utf8-Value'] == '????', 'add Utf8 header value'
373    assert headers['X-Add-Utf8-Name-???'] == 'y', 'add Utf8 header name'
374    assert headers['X-Add-Test'] == 'v1', 'add null header'
375    assert 'X-Set-Test1' not in headers, 'set null header'
376    assert headers['X-Set-Test2'] == '', 'set empty header'
377
378
379def test_java_application_content_type():
380    client.load('content_type')
381
382    headers = client.get(url='/1')['headers']
383
384    assert (
385        headers['Content-Type'] == 'text/plain;charset=utf-8'
386    ), '#1 Content-Type header'
387    assert (
388        headers['X-Content-Type'] == 'text/plain;charset=utf-8'
389    ), '#1 response Content-Type'
390    assert headers['X-Character-Encoding'] == 'utf-8', '#1 response charset'
391
392    headers = client.get(url='/2')['headers']
393
394    assert (
395        headers['Content-Type'] == 'text/plain;charset=iso-8859-1'
396    ), '#2 Content-Type header'
397    assert (
398        headers['X-Content-Type'] == 'text/plain;charset=iso-8859-1'
399    ), '#2 response Content-Type'
400    assert (
401        headers['X-Character-Encoding'] == 'iso-8859-1'
402    ), '#2 response charset'
403
404    headers = client.get(url='/3')['headers']
405
406    assert (
407        headers['Content-Type'] == 'text/plain;charset=windows-1251'
408    ), '#3 Content-Type header'
409    assert (
410        headers['X-Content-Type'] == 'text/plain;charset=windows-1251'
411    ), '#3 response Content-Type'
412    assert (
413        headers['X-Character-Encoding'] == 'windows-1251'
414    ), '#3 response charset'
415
416    headers = client.get(url='/4')['headers']
417
418    assert (
419        headers['Content-Type'] == 'text/plain;charset=windows-1251'
420    ), '#4 Content-Type header'
421    assert (
422        headers['X-Content-Type'] == 'text/plain;charset=windows-1251'
423    ), '#4 response Content-Type'
424    assert (
425        headers['X-Character-Encoding'] == 'windows-1251'
426    ), '#4 response charset'
427
428    headers = client.get(url='/5')['headers']
429
430    assert (
431        headers['Content-Type'] == 'text/plain;charset=iso-8859-1'
432    ), '#5 Content-Type header'
433    assert (
434        headers['X-Content-Type'] == 'text/plain;charset=iso-8859-1'
435    ), '#5 response Content-Type'
436    assert (
437        headers['X-Character-Encoding'] == 'iso-8859-1'
438    ), '#5 response charset'
439
440    headers = client.get(url='/6')['headers']
441
442    assert 'Content-Type' not in headers, '#6 no Content-Type header'
443    assert 'X-Content-Type' not in headers, '#6 no response Content-Type'
444    assert headers['X-Character-Encoding'] == 'utf-8', '#6 response charset'
445
446    headers = client.get(url='/7')['headers']
447
448    assert (
449        headers['Content-Type'] == 'text/plain;charset=utf-8'
450    ), '#7 Content-Type header'
451    assert (
452        headers['X-Content-Type'] == 'text/plain;charset=utf-8'
453    ), '#7 response Content-Type'
454    assert headers['X-Character-Encoding'] == 'utf-8', '#7 response charset'
455
456    headers = client.get(url='/8')['headers']
457
458    assert (
459        headers['Content-Type'] == 'text/html;charset=utf-8'
460    ), '#8 Content-Type header'
461    assert (
462        headers['X-Content-Type'] == 'text/html;charset=utf-8'
463    ), '#8 response Content-Type'
464    assert headers['X-Character-Encoding'] == 'utf-8', '#8 response charset'
465
466
467def test_java_application_welcome_files():
468    client.load('welcome_files')
469
470    headers = client.get()['headers']
471
472    resp = client.get(url='/dir1')
473
474    assert resp['status'] == 302, 'dir redirect expected'
475
476    resp = client.get(url='/dir1/')
477
478    assert 'This is index.txt.' in resp['body'], 'dir1 index body'
479    assert resp['headers']['X-TXT-Filter'] == '1', 'TXT Filter header'
480
481    headers = client.get(url='/dir2/')['headers']
482
483    assert headers['X-Unit-JSP'] == 'ok', 'JSP Ok header'
484    assert headers['X-JSP-Filter'] == '1', 'JSP Filter header'
485
486    headers = client.get(url='/dir3/')['headers']
487
488    assert headers['X-App-Servlet'] == '1', 'URL pattern overrides welcome file'
489
490    headers = client.get(url='/dir4/')['headers']
491
492    assert 'X-App-Servlet' not in headers, 'Static welcome file served first'
493
494    headers = client.get(url='/dir5/')['headers']
495
496    assert (
497        headers['X-App-Servlet'] == '1'
498    ), 'Servlet for welcome file served when no static file found'
499
500
501def test_java_application_request_listeners():
502    client.load('request_listeners')
503
504    headers = client.get(url='/test1')['headers']
505
506    assert (
507        headers['X-Request-Initialized'] == '/test1'
508    ), 'request initialized event'
509    assert headers['X-Request-Destroyed'] == '', 'request destroyed event'
510    assert headers['X-Attr-Added'] == '', 'attribute added event'
511    assert headers['X-Attr-Removed'] == '', 'attribute removed event'
512    assert headers['X-Attr-Replaced'] == '', 'attribute replaced event'
513
514    headers = client.get(url='/test2?var1=1')['headers']
515
516    assert (
517        headers['X-Request-Initialized'] == '/test2'
518    ), 'request initialized event'
519    assert headers['X-Request-Destroyed'] == '/test1', 'request destroyed event'
520    assert headers['X-Attr-Added'] == 'var=1;', 'attribute added event'
521    assert headers['X-Attr-Removed'] == 'var=1;', 'attribute removed event'
522    assert headers['X-Attr-Replaced'] == '', 'attribute replaced event'
523
524    headers = client.get(url='/test3?var1=1&var2=2')['headers']
525
526    assert (
527        headers['X-Request-Initialized'] == '/test3'
528    ), 'request initialized event'
529    assert headers['X-Request-Destroyed'] == '/test2', 'request destroyed event'
530    assert headers['X-Attr-Added'] == 'var=1;', 'attribute added event'
531    assert headers['X-Attr-Removed'] == 'var=2;', 'attribute removed event'
532    assert headers['X-Attr-Replaced'] == 'var=1;', 'attribute replaced event'
533
534    headers = client.get(url='/test4?var1=1&var2=2&var3=3')['headers']
535
536    assert (
537        headers['X-Request-Initialized'] == '/test4'
538    ), 'request initialized event'
539    assert headers['X-Request-Destroyed'] == '/test3', 'request destroyed event'
540    assert headers['X-Attr-Added'] == 'var=1;', 'attribute added event'
541    assert headers['X-Attr-Removed'] == '', 'attribute removed event'
542    assert (
543        headers['X-Attr-Replaced'] == 'var=1;var=2;'
544    ), 'attribute replaced event'
545
546
547def test_java_application_request_uri_forward():
548    client.load('forward')
549
550    resp = client.get(
551        url='/fwd?uri=%2Fdata%2Ftest%3Furi%3Dnew_uri%26a%3D2%26b%3D3&a=1&c=4'
552    )
553    headers = resp['headers']
554
555    assert headers['X-REQUEST-Id'] == 'fwd', 'initial request servlet mapping'
556    assert (
557        headers['X-Forward-To'] == '/data/test?uri=new_uri&a=2&b=3'
558    ), 'forwarding triggered'
559    assert (
560        headers['X-REQUEST-Param-uri'] == '/data/test?uri=new_uri&a=2&b=3'
561    ), 'original uri parameter'
562    assert headers['X-REQUEST-Param-a'] == '1', 'original a parameter'
563    assert headers['X-REQUEST-Param-c'] == '4', 'original c parameter'
564
565    assert headers['X-FORWARD-Id'] == 'data', 'forward request servlet mapping'
566    assert (
567        headers['X-FORWARD-Request-URI'] == '/data/test'
568    ), 'forward request uri'
569    assert (
570        headers['X-FORWARD-Servlet-Path'] == '/data'
571    ), 'forward request servlet path'
572    assert (
573        headers['X-FORWARD-Path-Info'] == '/test'
574    ), 'forward request path info'
575    assert (
576        headers['X-FORWARD-Query-String'] == 'uri=new_uri&a=2&b=3'
577    ), 'forward request query string'
578    assert (
579        headers['X-FORWARD-Param-uri']
580        == 'new_uri,/data/test?uri=new_uri&a=2&b=3'
581    ), 'forward uri parameter'
582    assert headers['X-FORWARD-Param-a'] == '2,1', 'forward a parameter'
583    assert headers['X-FORWARD-Param-b'] == '3', 'forward b parameter'
584    assert headers['X-FORWARD-Param-c'] == '4', 'forward c parameter'
585
586    assert (
587        headers['X-javax.servlet.forward.request_uri'] == '/fwd'
588    ), 'original request uri'
589    assert (
590        headers['X-javax.servlet.forward.context_path'] == ''
591    ), 'original request context path'
592    assert (
593        headers['X-javax.servlet.forward.servlet_path'] == '/fwd'
594    ), 'original request servlet path'
595    assert (
596        headers['X-javax.servlet.forward.path_info'] == 'null'
597    ), 'original request path info'
598    assert (
599        headers['X-javax.servlet.forward.query_string']
600        == 'uri=%2Fdata%2Ftest%3Furi%3Dnew_uri%26a%3D2%26b%3D3&a=1&c=4'
601    ), 'original request query'
602
603    assert (
604        'Before forwarding' not in resp['body']
605    ), 'discarded data added before forward() call'
606    assert (
607        'X-After-Forwarding' not in headers
608    ), 'cannot add headers after forward() call'
609    assert (
610        'After forwarding' not in resp['body']
611    ), 'cannot add data after forward() call'
612
613
614def test_java_application_named_dispatcher_forward():
615    client.load('forward')
616
617    resp = client.get(url='/fwd?disp=name&uri=data')
618    headers = resp['headers']
619
620    assert headers['X-REQUEST-Id'] == 'fwd', 'initial request servlet mapping'
621    assert headers['X-Forward-To'] == 'data', 'forwarding triggered'
622
623    assert headers['X-FORWARD-Id'] == 'data', 'forward request servlet mapping'
624    assert headers['X-FORWARD-Request-URI'] == '/fwd', 'forward request uri'
625    assert (
626        headers['X-FORWARD-Servlet-Path'] == '/fwd'
627    ), 'forward request servlet path'
628    assert headers['X-FORWARD-Path-Info'] == 'null', 'forward request path info'
629    assert (
630        headers['X-FORWARD-Query-String'] == 'disp=name&uri=data'
631    ), 'forward request query string'
632
633    assert (
634        headers['X-javax.servlet.forward.request_uri'] == 'null'
635    ), 'original request uri'
636    assert (
637        headers['X-javax.servlet.forward.context_path'] == 'null'
638    ), 'original request context path'
639    assert (
640        headers['X-javax.servlet.forward.servlet_path'] == 'null'
641    ), 'original request servlet path'
642    assert (
643        headers['X-javax.servlet.forward.path_info'] == 'null'
644    ), 'original request path info'
645    assert (
646        headers['X-javax.servlet.forward.query_string'] == 'null'
647    ), 'original request query'
648
649    assert (
650        'Before forwarding' not in resp['body']
651    ), 'discarded data added before forward() call'
652    assert (
653        'X-After-Forwarding' not in headers
654    ), 'cannot add headers after forward() call'
655    assert (
656        'After forwarding' not in resp['body']
657    ), 'cannot add data after forward() call'
658
659
660def test_java_application_request_uri_include():
661    client.load('include')
662
663    resp = client.get(url='/inc?uri=/data/test')
664    headers = resp['headers']
665    body = resp['body']
666
667    assert headers['X-REQUEST-Id'] == 'inc', 'initial request servlet mapping'
668    assert headers['X-Include'] == '/data/test', 'including triggered'
669
670    assert (
671        'X-INCLUDE-Id' not in headers
672    ), 'unable to add headers in include request'
673
674    assert (
675        'javax.servlet.include.request_uri:  /data/test' in body
676    ), 'include request uri'
677    # assert (
678    #    'javax.servlet.include.context_path: ' in body
679    # ) == True, 'include request context path'
680    assert (
681        'javax.servlet.include.servlet_path: /data' in body
682    ), 'include request servlet path'
683    assert (
684        'javax.servlet.include.path_info:    /test' in body
685    ), 'include request path info'
686    assert (
687        'javax.servlet.include.query_string: null' in body
688    ), 'include request query'
689
690    assert 'Before include' in body, 'preserve data added before include() call'
691    assert (
692        headers['X-After-Include'] == 'you-should-see-this'
693    ), 'add headers after include() call'
694    assert 'After include' in body, 'add data after include() call'
695
696
697def test_java_application_named_dispatcher_include():
698    client.load('include')
699
700    resp = client.get(url='/inc?disp=name&uri=data')
701    headers = resp['headers']
702    body = resp['body']
703
704    assert headers['X-REQUEST-Id'] == 'inc', 'initial request servlet mapping'
705    assert headers['X-Include'] == 'data', 'including triggered'
706
707    assert (
708        'X-INCLUDE-Id' not in headers
709    ), 'unable to add headers in include request'
710
711    assert (
712        'javax.servlet.include.request_uri:  null' in body
713    ), 'include request uri'
714    # assert (
715    #    'javax.servlet.include.context_path: null' in body
716    # ) == True, 'include request context path'
717    assert (
718        'javax.servlet.include.servlet_path: null' in body
719    ), 'include request servlet path'
720    assert (
721        'javax.servlet.include.path_info:    null' in body
722    ), 'include request path info'
723    assert (
724        'javax.servlet.include.query_string: null' in body
725    ), 'include request query'
726
727    assert 'Before include' in body, 'preserve data added before include() call'
728    assert (
729        headers['X-After-Include'] == 'you-should-see-this'
730    ), 'add headers after include() call'
731    assert 'After include' in body, 'add data after include() call'
732
733
734def test_java_application_path_translation():
735    client.load('path_translation')
736
737    headers = client.get(url='/pt/test?path=/')['headers']
738
739    assert headers['X-Servlet-Path'] == '/pt', 'matched servlet path'
740    assert headers['X-Path-Info'] == '/test', 'the rest of the path'
741    assert (
742        headers['X-Path-Translated']
743        == f"{headers['X-Real-Path']}{headers['X-Path-Info']}"
744    ), 'translated path is the app root + path info'
745    assert headers['X-Resource-Paths'].endswith(
746        '/WEB-INF/, /index.html]'
747    ), 'app root directory content'
748    assert (
749        headers['X-Resource-As-Stream'] == 'null'
750    ), 'no resource stream for root path'
751
752    headers = client.get(url='/test?path=/none')['headers']
753
754    assert headers['X-Servlet-Path'] == '/test', 'matched whole path'
755    assert (
756        headers['X-Path-Info'] == 'null'
757    ), 'the rest of the path is null, whole path matched'
758    assert (
759        headers['X-Path-Translated'] == 'null'
760    ), 'translated path is null because path info is null'
761    assert headers['X-Real-Path'].endswith('/none'), 'read path is not null'
762    assert headers['X-Resource-Paths'] == 'null', 'no resource found'
763    assert headers['X-Resource-As-Stream'] == 'null', 'no resource stream'
764
765
766def test_java_application_query_string():
767    client.load('query_string')
768
769    assert (
770        client.get(url='/?a=b')['headers']['X-Query-String'] == 'a=b'
771    ), 'query string'
772
773
774def test_java_application_query_empty():
775    client.load('query_string')
776
777    assert (
778        client.get(url='/?')['headers']['X-Query-String'] == ''
779    ), 'query string empty'
780
781
782def test_java_application_query_absent():
783    client.load('query_string')
784
785    assert (
786        client.get()['headers']['X-Query-String'] == 'null'
787    ), 'query string absent'
788
789
790def test_java_application_empty():
791    client.load('empty')
792
793    assert client.get()['status'] == 200, 'empty'
794
795
796def test_java_application_keepalive_body():
797    client.load('mirror')
798
799    assert client.post()['status'] == 200, 'init'
800
801    body = '0123456789' * 500
802    (resp, sock) = client.post(
803        headers={
804            'Connection': 'keep-alive',
805            'Content-Type': 'text/html',
806            'Host': 'localhost',
807        },
808        start=True,
809        body=body,
810        read_timeout=1,
811    )
812
813    assert resp['body'] == body, 'keep-alive 1'
814
815    body = '0123456789'
816    resp = client.post(
817        headers={
818            'Connection': 'close',
819            'Content-Type': 'text/html',
820            'Host': 'localhost',
821        },
822        sock=sock,
823        body=body,
824    )
825
826    assert resp['body'] == body, 'keep-alive 2'
827
828
829def test_java_application_http_10():
830    client.load('empty')
831
832    assert client.get(http_10=True)['status'] == 200, 'HTTP 1.0'
833
834
835def test_java_application_no_method():
836    client.load('empty')
837
838    assert client.post()['status'] == 405, 'no method'
839
840
841def test_java_application_get_header():
842    client.load('get_header')
843
844    assert (
845        client.get(
846            headers={
847                'X-Header': 'blah',
848                'Content-Type': 'text/html',
849                'Host': 'localhost',
850                'Connection': 'close',
851            }
852        )['headers']['X-Reply']
853        == 'blah'
854    ), 'get header'
855
856
857def test_java_application_get_header_empty():
858    client.load('get_header')
859
860    assert 'X-Reply' not in client.get()['headers'], 'get header empty'
861
862
863def test_java_application_get_headers():
864    client.load('get_headers')
865
866    headers = client.get(
867        headers={
868            'X-Header': ['blah', 'blah'],
869            'Content-Type': 'text/html',
870            'Host': 'localhost',
871            'Connection': 'close',
872        }
873    )['headers']
874
875    assert headers['X-Reply-0'] == 'blah', 'get headers'
876    assert headers['X-Reply-1'] == 'blah', 'get headers 2'
877
878
879def test_java_application_many_headers():
880    client.load('get_headers')
881
882    value = '0123456789' * 10
883
884    headers = client.get(
885        headers={
886            'X-Header': [value] * 100,
887            'Content-Type': 'text/html',
888            'Host': 'localhost',
889            'Connection': 'close',
890        }
891    )['headers']
892
893    for i in range(0, 99):
894        assert headers[f'X-Reply-{i}'] == value, 'many headers'
895
896
897def test_java_application_get_headers_empty():
898    client.load('get_headers')
899
900    assert 'X-Reply-0' not in client.get()['headers'], 'get headers empty'
901
902
903def test_java_application_get_header_names():
904    client.load('get_header_names')
905
906    headers = client.get()['headers']
907
908    assert re.search(
909        r'(?:Host|Connection)', headers['X-Reply-0']
910    ), 'get header names'
911    assert re.search(
912        r'(?:Host|Connection)', headers['X-Reply-1']
913    ), 'get header names 2'
914    assert (
915        headers['X-Reply-0'] != headers['X-Reply-1']
916    ), 'get header names not equal'
917
918
919def test_java_application_header_int():
920    client.load('header_int')
921
922    headers = client.get(
923        headers={
924            'X-Header': '2',
925            'Content-Type': 'text/html',
926            'Host': 'localhost',
927            'Connection': 'close',
928        }
929    )['headers']
930
931    assert headers['X-Set-Int'] == '1', 'set int header'
932    assert headers['X-Get-Int'] == '2', 'get int header'
933
934
935def test_java_application_header_date():
936    client.load('header_date')
937
938    date = 'Fri, 15 Mar 2019 14:45:34 GMT'
939
940    headers = client.get(
941        headers={
942            'X-Header': date,
943            'Content-Type': 'text/html',
944            'Host': 'localhost',
945            'Connection': 'close',
946        }
947    )['headers']
948
949    assert (
950        headers['X-Set-Date'] == 'Thu, 01 Jan 1970 00:00:01 GMT'
951    ), 'set date header'
952    assert headers['X-Get-Date'] == date, 'get date header'
953
954
955def test_java_application_multipart(search_in_file, temp_dir):
956    client.load('multipart')
957
958    reldst = '/uploads'
959    fulldst = f'{temp_dir}{reldst}'
960    Path(fulldst).mkdir(parents=True)
961    public_dir(fulldst)
962
963    fields = {
964        'file': {
965            'filename': 'sample.txt',
966            'type': 'text/plain',
967            'data': io.StringIO('Data from sample file'),
968        },
969        'destination': fulldst,
970        'upload': 'Upload',
971    }
972
973    encoded, content_type = client.multipart_encode(fields)
974
975    preamble = 'Preamble. Should be ignored.'
976    epilogue = 'Epilogue. Should be ignored.'
977    body = f'{preamble}\r\n{encoded.decode()}\r\n{epilogue}'
978
979    resp = client.post(
980        headers={
981            'Content-Type': content_type,
982            'Host': 'localhost',
983            'Connection': 'close',
984        },
985        body=body,
986    )
987
988    assert resp['status'] == 200, 'multipart status'
989    assert re.search(r'sample\.txt created', resp['body']), 'multipart body'
990    assert (
991        search_in_file(r'^Data from sample file$', name=f'{reldst}/sample.txt')
992        is not None
993    ), 'file created'
994
995
996def test_java_application_threads():
997    client.load('threads')
998
999    assert 'success' in client.conf(
1000        '4', 'applications/threads/threads'
1001    ), 'configure 4 threads'
1002
1003    socks = []
1004
1005    for _ in range(4):
1006        sock = client.get(
1007            headers={
1008                'Host': 'localhost',
1009                'X-Delay': '2',
1010                'Connection': 'close',
1011            },
1012            no_recv=True,
1013        )
1014
1015        socks.append(sock)
1016
1017        time.sleep(0.25)  # required to avoid greedy request reading
1018
1019    threads = set()
1020
1021    for sock in socks:
1022        resp = client.recvall(sock).decode('utf-8')
1023
1024        client.log_in(resp)
1025
1026        resp = client._resp_to_dict(resp)
1027
1028        assert resp['status'] == 200, 'status'
1029
1030        threads.add(resp['headers']['X-Thread'])
1031
1032        sock.close()
1033
1034    assert len(socks) == len(threads), 'threads differs'
1035