test_return.py (1596:b7e2d4d92624) test_return.py (1654:fc7d0578e124)
1import re
2
3from unit.applications.proto import TestApplicationProto
4
5
6class TestReturn(TestApplicationProto):
7 prerequisites = {}
8
9 def setup_method(self):
1import re
2
3from unit.applications.proto import TestApplicationProto
4
5
6class TestReturn(TestApplicationProto):
7 prerequisites = {}
8
9 def setup_method(self):
10 super().setup_method()
11
12 self._load_conf(
13 {
14 "listeners": {"*:7080": {"pass": "routes"}},
15 "routes": [{"action": {"return": 200}}],
16 "applications": {},
17 }
18 )
19
20 def get_resps_sc(self, req=10):
21 to_send = b"""GET / HTTP/1.1
22Host: localhost
23
24""" * (
25 req - 1
26 )
27
28 to_send += b"""GET / HTTP/1.1
29Host: localhost
30Connection: close
31
32"""
33
34 return self.http(to_send, raw_resp=True, raw=True)
35
36 def test_return(self):
37 resp = self.get()
38 assert resp['status'] == 200
39 assert 'Server' in resp['headers']
40 assert 'Date' in resp['headers']
41 assert resp['headers']['Content-Length'] == '0'
42 assert resp['headers']['Connection'] == 'close'
43 assert resp['body'] == '', 'body'
44
45 resp = self.post(body='blah')
46 assert resp['status'] == 200
47 assert resp['body'] == '', 'body'
48
49 resp = self.get_resps_sc()
50 assert len(re.findall('200 OK', resp)) == 10
51 assert len(re.findall('Connection:', resp)) == 1
52 assert len(re.findall('Connection: close', resp)) == 1
53
54 resp = self.get(http_10=True)
55 assert resp['status'] == 200
56 assert 'Server' in resp['headers']
57 assert 'Date' in resp['headers']
58 assert resp['headers']['Content-Length'] == '0'
59 assert 'Connection' not in resp['headers']
60 assert resp['body'] == '', 'body'
61
62 def test_return_update(self):
63 assert 'success' in self.conf('0', 'routes/0/action/return')
64
65 resp = self.get()
66 assert resp['status'] == 0
67 assert resp['body'] == ''
68
69 assert 'success' in self.conf('404', 'routes/0/action/return')
70
71 resp = self.get()
72 assert resp['status'] == 404
73 assert resp['body'] != ''
74
75 assert 'success' in self.conf('598', 'routes/0/action/return')
76
77 resp = self.get()
78 assert resp['status'] == 598
79 assert resp['body'] != ''
80
81 assert 'success' in self.conf('999', 'routes/0/action/return')
82
83 resp = self.get()
84 assert resp['status'] == 999
85 assert resp['body'] == ''
86
87 def test_return_location(self):
88 reserved = ":/?#[]@!$&'()*+,;="
89 unreserved = (
90 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
91 "0123456789-._~"
92 )
93 unsafe = " \"%<>\\^`{|}"
94 unsafe_enc = "%20%22%25%3C%3E%5C%5E%60%7B%7C%7D"
95
96 def check_location(location, expect=None):
97 if expect is None:
98 expect = location
99
100 assert 'success' in self.conf(
101 {"return": 301, "location": location}, 'routes/0/action'
102 ), 'configure location'
103
104 assert self.get()['headers']['Location'] == expect
105
106 # FAIL: can't specify empty header value.
107 # check_location("")
108
109 check_location(reserved)
110
111 # After first "?" all other "?" encoded.
112 check_location("/?" + reserved, "/?:/%3F#[]@!$&'()*+,;=")
113 check_location("???", "?%3F%3F")
114
115 # After first "#" all other "?" or "#" encoded.
116 check_location("/#" + reserved, "/#:/%3F%23[]@!$&'()*+,;=")
117 check_location("##?#?", "#%23%3F%23%3F")
118
119 # After first "?" next "#" not encoded.
120 check_location("/?#" + reserved, "/?#:/%3F%23[]@!$&'()*+,;=")
121 check_location("??##", "?%3F#%23")
122 check_location("/?##?", "/?#%23%3F")
123
124 # Unreserved never encoded.
125 check_location(unreserved)
126 check_location("/" + unreserved + "?" + unreserved + "#" + unreserved)
127
128 # Unsafe always encoded.
129 check_location(unsafe, unsafe_enc)
130 check_location("?" + unsafe, "?" + unsafe_enc)
131 check_location("#" + unsafe, "#" + unsafe_enc)
132
133 # %00-%20 and %7F-%FF always encoded.
134 check_location(u"\u0000\u0018\u001F\u0020\u0021", "%00%18%1F%20!")
135 check_location(u"\u007F\u0080н\u20BD", "%7F%C2%80%D0%BD%E2%82%BD")
136
137 # Encoded string detection. If at least one char need to be encoded
138 # then whole string will be encoded.
139 check_location("%20")
140 check_location("/%20?%20#%20")
141 check_location(" %20", "%20%2520")
142 check_location("%20 ", "%2520%20")
143 check_location("/%20?%20#%20 ", "/%2520?%2520#%2520%20")
144
145 def test_return_location_edit(self):
146 assert 'success' in self.conf(
147 {"return": 302, "location": "blah"}, 'routes/0/action'
148 ), 'configure init location'
149 assert self.get()['headers']['Location'] == 'blah'
150
151 assert 'success' in self.conf_delete(
152 'routes/0/action/location'
153 ), 'location delete'
154 assert 'Location' not in self.get()['headers']
155
156 assert 'success' in self.conf(
157 '"blah"', 'routes/0/action/location'
158 ), 'location restore'
159 assert self.get()['headers']['Location'] == 'blah'
160
161 assert 'error' in self.conf_post(
162 '"blah"', 'routes/0/action/location'
163 ), 'location method not allowed'
164 assert self.get()['headers']['Location'] == 'blah'
165
166 def test_return_invalid(self):
167 def check_error(conf):
168 assert 'error' in self.conf(conf, 'routes/0/action')
169
170 check_error({"return": "200"})
171 check_error({"return": []})
172 check_error({"return": 80.1})
173 check_error({"return": 1000})
174 check_error({"return": -1})
175 check_error({"return": 200, "share": "/blah"})
176
177 assert 'error' in self.conf(
178 '001', 'routes/0/action/return'
179 ), 'leading zero'
180
181 check_error({"return": 301, "location": 0})
182 check_error({"return": 301, "location": []})
10 self._load_conf(
11 {
12 "listeners": {"*:7080": {"pass": "routes"}},
13 "routes": [{"action": {"return": 200}}],
14 "applications": {},
15 }
16 )
17
18 def get_resps_sc(self, req=10):
19 to_send = b"""GET / HTTP/1.1
20Host: localhost
21
22""" * (
23 req - 1
24 )
25
26 to_send += b"""GET / HTTP/1.1
27Host: localhost
28Connection: close
29
30"""
31
32 return self.http(to_send, raw_resp=True, raw=True)
33
34 def test_return(self):
35 resp = self.get()
36 assert resp['status'] == 200
37 assert 'Server' in resp['headers']
38 assert 'Date' in resp['headers']
39 assert resp['headers']['Content-Length'] == '0'
40 assert resp['headers']['Connection'] == 'close'
41 assert resp['body'] == '', 'body'
42
43 resp = self.post(body='blah')
44 assert resp['status'] == 200
45 assert resp['body'] == '', 'body'
46
47 resp = self.get_resps_sc()
48 assert len(re.findall('200 OK', resp)) == 10
49 assert len(re.findall('Connection:', resp)) == 1
50 assert len(re.findall('Connection: close', resp)) == 1
51
52 resp = self.get(http_10=True)
53 assert resp['status'] == 200
54 assert 'Server' in resp['headers']
55 assert 'Date' in resp['headers']
56 assert resp['headers']['Content-Length'] == '0'
57 assert 'Connection' not in resp['headers']
58 assert resp['body'] == '', 'body'
59
60 def test_return_update(self):
61 assert 'success' in self.conf('0', 'routes/0/action/return')
62
63 resp = self.get()
64 assert resp['status'] == 0
65 assert resp['body'] == ''
66
67 assert 'success' in self.conf('404', 'routes/0/action/return')
68
69 resp = self.get()
70 assert resp['status'] == 404
71 assert resp['body'] != ''
72
73 assert 'success' in self.conf('598', 'routes/0/action/return')
74
75 resp = self.get()
76 assert resp['status'] == 598
77 assert resp['body'] != ''
78
79 assert 'success' in self.conf('999', 'routes/0/action/return')
80
81 resp = self.get()
82 assert resp['status'] == 999
83 assert resp['body'] == ''
84
85 def test_return_location(self):
86 reserved = ":/?#[]@!$&'()*+,;="
87 unreserved = (
88 "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz"
89 "0123456789-._~"
90 )
91 unsafe = " \"%<>\\^`{|}"
92 unsafe_enc = "%20%22%25%3C%3E%5C%5E%60%7B%7C%7D"
93
94 def check_location(location, expect=None):
95 if expect is None:
96 expect = location
97
98 assert 'success' in self.conf(
99 {"return": 301, "location": location}, 'routes/0/action'
100 ), 'configure location'
101
102 assert self.get()['headers']['Location'] == expect
103
104 # FAIL: can't specify empty header value.
105 # check_location("")
106
107 check_location(reserved)
108
109 # After first "?" all other "?" encoded.
110 check_location("/?" + reserved, "/?:/%3F#[]@!$&'()*+,;=")
111 check_location("???", "?%3F%3F")
112
113 # After first "#" all other "?" or "#" encoded.
114 check_location("/#" + reserved, "/#:/%3F%23[]@!$&'()*+,;=")
115 check_location("##?#?", "#%23%3F%23%3F")
116
117 # After first "?" next "#" not encoded.
118 check_location("/?#" + reserved, "/?#:/%3F%23[]@!$&'()*+,;=")
119 check_location("??##", "?%3F#%23")
120 check_location("/?##?", "/?#%23%3F")
121
122 # Unreserved never encoded.
123 check_location(unreserved)
124 check_location("/" + unreserved + "?" + unreserved + "#" + unreserved)
125
126 # Unsafe always encoded.
127 check_location(unsafe, unsafe_enc)
128 check_location("?" + unsafe, "?" + unsafe_enc)
129 check_location("#" + unsafe, "#" + unsafe_enc)
130
131 # %00-%20 and %7F-%FF always encoded.
132 check_location(u"\u0000\u0018\u001F\u0020\u0021", "%00%18%1F%20!")
133 check_location(u"\u007F\u0080н\u20BD", "%7F%C2%80%D0%BD%E2%82%BD")
134
135 # Encoded string detection. If at least one char need to be encoded
136 # then whole string will be encoded.
137 check_location("%20")
138 check_location("/%20?%20#%20")
139 check_location(" %20", "%20%2520")
140 check_location("%20 ", "%2520%20")
141 check_location("/%20?%20#%20 ", "/%2520?%2520#%2520%20")
142
143 def test_return_location_edit(self):
144 assert 'success' in self.conf(
145 {"return": 302, "location": "blah"}, 'routes/0/action'
146 ), 'configure init location'
147 assert self.get()['headers']['Location'] == 'blah'
148
149 assert 'success' in self.conf_delete(
150 'routes/0/action/location'
151 ), 'location delete'
152 assert 'Location' not in self.get()['headers']
153
154 assert 'success' in self.conf(
155 '"blah"', 'routes/0/action/location'
156 ), 'location restore'
157 assert self.get()['headers']['Location'] == 'blah'
158
159 assert 'error' in self.conf_post(
160 '"blah"', 'routes/0/action/location'
161 ), 'location method not allowed'
162 assert self.get()['headers']['Location'] == 'blah'
163
164 def test_return_invalid(self):
165 def check_error(conf):
166 assert 'error' in self.conf(conf, 'routes/0/action')
167
168 check_error({"return": "200"})
169 check_error({"return": []})
170 check_error({"return": 80.1})
171 check_error({"return": 1000})
172 check_error({"return": -1})
173 check_error({"return": 200, "share": "/blah"})
174
175 assert 'error' in self.conf(
176 '001', 'routes/0/action/return'
177 ), 'leading zero'
178
179 check_error({"return": 301, "location": 0})
180 check_error({"return": 301, "location": []})