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