diff options
Diffstat (limited to 'test/test_return.py')
-rw-r--r-- | test/test_return.py | 198 |
1 files changed, 198 insertions, 0 deletions
diff --git a/test/test_return.py b/test/test_return.py new file mode 100644 index 00000000..fcb51745 --- /dev/null +++ b/test/test_return.py @@ -0,0 +1,198 @@ +import re +import unittest +from unit.applications.proto import TestApplicationProto + + +class TestReturn(TestApplicationProto): + prerequisites = {} + + def setUp(self): + super().setUp() + + self._load_conf( + { + "listeners": {"*:7080": {"pass": "routes"}}, + "routes": [{"action": {"return": 200}}], + "applications": {}, + } + ) + + def get_resps_sc(self, req=10): + to_send = b"""GET / HTTP/1.1 +Host: localhost + +""" * ( + req - 1 + ) + + to_send += b"""GET / HTTP/1.1 +Host: localhost +Connection: close + +""" + + return self.http(to_send, raw_resp=True, raw=True) + + def test_return(self): + resp = self.get() + self.assertEqual(resp['status'], 200) + self.assertIn('Server', resp['headers']) + self.assertIn('Date', resp['headers']) + self.assertEqual(resp['headers']['Content-Length'], '0') + self.assertEqual(resp['headers']['Connection'], 'close') + self.assertEqual(resp['body'], '', 'body') + + resp = self.post(body='blah') + self.assertEqual(resp['status'], 200) + self.assertEqual(resp['body'], '', 'body') + + resp = self.get_resps_sc() + self.assertEqual(len(re.findall('200 OK', resp)), 10) + self.assertEqual(len(re.findall('Connection:', resp)), 1) + self.assertEqual(len(re.findall('Connection: close', resp)), 1) + + resp = self.get(http_10=True) + self.assertEqual(resp['status'], 200) + self.assertIn('Server', resp['headers']) + self.assertIn('Date', resp['headers']) + self.assertEqual(resp['headers']['Content-Length'], '0') + self.assertNotIn('Connection', resp['headers']) + self.assertEqual(resp['body'], '', 'body') + + def test_return_update(self): + self.assertIn('success', self.conf('0', 'routes/0/action/return')) + + resp = self.get() + self.assertEqual(resp['status'], 0) + self.assertEqual(resp['body'], '') + + self.assertIn('success', self.conf('404', 'routes/0/action/return')) + + resp = self.get() + self.assertEqual(resp['status'], 404) + self.assertNotEqual(resp['body'], '') + + self.assertIn('success', self.conf('598', 'routes/0/action/return')) + + resp = self.get() + self.assertEqual(resp['status'], 598) + self.assertNotEqual(resp['body'], '') + + self.assertIn('success', self.conf('999', 'routes/0/action/return')) + + resp = self.get() + self.assertEqual(resp['status'], 999) + self.assertEqual(resp['body'], '') + + def test_return_location(self): + reserved = ":/?#[]@!$&'()*+,;=" + unreserved = ("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" + "0123456789-._~") + unsafe = " \"%<>\\^`{|}" + unsafe_enc = "%20%22%25%3C%3E%5C%5E%60%7B%7C%7D" + + def check_location(location, expect=None): + if expect is None: + expect = location + + self.assertIn( + 'success', + self.conf( + {"return": 301, "location": location}, 'routes/0/action' + ), + 'configure location' + ) + + self.assertEqual(self.get()['headers']['Location'], expect) + + # FAIL: can't specify empty header value. + # check_location("") + + check_location(reserved) + + # After first "?" all other "?" encoded. + check_location("/?" + reserved, "/?:/%3F#[]@!$&'()*+,;=") + check_location("???", "?%3F%3F") + + # After first "#" all other "?" or "#" encoded. + check_location("/#" + reserved, "/#:/%3F%23[]@!$&'()*+,;=") + check_location("##?#?", "#%23%3F%23%3F") + + # After first "?" next "#" not encoded. + check_location("/?#" + reserved, "/?#:/%3F%23[]@!$&'()*+,;=") + check_location("??##", "?%3F#%23") + check_location("/?##?", "/?#%23%3F") + + # Unreserved never encoded. + check_location(unreserved) + check_location("/" + unreserved + "?" + unreserved + "#" + unreserved) + + # Unsafe always encoded. + check_location(unsafe, unsafe_enc) + check_location("?" + unsafe, "?" + unsafe_enc) + check_location("#" + unsafe, "#" + unsafe_enc) + + # %00-%20 and %7F-%FF always encoded. + check_location(u"\u0000\u0018\u001F\u0020\u0021", "%00%18%1F%20!") + check_location(u"\u007F\u0080н\u20BD", "%7F%C2%80%D0%BD%E2%82%BD") + + # Encoded string detection. If at least one char need to be encoded + # then whole string will be encoded. + check_location("%20") + check_location("/%20?%20#%20") + check_location(" %20", "%20%2520") + check_location("%20 ", "%2520%20") + check_location("/%20?%20#%20 ", "/%2520?%2520#%2520%20") + + def test_return_location_edit(self): + self.assertIn( + 'success', + self.conf( + {"return": 302, "location": "blah"}, 'routes/0/action' + ), + 'configure init location' + ) + self.assertEqual(self.get()['headers']['Location'], 'blah') + + self.assertIn( + 'success', + self.conf_delete('routes/0/action/location'), + 'location delete' + ) + self.assertNotIn('Location', self.get()['headers']) + + self.assertIn( + 'success', + self.conf('"blah"', 'routes/0/action/location'), + 'location restore' + ) + self.assertEqual(self.get()['headers']['Location'], 'blah') + + self.assertIn( + 'error', + self.conf_post('"blah"', 'routes/0/action/location'), + 'location method not allowed' + ) + self.assertEqual(self.get()['headers']['Location'], 'blah') + + def test_return_invalid(self): + def check_error(conf): + self.assertIn('error', self.conf(conf, 'routes/0/action')) + + check_error({"return": "200"}) + check_error({"return": []}) + check_error({"return": 80.1}) + check_error({"return": 1000}) + check_error({"return": -1}) + check_error({"return": 200, "share": "/blah"}) + + self.assertIn( + 'error', self.conf('001', 'routes/0/action/return'), 'leading zero' + ) + + check_error({"return": 301, "location": 0}) + check_error({"return": 301, "location": []}) + + +if __name__ == '__main__': + TestReturn.main() |