summaryrefslogtreecommitdiffhomepage
path: root/test/test_routing.py
diff options
context:
space:
mode:
Diffstat (limited to 'test/test_routing.py')
-rw-r--r--test/test_routing.py3470
1 files changed, 1782 insertions, 1688 deletions
diff --git a/test/test_routing.py b/test/test_routing.py
index a4806d5c..a18edb04 100644
--- a/test/test_routing.py
+++ b/test/test_routing.py
@@ -1,1914 +1,2008 @@
# -*- coding: utf-8 -*-
import pytest
-from unit.applications.lang.python import TestApplicationPython
+from unit.applications.lang.python import ApplicationPython
from unit.option import option
+prerequisites = {'modules': {'python': 'any'}}
-class TestRouting(TestApplicationPython):
- prerequisites = {'modules': {'python': 'any'}}
+client = ApplicationPython()
- def setup_method(self):
- assert 'success' in self.conf(
- {
- "listeners": {"*:7080": {"pass": "routes"}},
- "routes": [
- {
- "match": {"method": "GET"},
- "action": {"return": 200},
- }
- ],
- "applications": {},
- }
- ), 'routing configure'
- def route(self, route):
- return self.conf([route], 'routes')
+@pytest.fixture(autouse=True)
+def setup_method_fixture():
+ assert 'success' in client.conf(
+ {
+ "listeners": {"*:7080": {"pass": "routes"}},
+ "routes": [
+ {
+ "match": {"method": "GET"},
+ "action": {"return": 200},
+ }
+ ],
+ "applications": {},
+ }
+ ), 'routing configure'
- def route_match(self, match):
- assert 'success' in self.route(
- {"match": match, "action": {"return": 200}}
- ), 'route match configure'
- def route_match_invalid(self, match):
- assert 'error' in self.route(
- {"match": match, "action": {"return": 200}}
- ), 'route match configure invalid'
+def route(route):
+ return client.conf([route], 'routes')
- def host(self, host, status):
- assert (
- self.get(headers={'Host': host, 'Connection': 'close'})['status']
- == status
- ), 'match host'
- def cookie(self, cookie, status):
- assert (
- self.get(
- headers={
- 'Host': 'localhost',
- 'Cookie': cookie,
- 'Connection': 'close',
- },
- )['status']
- == status
- ), 'match cookie'
+def route_match(match):
+ assert 'success' in route(
+ {"match": match, "action": {"return": 200}}
+ ), 'route match configure'
- def test_routes_match_method_positive(self):
- assert self.get()['status'] == 200, 'GET'
- assert self.post()['status'] == 404, 'POST'
- def test_routes_match_method_positive_many(self):
- self.route_match({"method": ["GET", "POST"]})
+def route_match_invalid(match):
+ assert 'error' in route(
+ {"match": match, "action": {"return": 200}}
+ ), 'route match configure invalid'
- assert self.get()['status'] == 200, 'GET'
- assert self.post()['status'] == 200, 'POST'
- assert self.delete()['status'] == 404, 'DELETE'
- def test_routes_match_method_negative(self):
- self.route_match({"method": "!GET"})
+def host(host, status):
+ assert (
+ client.get(headers={'Host': host, 'Connection': 'close'})['status']
+ == status
+ ), 'match host'
- assert self.get()['status'] == 404, 'GET'
- assert self.post()['status'] == 200, 'POST'
- def test_routes_match_method_negative_many(self):
- self.route_match({"method": ["!GET", "!POST"]})
+def cookie(cookie, status):
+ assert (
+ client.get(
+ headers={
+ 'Host': 'localhost',
+ 'Cookie': cookie,
+ 'Connection': 'close',
+ },
+ )['status']
+ == status
+ ), 'match cookie'
- assert self.get()['status'] == 404, 'GET'
- assert self.post()['status'] == 404, 'POST'
- assert self.delete()['status'] == 200, 'DELETE'
- def test_routes_match_method_wildcard_left(self):
- self.route_match({"method": "*ET"})
+def test_routes_match_method_positive():
+ assert client.get()['status'] == 200, 'GET'
+ assert client.post()['status'] == 404, 'POST'
- assert self.get()['status'] == 200, 'GET'
- assert self.post()['status'] == 404, 'POST'
- def test_routes_match_method_wildcard_right(self):
- self.route_match({"method": "GE*"})
+def test_routes_match_method_positive_many():
+ route_match({"method": ["GET", "POST"]})
- assert self.get()['status'] == 200, 'GET'
- assert self.post()['status'] == 404, 'POST'
+ assert client.get()['status'] == 200, 'GET'
+ assert client.post()['status'] == 200, 'POST'
+ assert client.delete()['status'] == 404, 'DELETE'
- def test_routes_match_method_wildcard_left_right(self):
- self.route_match({"method": "*GET*"})
- assert self.get()['status'] == 200, 'GET'
- assert self.post()['status'] == 404, 'POST'
+def test_routes_match_method_negative():
+ route_match({"method": "!GET"})
- def test_routes_match_method_wildcard(self):
- self.route_match({"method": "*"})
+ assert client.get()['status'] == 404, 'GET'
+ assert client.post()['status'] == 200, 'POST'
- assert self.get()['status'] == 200, 'GET'
- def test_routes_match_invalid(self):
- self.route_match_invalid({"method": "**"})
+def test_routes_match_method_negative_many():
+ route_match({"method": ["!GET", "!POST"]})
- def test_routes_match_valid(self):
- self.route_match({"method": "blah*"})
- self.route_match({"host": "*blah*blah"})
- self.route_match({"host": "blah*blah*blah"})
- self.route_match({"host": "blah*blah*"})
+ assert client.get()['status'] == 404, 'GET'
+ assert client.post()['status'] == 404, 'POST'
+ assert client.delete()['status'] == 200, 'DELETE'
- def test_routes_match_empty_exact(self):
- self.route_match({"uri": ""})
- assert self.get()['status'] == 404
- self.route_match({"uri": "/"})
- assert self.get()['status'] == 200
- assert self.get(url='/blah')['status'] == 404
+def test_routes_match_method_wildcard_left():
+ route_match({"method": "*ET"})
- def test_routes_match_negative(self):
- self.route_match({"uri": "!"})
- assert self.get()['status'] == 200
+ assert client.get()['status'] == 200, 'GET'
+ assert client.post()['status'] == 404, 'POST'
- self.route_match({"uri": "!*"})
- assert self.get()['status'] == 404
- self.route_match({"uri": "!/"})
- assert self.get()['status'] == 404
- assert self.get(url='/blah')['status'] == 200
+def test_routes_match_method_wildcard_right():
+ route_match({"method": "GE*"})
- self.route_match({"uri": "!*blah"})
- assert self.get()['status'] == 200
- assert self.get(url='/bla')['status'] == 200
- assert self.get(url='/blah')['status'] == 404
- assert self.get(url='/blah1')['status'] == 200
+ assert client.get()['status'] == 200, 'GET'
+ assert client.post()['status'] == 404, 'POST'
- self.route_match({"uri": "!/blah*1*"})
- assert self.get()['status'] == 200
- assert self.get(url='/blah')['status'] == 200
- assert self.get(url='/blah1')['status'] == 404
- assert self.get(url='/blah12')['status'] == 404
- assert self.get(url='/blah2')['status'] == 200
- def test_routes_match_wildcard_middle(self):
- self.route_match({"host": "ex*le"})
+def test_routes_match_method_wildcard_left_right():
+ route_match({"method": "*GET*"})
- self.host('example', 200)
- self.host('www.example', 404)
- self.host('example.com', 404)
- self.host('exampl', 404)
+ assert client.get()['status'] == 200, 'GET'
+ assert client.post()['status'] == 404, 'POST'
- def test_routes_match_method_case_insensitive(self):
- self.route_match({"method": "get"})
- assert self.get()['status'] == 200, 'GET'
+def test_routes_match_method_wildcard():
+ route_match({"method": "*"})
- def test_routes_match_wildcard_left_case_insensitive(self):
- self.route_match({"method": "*get"})
- assert self.get()['status'] == 200, 'GET'
+ assert client.get()['status'] == 200, 'GET'
- self.route_match({"method": "*et"})
- assert self.get()['status'] == 200, 'GET'
- def test_routes_match_wildcard_middle_case_insensitive(self):
- self.route_match({"method": "g*t"})
+def test_routes_match_invalid():
+ route_match_invalid({"method": "**"})
- assert self.get()['status'] == 200, 'GET'
- def test_routes_match_wildcard_right_case_insensitive(self):
- self.route_match({"method": "get*"})
- assert self.get()['status'] == 200, 'GET'
+def test_routes_match_valid():
+ route_match({"method": "blah*"})
+ route_match({"host": "*blah*blah"})
+ route_match({"host": "blah*blah*blah"})
+ route_match({"host": "blah*blah*"})
- self.route_match({"method": "ge*"})
- assert self.get()['status'] == 200, 'GET'
- def test_routes_match_wildcard_substring_case_insensitive(self):
- self.route_match({"method": "*et*"})
+def test_routes_match_empty_exact():
+ route_match({"uri": ""})
+ assert client.get()['status'] == 404
- assert self.get()['status'] == 200, 'GET'
+ route_match({"uri": "/"})
+ assert client.get()['status'] == 200
+ assert client.get(url='/blah')['status'] == 404
- def test_routes_match_wildcard_left_case_sensitive(self):
- self.route_match({"uri": "*blah"})
- assert self.get(url='/blah')['status'] == 200, '/blah'
- assert self.get(url='/BLAH')['status'] == 404, '/BLAH'
+def test_routes_match_negative():
+ route_match({"uri": "!"})
+ assert client.get()['status'] == 200
- def test_routes_match_wildcard_middle_case_sensitive(self):
- self.route_match({"uri": "/b*h"})
+ route_match({"uri": "!*"})
+ assert client.get()['status'] == 404
- assert self.get(url='/blah')['status'] == 200, '/blah'
- assert self.get(url='/BLAH')['status'] == 404, '/BLAH'
+ route_match({"uri": "!/"})
+ assert client.get()['status'] == 404
+ assert client.get(url='/blah')['status'] == 200
- def test_route_match_wildcards_ordered(self):
- self.route_match({"uri": "/a*x*y*"})
+ route_match({"uri": "!*blah"})
+ assert client.get()['status'] == 200
+ assert client.get(url='/bla')['status'] == 200
+ assert client.get(url='/blah')['status'] == 404
+ assert client.get(url='/blah1')['status'] == 200
- assert self.get(url='/axy')['status'] == 200, '/axy'
- assert self.get(url='/ayx')['status'] == 404, '/ayx'
+ route_match({"uri": "!/blah*1*"})
+ assert client.get()['status'] == 200
+ assert client.get(url='/blah')['status'] == 200
+ assert client.get(url='/blah1')['status'] == 404
+ assert client.get(url='/blah12')['status'] == 404
+ assert client.get(url='/blah2')['status'] == 200
- def test_route_match_wildcards_adjust_start(self):
- self.route_match({"uri": "/bla*bla*"})
- assert self.get(url='/bla_foo')['status'] == 404, '/bla_foo'
+def test_routes_match_wildcard_middle():
+ route_match({"host": "ex*le"})
- def test_route_match_wildcards_adjust_start_substr(self):
- self.route_match({"uri": "*bla*bla*"})
+ host('example', 200)
+ host('www.example', 404)
+ host('example.com', 404)
+ host('exampl', 404)
- assert self.get(url='/bla_foo')['status'] == 404, '/bla_foo'
- def test_route_match_wildcards_adjust_end(self):
- self.route_match({"uri": "/bla*bla"})
+def test_routes_match_method_case_insensitive():
+ route_match({"method": "get"})
- assert self.get(url='/foo_bla')['status'] == 404, '/foo_bla'
+ assert client.get()['status'] == 200, 'GET'
- def test_routes_match_wildcard_right_case_sensitive(self):
- self.route_match({"uri": "/bla*"})
- assert self.get(url='/blah')['status'] == 200, '/blah'
- assert self.get(url='/BLAH')['status'] == 404, '/BLAH'
+def test_routes_match_wildcard_left_case_insensitive():
+ route_match({"method": "*get"})
+ assert client.get()['status'] == 200, 'GET'
- def test_routes_match_wildcard_substring_case_sensitive(self):
- self.route_match({"uri": "*bla*"})
+ route_match({"method": "*et"})
+ assert client.get()['status'] == 200, 'GET'
- assert self.get(url='/blah')['status'] == 200, '/blah'
- assert self.get(url='/BLAH')['status'] == 404, '/BLAH'
- def test_routes_match_many_wildcard_substrings_case_sensitive(self):
- self.route_match({"uri": "*a*B*c*"})
+def test_routes_match_wildcard_middle_case_insensitive():
+ route_match({"method": "g*t"})
- assert self.get(url='/blah-a-B-c-blah')['status'] == 200
- assert self.get(url='/a-B-c')['status'] == 200
- assert self.get(url='/aBc')['status'] == 200
- assert self.get(url='/aBCaBbc')['status'] == 200
- assert self.get(url='/ABc')['status'] == 404
+ assert client.get()['status'] == 200, 'GET'
- def test_routes_empty_regex(self):
- if not option.available['modules']['regex']:
- pytest.skip('requires regex')
- self.route_match({"uri": "~"})
- assert self.get(url='/')['status'] == 200, 'empty regexp'
- assert self.get(url='/anything')['status'] == 200, '/anything'
+def test_routes_match_wildcard_right_case_insensitive():
+ route_match({"method": "get*"})
+ assert client.get()['status'] == 200, 'GET'
- self.route_match({"uri": "!~"})
- assert self.get(url='/')['status'] == 404, 'empty regexp 2'
- assert self.get(url='/nothing')['status'] == 404, '/nothing'
+ route_match({"method": "ge*"})
+ assert client.get()['status'] == 200, 'GET'
- def test_routes_bad_regex(self):
- if not option.available['modules']['regex']:
- pytest.skip('requires regex')
- assert 'error' in self.route(
- {"match": {"uri": "~/bl[ah"}, "action": {"return": 200}}
- ), 'bad regex'
+def test_routes_match_wildcard_substring_case_insensitive():
+ route_match({"method": "*et*"})
- status = self.route(
- {"match": {"uri": "~(?R)?z"}, "action": {"return": 200}}
- )
- if 'error' not in status:
- assert self.get(url='/nothing_z')['status'] == 500, '/nothing_z'
+ assert client.get()['status'] == 200, 'GET'
- status = self.route(
- {"match": {"uri": "~((?1)?z)"}, "action": {"return": 200}}
- )
- if 'error' not in status:
- assert self.get(url='/nothing_z')['status'] == 500, '/nothing_z'
- def test_routes_match_regex_case_sensitive(self):
- if not option.available['modules']['regex']:
- pytest.skip('requires regex')
+def test_routes_match_wildcard_left_case_sensitive():
+ route_match({"uri": "*blah"})
- self.route_match({"uri": "~/bl[ah]"})
+ assert client.get(url='/blah')['status'] == 200, '/blah'
+ assert client.get(url='/BLAH')['status'] == 404, '/BLAH'
- assert self.get(url='/rlah')['status'] == 404, '/rlah'
- assert self.get(url='/blah')['status'] == 200, '/blah'
- assert self.get(url='/blh')['status'] == 200, '/blh'
- assert self.get(url='/BLAH')['status'] == 404, '/BLAH'
- def test_routes_match_regex_negative_case_sensitive(self):
- if not option.available['modules']['regex']:
- pytest.skip('requires regex')
+def test_routes_match_wildcard_middle_case_sensitive():
+ route_match({"uri": "/b*h"})
- self.route_match({"uri": "!~/bl[ah]"})
+ assert client.get(url='/blah')['status'] == 200, '/blah'
+ assert client.get(url='/BLAH')['status'] == 404, '/BLAH'
- assert self.get(url='/rlah')['status'] == 200, '/rlah'
- assert self.get(url='/blah')['status'] == 404, '/blah'
- assert self.get(url='/blh')['status'] == 404, '/blh'
- assert self.get(url='/BLAH')['status'] == 200, '/BLAH'
- def test_routes_pass_encode(self):
- python_dir = f'{option.test_dir}/python'
+def test_route_match_wildcards_ordered():
+ route_match({"uri": "/a*x*y*"})
- def check_pass(path, name):
- assert 'success' in self.conf(
- {
- "listeners": {"*:7080": {"pass": f'applications/{path}'}},
- "applications": {
- name: {
- "type": self.get_application_type(),
- "processes": {"spare": 0},
- "path": f'{python_dir}/empty',
- "working_directory": f'{python_dir}/empty',
- "module": "wsgi",
- }
- },
- }
- )
+ assert client.get(url='/axy')['status'] == 200, '/axy'
+ assert client.get(url='/ayx')['status'] == 404, '/ayx'
- assert self.get()['status'] == 200
- check_pass("%25", "%")
- check_pass("blah%2Fblah", "blah/blah")
- check_pass("%2Fblah%2F%2Fblah%2F", "/blah//blah/")
- check_pass("%20blah%252Fblah%7E", " blah%2Fblah~")
+def test_route_match_wildcards_adjust_start():
+ route_match({"uri": "/bla*bla*"})
- def check_pass_error(path, name):
- assert 'error' in self.conf(
- {
- "listeners": {"*:7080": {"pass": f'applications/{path}'}},
- "applications": {
- name: {
- "type": self.get_application_type(),
- "processes": {"spare": 0},
- "path": f'{python_dir}/empty',
- "working_directory": f'{python_dir}/empty',
- "module": "wsgi",
- }
- },
- }
- )
+ assert client.get(url='/bla_foo')['status'] == 404, '/bla_foo'
- check_pass_error("%", "%")
- check_pass_error("%1", "%1")
- def test_routes_absent(self):
- assert 'success' in self.conf(
- {
- "listeners": {"*:7081": {"pass": "applications/empty"}},
- "applications": {
- "empty": {
- "type": self.get_application_type(),
- "processes": {"spare": 0},
- "path": f'{option.test_dir}/python/empty',
- "working_directory": f'{option.test_dir}/python/empty',
- "module": "wsgi",
- }
- },
- }
- )
+def test_route_match_wildcards_adjust_start_substr():
+ route_match({"uri": "*bla*bla*"})
- assert self.get(port=7081)['status'] == 200, 'routes absent'
+ assert client.get(url='/bla_foo')['status'] == 404, '/bla_foo'
- def test_routes_pass_invalid(self):
- assert 'error' in self.conf(
- {"pass": "routes/blah"}, 'listeners/*:7080'
- ), 'routes invalid'
- def test_route_empty(self):
- assert 'success' in self.conf(
- {
- "listeners": {"*:7080": {"pass": "routes/main"}},
- "routes": {"main": []},
- "applications": {},
- }
- ), 'route empty configure'
+def test_route_match_wildcards_adjust_end():
+ route_match({"uri": "/bla*bla"})
- assert self.get()['status'] == 404, 'route empty'
+ assert client.get(url='/foo_bla')['status'] == 404, '/foo_bla'
- def test_routes_route_empty(self):
- assert 'success' in self.conf(
- {}, 'listeners'
- ), 'routes empty listeners configure'
- assert 'success' in self.conf({}, 'routes'), 'routes empty configure'
+def test_routes_match_wildcard_right_case_sensitive():
+ route_match({"uri": "/bla*"})
- def test_routes_route_match_absent(self):
- assert 'success' in self.conf(
- [{"action": {"return": 200}}], 'routes'
- ), 'route match absent configure'
+ assert client.get(url='/blah')['status'] == 200, '/blah'
+ assert client.get(url='/BLAH')['status'] == 404, '/BLAH'
- assert self.get()['status'] == 200, 'route match absent'
- def test_routes_route_action_absent(self, skip_alert):
- skip_alert(r'failed to apply new conf')
+def test_routes_match_wildcard_substring_case_sensitive():
+ route_match({"uri": "*bla*"})
- assert 'error' in self.conf(
- [{"match": {"method": "GET"}}], 'routes'
- ), 'route pass absent configure'
+ assert client.get(url='/blah')['status'] == 200, '/blah'
+ assert client.get(url='/BLAH')['status'] == 404, '/BLAH'
- def test_routes_route_pass(self):
- assert 'success' in self.conf(
- {
- "applications": {
- "app": {
- "type": self.get_application_type(),
- "processes": {"spare": 0},
- "path": "/app",
- "module": "wsgi",
- }
- },
- "upstreams": {
- "one": {
- "servers": {
- "127.0.0.1:7081": {},
- "127.0.0.1:7082": {},
- },
- },
- "two": {
- "servers": {
- "127.0.0.1:7081": {},
- "127.0.0.1:7082": {},
- },
- },
- },
- }
- )
- assert 'success' in self.conf(
- [{"action": {"pass": "routes"}}], 'routes'
- )
- assert 'success' in self.conf(
- [{"action": {"pass": "applications/app"}}], 'routes'
- )
- assert 'success' in self.conf(
- [{"action": {"pass": "upstreams/one"}}], 'routes'
- )
+def test_routes_match_many_wildcard_substrings_case_sensitive():
+ route_match({"uri": "*a*B*c*"})
+
+ assert client.get(url='/blah-a-B-c-blah')['status'] == 200
+ assert client.get(url='/a-B-c')['status'] == 200
+ assert client.get(url='/aBc')['status'] == 200
+ assert client.get(url='/aBCaBbc')['status'] == 200
+ assert client.get(url='/ABc')['status'] == 404
+
+
+def test_routes_empty_regex(require):
+ require({'modules': {'regex': True}})
+
+ route_match({"uri": "~"})
+ assert client.get(url='/')['status'] == 200, 'empty regexp'
+ assert client.get(url='/anything')['status'] == 200, '/anything'
+
+ route_match({"uri": "!~"})
+ assert client.get(url='/')['status'] == 404, 'empty regexp 2'
+ assert client.get(url='/nothing')['status'] == 404, '/nothing'
+
+
+def test_routes_bad_regex(require):
+ require({'modules': {'regex': True}})
+
+ assert 'error' in route(
+ {"match": {"uri": "~/bl[ah"}, "action": {"return": 200}}
+ ), 'bad regex'
+
+ status = route({"match": {"uri": "~(?R)?z"}, "action": {"return": 200}})
+ if 'error' not in status:
+ assert client.get(url='/nothing_z')['status'] == 500, '/nothing_z'
- def test_routes_route_pass_absent(self):
- assert 'error' in self.conf(
- [{"match": {"method": "GET"}, "action": {}}], 'routes'
- ), 'route pass absent configure'
+ status = route({"match": {"uri": "~((?1)?z)"}, "action": {"return": 200}})
+ if 'error' not in status:
+ assert client.get(url='/nothing_z')['status'] == 500, '/nothing_z'
- def test_routes_route_pass_invalid(self):
- assert 'success' in self.conf(
+
+def test_routes_match_regex_case_sensitive(require):
+ require({'modules': {'regex': True}})
+
+ route_match({"uri": "~/bl[ah]"})
+
+ assert client.get(url='/rlah')['status'] == 404, '/rlah'
+ assert client.get(url='/blah')['status'] == 200, '/blah'
+ assert client.get(url='/blh')['status'] == 200, '/blh'
+ assert client.get(url='/BLAH')['status'] == 404, '/BLAH'
+
+
+def test_routes_match_regex_negative_case_sensitive(require):
+ require({'modules': {'regex': True}})
+
+ route_match({"uri": "!~/bl[ah]"})
+
+ assert client.get(url='/rlah')['status'] == 200, '/rlah'
+ assert client.get(url='/blah')['status'] == 404, '/blah'
+ assert client.get(url='/blh')['status'] == 404, '/blh'
+ assert client.get(url='/BLAH')['status'] == 200, '/BLAH'
+
+
+def test_routes_pass_encode():
+ python_dir = f'{option.test_dir}/python'
+
+ def check_pass(path, name):
+ assert 'success' in client.conf(
{
+ "listeners": {"*:7080": {"pass": f'applications/{path}'}},
"applications": {
- "app": {
- "type": self.get_application_type(),
+ name: {
+ "type": client.get_application_type(),
"processes": {"spare": 0},
- "path": "/app",
+ "path": f'{python_dir}/empty',
+ "working_directory": f'{python_dir}/empty',
"module": "wsgi",
}
},
- "upstreams": {
- "one": {
- "servers": {
- "127.0.0.1:7081": {},
- "127.0.0.1:7082": {},
- },
- },
- "two": {
- "servers": {
- "127.0.0.1:7081": {},
- "127.0.0.1:7082": {},
- },
- },
- },
}
)
- assert 'error' in self.conf(
- [{"action": {"pass": "blah"}}], 'routes'
- ), 'route pass invalid'
- assert 'error' in self.conf(
- [{"action": {"pass": "routes/blah"}}], 'routes'
- ), 'route pass routes invalid'
- assert 'error' in self.conf(
- [{"action": {"pass": "applications/blah"}}], 'routes'
- ), 'route pass applications invalid'
- assert 'error' in self.conf(
- [{"action": {"pass": "upstreams/blah"}}], 'routes'
- ), 'route pass upstreams invalid'
-
- def test_routes_action_unique(self, temp_dir):
- assert 'success' in self.conf(
+ assert client.get()['status'] == 200
+
+ check_pass("%25", "%")
+ check_pass("blah%2Fblah", "blah/blah")
+ check_pass("%2Fblah%2F%2Fblah%2F", "/blah//blah/")
+ check_pass("%20blah%252Fblah%7E", " blah%2Fblah~")
+
+ def check_pass_error(path, name):
+ assert 'error' in client.conf(
{
- "listeners": {
- "*:7080": {"pass": "routes"},
- "*:7081": {"pass": "applications/app"},
- },
- "routes": [{"action": {"proxy": "http://127.0.0.1:7081"}}],
+ "listeners": {"*:7080": {"pass": f'applications/{path}'}},
"applications": {
- "app": {
- "type": self.get_application_type(),
+ name: {
+ "type": client.get_application_type(),
"processes": {"spare": 0},
- "path": "/app",
+ "path": f'{python_dir}/empty',
+ "working_directory": f'{python_dir}/empty',
"module": "wsgi",
}
},
}
)
- assert 'error' in self.conf(
- {"proxy": "http://127.0.0.1:7081", "share": temp_dir},
- 'routes/0/action',
- ), 'proxy share'
- assert 'error' in self.conf(
- {
- "proxy": "http://127.0.0.1:7081",
- "pass": "applications/app",
+ check_pass_error("%", "%")
+ check_pass_error("%1", "%1")
+
+
+def test_routes_absent():
+ assert 'success' in client.conf(
+ {
+ "listeners": {"*:7081": {"pass": "applications/empty"}},
+ "applications": {
+ "empty": {
+ "type": client.get_application_type(),
+ "processes": {"spare": 0},
+ "path": f'{option.test_dir}/python/empty',
+ "working_directory": f'{option.test_dir}/python/empty',
+ "module": "wsgi",
+ }
},
- 'routes/0/action',
- ), 'proxy pass'
- assert 'error' in self.conf(
- {"share": temp_dir, "pass": "applications/app"},
- 'routes/0/action',
- ), 'share pass'
-
- def test_routes_rules_two(self):
- assert 'success' in self.conf(
- [
- {"match": {"method": "GET"}, "action": {"return": 200}},
- {"match": {"method": "POST"}, "action": {"return": 201}},
- ],
- 'routes',
- ), 'rules two configure'
+ }
+ )
- assert self.get()['status'] == 200, 'rules two match first'
- assert self.post()['status'] == 201, 'rules two match second'
+ assert client.get(port=7081)['status'] == 200, 'routes absent'
- def test_routes_two(self):
- assert 'success' in self.conf(
- {
- "listeners": {"*:7080": {"pass": "routes/first"}},
- "routes": {
- "first": [
- {
- "match": {"method": "GET"},
- "action": {"pass": "routes/second"},
- }
- ],
- "second": [
- {
- "match": {"host": "localhost"},
- "action": {"return": 200},
- }
- ],
+
+def test_routes_pass_invalid():
+ assert 'error' in client.conf(
+ {"pass": "routes/blah"}, 'listeners/*:7080'
+ ), 'routes invalid'
+
+
+def test_route_empty():
+ assert 'success' in client.conf(
+ {
+ "listeners": {"*:7080": {"pass": "routes/main"}},
+ "routes": {"main": []},
+ "applications": {},
+ }
+ ), 'route empty configure'
+
+ assert client.get()['status'] == 404, 'route empty'
+
+
+def test_routes_route_empty():
+ assert 'success' in client.conf(
+ {}, 'listeners'
+ ), 'routes empty listeners configure'
+
+ assert 'success' in client.conf({}, 'routes'), 'routes empty configure'
+
+
+def test_routes_route_match_absent():
+ assert 'success' in client.conf(
+ [{"action": {"return": 200}}], 'routes'
+ ), 'route match absent configure'
+
+ assert client.get()['status'] == 200, 'route match absent'
+
+
+def test_routes_route_action_absent(skip_alert):
+ skip_alert(r'failed to apply new conf')
+
+ assert 'error' in client.conf(
+ [{"match": {"method": "GET"}}], 'routes'
+ ), 'route pass absent configure'
+
+
+def test_routes_route_pass():
+ assert 'success' in client.conf(
+ {
+ "applications": {
+ "app": {
+ "type": client.get_application_type(),
+ "processes": {"spare": 0},
+ "path": "/app",
+ "module": "wsgi",
+ }
+ },
+ "upstreams": {
+ "one": {
+ "servers": {
+ "127.0.0.1:7081": {},
+ "127.0.0.1:7082": {},
+ },
},
- "applications": {},
- }
- ), 'routes two configure'
+ "two": {
+ "servers": {
+ "127.0.0.1:7081": {},
+ "127.0.0.1:7082": {},
+ },
+ },
+ },
+ }
+ )
+
+ assert 'success' in client.conf([{"action": {"pass": "routes"}}], 'routes')
+ assert 'success' in client.conf(
+ [{"action": {"pass": "applications/app"}}], 'routes'
+ )
+ assert 'success' in client.conf(
+ [{"action": {"pass": "upstreams/one"}}], 'routes'
+ )
+
+
+def test_routes_route_pass_absent():
+ assert 'error' in client.conf(
+ [{"match": {"method": "GET"}, "action": {}}], 'routes'
+ ), 'route pass absent configure'
+
+
+def test_routes_route_pass_invalid():
+ assert 'success' in client.conf(
+ {
+ "applications": {
+ "app": {
+ "type": client.get_application_type(),
+ "processes": {"spare": 0},
+ "path": "/app",
+ "module": "wsgi",
+ }
+ },
+ "upstreams": {
+ "one": {
+ "servers": {
+ "127.0.0.1:7081": {},
+ "127.0.0.1:7082": {},
+ },
+ },
+ "two": {
+ "servers": {
+ "127.0.0.1:7081": {},
+ "127.0.0.1:7082": {},
+ },
+ },
+ },
+ }
+ )
+
+ assert 'error' in client.conf(
+ [{"action": {"pass": "blah"}}], 'routes'
+ ), 'route pass invalid'
+ assert 'error' in client.conf(
+ [{"action": {"pass": "routes/blah"}}], 'routes'
+ ), 'route pass routes invalid'
+ assert 'error' in client.conf(
+ [{"action": {"pass": "applications/blah"}}], 'routes'
+ ), 'route pass applications invalid'
+ assert 'error' in client.conf(
+ [{"action": {"pass": "upstreams/blah"}}], 'routes'
+ ), 'route pass upstreams invalid'
+
+
+def test_routes_action_unique(temp_dir):
+ assert 'success' in client.conf(
+ {
+ "listeners": {
+ "*:7080": {"pass": "routes"},
+ "*:7081": {"pass": "applications/app"},
+ },
+ "routes": [{"action": {"proxy": "http://127.0.0.1:7081"}}],
+ "applications": {
+ "app": {
+ "type": client.get_application_type(),
+ "processes": {"spare": 0},
+ "path": "/app",
+ "module": "wsgi",
+ }
+ },
+ }
+ )
+
+ assert 'error' in client.conf(
+ {"proxy": "http://127.0.0.1:7081", "share": temp_dir},
+ 'routes/0/action',
+ ), 'proxy share'
+ assert 'error' in client.conf(
+ {
+ "proxy": "http://127.0.0.1:7081",
+ "pass": "applications/app",
+ },
+ 'routes/0/action',
+ ), 'proxy pass'
+ assert 'error' in client.conf(
+ {"share": temp_dir, "pass": "applications/app"},
+ 'routes/0/action',
+ ), 'share pass'
+
+
+def test_routes_rules_two():
+ assert 'success' in client.conf(
+ [
+ {"match": {"method": "GET"}, "action": {"return": 200}},
+ {"match": {"method": "POST"}, "action": {"return": 201}},
+ ],
+ 'routes',
+ ), 'rules two configure'
+
+ assert client.get()['status'] == 200, 'rules two match first'
+ assert client.post()['status'] == 201, 'rules two match second'
+
+
+def test_routes_two():
+ assert 'success' in client.conf(
+ {
+ "listeners": {"*:7080": {"pass": "routes/first"}},
+ "routes": {
+ "first": [
+ {
+ "match": {"method": "GET"},
+ "action": {"pass": "routes/second"},
+ }
+ ],
+ "second": [
+ {
+ "match": {"host": "localhost"},
+ "action": {"return": 200},
+ }
+ ],
+ },
+ "applications": {},
+ }
+ ), 'routes two configure'
- assert self.get()['status'] == 200, 'routes two'
+ assert client.get()['status'] == 200, 'routes two'
- def test_routes_match_host_positive(self):
- self.route_match({"host": "localhost"})
- assert self.get()['status'] == 200, 'localhost'
- self.host('localhost.', 200)
- self.host('localhost.', 200)
- self.host('.localhost', 404)
- self.host('www.localhost', 404)
- self.host('localhost1', 404)
+def test_routes_match_host_positive():
+ route_match({"host": "localhost"})
- @pytest.mark.skip('not yet')
- def test_routes_match_host_absent(self):
- self.route_match({"host": "localhost"})
+ assert client.get()['status'] == 200, 'localhost'
+ host('localhost.', 200)
+ host('localhost.', 200)
+ host('.localhost', 404)
+ host('www.localhost', 404)
+ host('localhost1', 404)
- assert (
- self.get(headers={'Connection': 'close'})['status'] == 400
- ), 'match host absent'
- def test_routes_match_host_ipv4(self):
- self.route_match({"host": "127.0.0.1"})
+@pytest.mark.skip('not yet')
+def test_routes_match_host_absent():
+ route_match({"host": "localhost"})
- self.host('127.0.0.1', 200)
- self.host('127.0.0.1:7080', 200)
+ assert (
+ client.get(headers={'Connection': 'close'})['status'] == 400
+ ), 'match host absent'
- def test_routes_match_host_ipv6(self):
- self.route_match({"host": "[::1]"})
- self.host('[::1]', 200)
- self.host('[::1]:7080', 200)
+def test_routes_match_host_ipv4():
+ route_match({"host": "127.0.0.1"})
- def test_routes_match_host_positive_many(self):
- self.route_match({"host": ["localhost", "example.com"]})
+ host('127.0.0.1', 200)
+ host('127.0.0.1:7080', 200)
- assert self.get()['status'] == 200, 'localhost'
- self.host('example.com', 200)
- def test_routes_match_host_positive_and_negative(self):
- self.route_match({"host": ["*example.com", "!www.example.com"]})
+def test_routes_match_host_ipv6():
+ route_match({"host": "[::1]"})
- assert self.get()['status'] == 404, 'localhost'
- self.host('example.com', 200)
- self.host('www.example.com', 404)
- self.host('!www.example.com', 200)
+ host('[::1]', 200)
+ host('[::1]:7080', 200)
- def test_routes_match_host_positive_and_negative_wildcard(self):
- self.route_match({"host": ["*example*", "!www.example*"]})
- self.host('example.com', 200)
- self.host('www.example.com', 404)
+def test_routes_match_host_positive_many():
+ route_match({"host": ["localhost", "example.com"]})
- def test_routes_match_host_case_insensitive(self):
- self.route_match({"host": "Example.com"})
+ assert client.get()['status'] == 200, 'localhost'
+ host('example.com', 200)
- self.host('example.com', 200)
- self.host('EXAMPLE.COM', 200)
- def test_routes_match_host_port(self):
- self.route_match({"host": "example.com"})
+def test_routes_match_host_positive_and_negative():
+ route_match({"host": ["*example.com", "!www.example.com"]})
- self.host('example.com:7080', 200)
+ assert client.get()['status'] == 404, 'localhost'
+ host('example.com', 200)
+ host('www.example.com', 404)
+ host('!www.example.com', 200)
- def test_routes_match_host_empty(self):
- self.route_match({"host": ""})
- self.host('', 200)
- assert (
- self.get(http_10=True, headers={})['status'] == 200
- ), 'match host empty 2'
- assert self.get()['status'] == 404, 'match host empty 3'
-
- def test_routes_match_uri_positive(self):
- self.route_match({"uri": ["/blah", "/slash/"]})
-
- assert self.get()['status'] == 404, '/'
- assert self.get(url='/blah')['status'] == 200, '/blah'
- assert self.get(url='/blah#foo')['status'] == 200, '/blah#foo'
- assert self.get(url='/blah?var')['status'] == 200, '/blah?var'
- assert self.get(url='//blah')['status'] == 200, '//blah'
- assert self.get(url='/slash/foo/../')['status'] == 200, 'relative'
- assert self.get(url='/slash/./')['status'] == 200, '/slash/./'
- assert self.get(url='/slash//.//')['status'] == 200, 'adjacent slashes'
- assert self.get(url='/%')['status'] == 400, 'percent'
- assert self.get(url='/%1')['status'] == 400, 'percent digit'
- assert self.get(url='/%A')['status'] == 400, 'percent letter'
- assert self.get(url='/slash/.?args')['status'] == 200, 'dot args'
- assert self.get(url='/slash/.#frag')['status'] == 200, 'dot frag'
- assert (
- self.get(url='/slash/foo/..?args')['status'] == 200
- ), 'dot dot args'
- assert (
- self.get(url='/slash/foo/..#frag')['status'] == 200
- ), 'dot dot frag'
- assert self.get(url='/slash/.')['status'] == 200, 'trailing dot'
- assert (
- self.get(url='/slash/foo/..')['status'] == 200
- ), 'trailing dot dot'
+def test_routes_match_host_positive_and_negative_wildcard():
+ route_match({"host": ["*example*", "!www.example*"]})
- def test_routes_match_uri_case_sensitive(self):
- self.route_match({"uri": "/BLAH"})
+ host('example.com', 200)
+ host('www.example.com', 404)
- assert self.get(url='/blah')['status'] == 404, '/blah'
- assert self.get(url='/BlaH')['status'] == 404, '/BlaH'
- assert self.get(url='/BLAH')['status'] == 200, '/BLAH'
- def test_routes_match_uri_normalize(self):
- self.route_match({"uri": "/blah"})
+def test_routes_match_host_case_insensitive():
+ route_match({"host": "Example.com"})
- assert self.get(url='/%62%6c%61%68')['status'] == 200, 'normalize'
+ host('example.com', 200)
+ host('EXAMPLE.COM', 200)
- def test_routes_match_empty_array(self):
- self.route_match({"uri": []})
- assert self.get(url='/blah')['status'] == 200, 'empty array'
+def test_routes_match_host_port():
+ route_match({"host": "example.com"})
- def test_routes_reconfigure(self):
- assert 'success' in self.conf([], 'routes'), 'redefine'
- assert self.get()['status'] == 404, 'redefine request'
+ host('example.com:7080', 200)
- assert 'success' in self.conf(
- [{"action": {"return": 200}}], 'routes'
- ), 'redefine 2'
- assert self.get()['status'] == 200, 'redefine request 2'
- assert 'success' in self.conf([], 'routes'), 'redefine 3'
- assert self.get()['status'] == 404, 'redefine request 3'
+def test_routes_match_host_empty():
+ route_match({"host": ""})
- assert 'success' in self.conf(
- {
- "listeners": {"*:7080": {"pass": "routes/main"}},
- "routes": {"main": [{"action": {"return": 200}}]},
- "applications": {},
- }
- ), 'redefine 4'
- assert self.get()['status'] == 200, 'redefine request 4'
-
- assert 'success' in self.conf_delete('routes/main/0'), 'redefine 5'
- assert self.get()['status'] == 404, 'redefine request 5'
-
- assert 'success' in self.conf_post(
- {"action": {"return": 200}}, 'routes/main'
- ), 'redefine 6'
- assert self.get()['status'] == 200, 'redefine request 6'
-
- assert 'error' in self.conf(
- {"action": {"return": 200}}, 'routes/main/2'
- ), 'redefine 7'
- assert 'success' in self.conf(
- {"action": {"return": 201}}, 'routes/main/1'
- ), 'redefine 8'
-
- assert len(self.conf_get('routes/main')) == 2, 'redefine conf 8'
- assert self.get()['status'] == 200, 'redefine request 8'
-
- def test_routes_edit(self):
- self.route_match({"method": "GET"})
-
- assert self.get()['status'] == 200, 'routes edit GET'
- assert self.post()['status'] == 404, 'routes edit POST'
-
- assert 'success' in self.conf_post(
- {"match": {"method": "POST"}, "action": {"return": 200}},
- 'routes',
- ), 'routes edit configure 2'
- assert 'GET' == self.conf_get(
- 'routes/0/match/method'
- ), 'routes edit configure 2 check'
- assert 'POST' == self.conf_get(
- 'routes/1/match/method'
- ), 'routes edit configure 2 check 2'
-
- assert self.get()['status'] == 200, 'routes edit GET 2'
- assert self.post()['status'] == 200, 'routes edit POST 2'
-
- assert 'success' in self.conf_delete(
- 'routes/0'
- ), 'routes edit configure 3'
-
- assert self.get()['status'] == 404, 'routes edit GET 3'
- assert self.post()['status'] == 200, 'routes edit POST 3'
-
- assert 'error' in self.conf_delete(
- 'routes/1'
- ), 'routes edit configure invalid'
- assert 'error' in self.conf_delete(
- 'routes/-1'
- ), 'routes edit configure invalid 2'
- assert 'error' in self.conf_delete(
- 'routes/blah'
- ), 'routes edit configure invalid 3'
-
- assert self.get()['status'] == 404, 'routes edit GET 4'
- assert self.post()['status'] == 200, 'routes edit POST 4'
-
- assert 'success' in self.conf_delete(
- 'routes/0'
- ), 'routes edit configure 5'
-
- assert self.get()['status'] == 404, 'routes edit GET 5'
- assert self.post()['status'] == 404, 'routes edit POST 5'
-
- assert 'success' in self.conf_post(
- {"match": {"method": "POST"}, "action": {"return": 200}},
- 'routes',
- ), 'routes edit configure 6'
-
- assert self.get()['status'] == 404, 'routes edit GET 6'
- assert self.post()['status'] == 200, 'routes edit POST 6'
-
- assert 'success' in self.conf(
- {
- "listeners": {"*:7080": {"pass": "routes/main"}},
- "routes": {"main": [{"action": {"return": 200}}]},
- "applications": {},
- }
- ), 'route edit configure 7'
-
- assert 'error' in self.conf_delete(
- 'routes/0'
- ), 'routes edit configure invalid 4'
- assert 'error' in self.conf_delete(
- 'routes/main'
- ), 'routes edit configure invalid 5'
-
- assert self.get()['status'] == 200, 'routes edit GET 7'
-
- assert 'success' in self.conf_delete(
- 'listeners/*:7080'
- ), 'route edit configure 8'
- assert 'success' in self.conf_delete(
- 'routes/main'
- ), 'route edit configure 9'
-
- def test_match_edit(self, skip_alert):
- skip_alert(r'failed to apply new conf')
-
- self.route_match({"method": ["GET", "POST"]})
-
- assert self.get()['status'] == 200, 'match edit GET'
- assert self.post()['status'] == 200, 'match edit POST'
- assert self.put()['status'] == 404, 'match edit PUT'
-
- assert 'success' in self.conf_post(
- '\"PUT\"', 'routes/0/match/method'
- ), 'match edit configure 2'
- assert ['GET', 'POST', 'PUT'] == self.conf_get(
- 'routes/0/match/method'
- ), 'match edit configure 2 check'
-
- assert self.get()['status'] == 200, 'match edit GET 2'
- assert self.post()['status'] == 200, 'match edit POST 2'
- assert self.put()['status'] == 200, 'match edit PUT 2'
-
- assert 'success' in self.conf_delete(
- 'routes/0/match/method/1'
- ), 'match edit configure 3'
- assert ['GET', 'PUT'] == self.conf_get(
- 'routes/0/match/method'
- ), 'match edit configure 3 check'
-
- assert self.get()['status'] == 200, 'match edit GET 3'
- assert self.post()['status'] == 404, 'match edit POST 3'
- assert self.put()['status'] == 200, 'match edit PUT 3'
-
- assert 'success' in self.conf_delete(
- 'routes/0/match/method/1'
- ), 'match edit configure 4'
- assert ['GET'] == self.conf_get(
- 'routes/0/match/method'
- ), 'match edit configure 4 check'
-
- assert self.get()['status'] == 200, 'match edit GET 4'
- assert self.post()['status'] == 404, 'match edit POST 4'
- assert self.put()['status'] == 404, 'match edit PUT 4'
-
- assert 'error' in self.conf_delete(
- 'routes/0/match/method/1'
- ), 'match edit configure invalid'
- assert 'error' in self.conf_delete(
- 'routes/0/match/method/-1'
- ), 'match edit configure invalid 2'
- assert 'error' in self.conf_delete(
- 'routes/0/match/method/blah'
- ), 'match edit configure invalid 3'
- assert ['GET'] == self.conf_get(
- 'routes/0/match/method'
- ), 'match edit configure 5 check'
-
- assert self.get()['status'] == 200, 'match edit GET 5'
- assert self.post()['status'] == 404, 'match edit POST 5'
- assert self.put()['status'] == 404, 'match edit PUT 5'
-
- assert 'success' in self.conf_delete(
- 'routes/0/match/method/0'
- ), 'match edit configure 6'
- assert [] == self.conf_get(
- 'routes/0/match/method'
- ), 'match edit configure 6 check'
-
- assert self.get()['status'] == 200, 'match edit GET 6'
- assert self.post()['status'] == 200, 'match edit POST 6'
- assert self.put()['status'] == 200, 'match edit PUT 6'
-
- assert 'success' in self.conf(
- '"GET"', 'routes/0/match/method'
- ), 'match edit configure 7'
-
- assert self.get()['status'] == 200, 'match edit GET 7'
- assert self.post()['status'] == 404, 'match edit POST 7'
- assert self.put()['status'] == 404, 'match edit PUT 7'
-
- assert 'error' in self.conf_delete(
- 'routes/0/match/method/0'
- ), 'match edit configure invalid 5'
- assert 'error' in self.conf(
- {}, 'routes/0/action'
- ), 'match edit configure invalid 6'
-
- assert 'success' in self.conf(
- {}, 'routes/0/match'
- ), 'match edit configure 8'
-
- assert self.get()['status'] == 200, 'match edit GET 8'
-
- def test_routes_match_rules(self):
- self.route_match({"method": "GET", "host": "localhost", "uri": "/"})
-
- assert self.get()['status'] == 200, 'routes match rules'
-
- def test_routes_loop(self):
- assert 'success' in self.route(
- {"match": {"uri": "/"}, "action": {"pass": "routes"}}
- ), 'routes loop configure'
-
- assert self.get()['status'] == 500, 'routes loop'
-
- def test_routes_match_headers(self):
- self.route_match({"headers": {"host": "localhost"}})
-
- assert self.get()['status'] == 200, 'match headers'
- self.host('Localhost', 200)
- self.host('localhost.com', 404)
- self.host('llocalhost', 404)
- self.host('host', 404)
-
- def test_routes_match_headers_multiple(self):
- self.route_match({"headers": {"host": "localhost", "x-blah": "test"}})
-
- assert self.get()['status'] == 404, 'match headers multiple'
- assert (
- self.get(
- headers={
- "Host": "localhost",
- "X-blah": "test",
- "Connection": "close",
- }
- )['status']
- == 200
- ), 'match headers multiple 2'
+ host('', 200)
+ assert (
+ client.get(http_10=True, headers={})['status'] == 200
+ ), 'match host empty 2'
+ assert client.get()['status'] == 404, 'match host empty 3'
- assert (
- self.get(
- headers={
- "Host": "localhost",
- "X-blah": "",
- "Connection": "close",
- }
- )['status']
- == 404
- ), 'match headers multiple 3'
- def test_routes_match_headers_multiple_values(self):
- self.route_match({"headers": {"x-blah": "test"}})
+def test_routes_match_uri_positive():
+ route_match({"uri": ["/blah", "/slash/"]})
- assert (
- self.get(
- headers={
- "Host": "localhost",
- "X-blah": ["test", "test", "test"],
- "Connection": "close",
- }
- )['status']
- == 200
- ), 'match headers multiple values'
- assert (
- self.get(
- headers={
- "Host": "localhost",
- "X-blah": ["test", "blah", "test"],
- "Connection": "close",
- }
- )['status']
- == 404
- ), 'match headers multiple values 2'
- assert (
- self.get(
- headers={
- "Host": "localhost",
- "X-blah": ["test", "", "test"],
- "Connection": "close",
- }
- )['status']
- == 404
- ), 'match headers multiple values 3'
+ assert client.get()['status'] == 404, '/'
+ assert client.get(url='/blah')['status'] == 200, '/blah'
+ assert client.get(url='/blah#foo')['status'] == 200, '/blah#foo'
+ assert client.get(url='/blah?var')['status'] == 200, '/blah?var'
+ assert client.get(url='//blah')['status'] == 200, '//blah'
+ assert client.get(url='/slash/foo/../')['status'] == 200, 'relative'
+ assert client.get(url='/slash/./')['status'] == 200, '/slash/./'
+ assert client.get(url='/slash//.//')['status'] == 200, 'adjacent slashes'
+ assert client.get(url='/%')['status'] == 400, 'percent'
+ assert client.get(url='/%1')['status'] == 400, 'percent digit'
+ assert client.get(url='/%A')['status'] == 400, 'percent letter'
+ assert client.get(url='/slash/.?args')['status'] == 200, 'dot args'
+ assert client.get(url='/slash/.#frag')['status'] == 200, 'dot frag'
+ assert client.get(url='/slash/foo/..?args')['status'] == 200, 'dot dot args'
+ assert client.get(url='/slash/foo/..#frag')['status'] == 200, 'dot dot frag'
+ assert client.get(url='/slash/.')['status'] == 200, 'trailing dot'
+ assert client.get(url='/slash/foo/..')['status'] == 200, 'trailing dot dot'
- def test_routes_match_headers_multiple_rules(self):
- self.route_match({"headers": {"x-blah": ["test", "blah"]}})
- assert self.get()['status'] == 404, 'match headers multiple rules'
- assert (
- self.get(
- headers={
- "Host": "localhost",
- "X-blah": "test",
- "Connection": "close",
- }
- )['status']
- == 200
- ), 'match headers multiple rules 2'
- assert (
- self.get(
- headers={
- "Host": "localhost",
- "X-blah": "blah",
- "Connection": "close",
- }
- )['status']
- == 200
- ), 'match headers multiple rules 3'
- assert (
- self.get(
- headers={
- "Host": "localhost",
- "X-blah": ["test", "blah", "test"],
- "Connection": "close",
- }
- )['status']
- == 200
- ), 'match headers multiple rules 4'
+def test_routes_match_uri_case_sensitive():
+ route_match({"uri": "/BLAH"})
- assert (
- self.get(
- headers={
- "Host": "localhost",
- "X-blah": ["blah", ""],
- "Connection": "close",
- }
- )['status']
- == 404
- ), 'match headers multiple rules 5'
+ assert client.get(url='/blah')['status'] == 404, '/blah'
+ assert client.get(url='/BlaH')['status'] == 404, '/BlaH'
+ assert client.get(url='/BLAH')['status'] == 200, '/BLAH'
- def test_routes_match_headers_case_insensitive(self):
- self.route_match({"headers": {"X-BLAH": "TEST"}})
- assert (
- self.get(
- headers={
- "Host": "localhost",
- "x-blah": "test",
- "Connection": "close",
- }
- )['status']
- == 200
- ), 'match headers case insensitive'
+def test_routes_match_uri_normalize():
+ route_match({"uri": "/blah"})
- def test_routes_match_headers_invalid(self):
- self.route_match_invalid({"headers": ["blah"]})
- self.route_match_invalid({"headers": {"foo": ["bar", {}]}})
- self.route_match_invalid({"headers": {"": "blah"}})
+ assert client.get(url='/%62%6c%61%68')['status'] == 200, 'normalize'
- def test_routes_match_headers_empty_rule(self):
- self.route_match({"headers": {"host": ""}})
- assert self.get()['status'] == 404, 'localhost'
- self.host('', 200)
+def test_routes_match_empty_array():
+ route_match({"uri": []})
- def test_routes_match_headers_empty(self):
- self.route_match({"headers": {}})
- assert self.get()['status'] == 200, 'empty'
+ assert client.get(url='/blah')['status'] == 200, 'empty array'
- self.route_match({"headers": []})
- assert self.get()['status'] == 200, 'empty 2'
- def test_routes_match_headers_rule_array_empty(self):
- self.route_match({"headers": {"blah": []}})
+def test_routes_reconfigure():
+ assert 'success' in client.conf([], 'routes'), 'redefine'
+ assert client.get()['status'] == 404, 'redefine request'
- assert self.get()['status'] == 404, 'array empty'
- assert (
- self.get(
- headers={
- "Host": "localhost",
- "blah": "foo",
- "Connection": "close",
- }
- )['status']
- == 200
- ), 'match headers rule array empty 2'
+ assert 'success' in client.conf(
+ [{"action": {"return": 200}}], 'routes'
+ ), 'redefine 2'
+ assert client.get()['status'] == 200, 'redefine request 2'
- def test_routes_match_headers_array(self):
- self.route_match(
- {
- "headers": [
- {"x-header1": "foo*"},
- {"x-header2": "bar"},
- {"x-header3": ["foo", "bar"]},
- {"x-header1": "bar", "x-header4": "foo"},
- ]
- }
- )
+ assert 'success' in client.conf([], 'routes'), 'redefine 3'
+ assert client.get()['status'] == 404, 'redefine request 3'
- def check_headers(hds):
- hds = dict({"Host": "localhost", "Connection": "close"}, **hds)
- assert self.get(headers=hds)['status'] == 200, 'headers array match'
-
- def check_headers_404(hds):
- hds = dict({"Host": "localhost", "Connection": "close"}, **hds)
- assert (
- self.get(headers=hds)['status'] == 404
- ), 'headers array no match'
-
- assert self.get()['status'] == 404, 'match headers array'
- check_headers({"x-header1": "foo123"})
- check_headers({"x-header2": "bar"})
- check_headers({"x-header3": "bar"})
- check_headers_404({"x-header1": "bar"})
- check_headers({"x-header1": "bar", "x-header4": "foo"})
-
- assert 'success' in self.conf_delete(
- 'routes/0/match/headers/1'
- ), 'match headers array configure 2'
-
- check_headers_404({"x-header2": "bar"})
- check_headers({"x-header3": "foo"})
-
- def test_routes_match_arguments(self):
- self.route_match({"arguments": {"foo": "bar"}})
-
- assert self.get()['status'] == 404, 'args'
- assert self.get(url='/?foo=bar')['status'] == 200, 'args 2'
- assert self.get(url='/?foo=bar1')['status'] == 404, 'args 3'
- assert self.get(url='/?1foo=bar')['status'] == 404, 'args 4'
- assert self.get(url='/?Foo=bar')['status'] == 404, 'case'
- assert self.get(url='/?foo=Bar')['status'] == 404, 'case 2'
-
- def test_routes_match_arguments_chars(self):
- chars = (
- " !\"%23$%25%26'()*%2B,-./0123456789:;<%3D>?@"
- "ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"
- )
+ assert 'success' in client.conf(
+ {
+ "listeners": {"*:7080": {"pass": "routes/main"}},
+ "routes": {"main": [{"action": {"return": 200}}]},
+ "applications": {},
+ }
+ ), 'redefine 4'
+ assert client.get()['status'] == 200, 'redefine request 4'
- chars_enc = ""
- for h1 in ["2", "3", "4", "5", "6", "7"]:
- for h2 in [
- "0",
- "1",
- "2",
- "3",
- "4",
- "5",
- "6",
- "7",
- "8",
- "9",
- "A",
- "B",
- "C",
- "D",
- "E",
- "F",
- ]:
- chars_enc += f'%{h1}{h2}'
- chars_enc = chars_enc[:-3]
-
- def check_args(args, query):
- self.route_match({"arguments": args})
- assert self.get(url=f'/?{query}')['status'] == 200
-
- check_args({chars: chars}, f'{chars}={chars}')
- check_args({chars: chars}, f'{chars}={chars_enc}')
- check_args({chars: chars}, f'{chars_enc}={chars}')
- check_args({chars: chars}, f'{chars_enc}={chars_enc}')
- check_args({chars_enc: chars_enc}, f'{chars}={chars}')
- check_args({chars_enc: chars_enc}, f'{chars}={chars_enc}')
- check_args({chars_enc: chars_enc}, f'{chars_enc}={chars}')
- check_args({chars_enc: chars_enc}, f'{chars_enc}={chars_enc}')
-
- def test_routes_match_arguments_empty(self):
- self.route_match({"arguments": {}})
- assert self.get()['status'] == 200, 'arguments empty'
-
- self.route_match({"arguments": []})
- assert self.get()['status'] == 200, 'arguments empty 2'
-
- def test_routes_match_arguments_space(self):
- self.route_match({"arguments": {"+fo o%20": "%20b+a r"}})
- assert self.get(url='/? fo o = b a r&')['status'] == 200
- assert self.get(url='/?+fo+o+=+b+a+r&')['status'] == 200
- assert self.get(url='/?%20fo%20o%20=%20b%20a%20r&')['status'] == 200
-
- self.route_match({"arguments": {"%20foo": " bar"}})
- assert self.get(url='/? foo= bar')['status'] == 200
- assert self.get(url='/?+foo=+bar')['status'] == 200
- assert self.get(url='/?%20foo=%20bar')['status'] == 200
- assert self.get(url='/?+foo= bar')['status'] == 200
- assert self.get(url='/?%20foo=+bar')['status'] == 200
-
- def test_routes_match_arguments_equal(self):
- self.route_match({"arguments": {"=": "="}})
- assert self.get(url='/?%3D=%3D')['status'] == 200
- assert self.get(url='/?%3D==')['status'] == 200
- assert self.get(url='/?===')['status'] == 404
- assert self.get(url='/?%3D%3D%3D')['status'] == 404
- assert self.get(url='/?==%3D')['status'] == 404
-
- def test_routes_match_arguments_enc(self):
- self.route_match({"arguments": {"Ю": "н"}})
- assert self.get(url='/?%D0%AE=%D0%BD')['status'] == 200
- assert self.get(url='/?%d0%ae=%d0%Bd')['status'] == 200
-
- def test_routes_match_arguments_hash(self):
- self.route_match({"arguments": {"#": "#"}})
- assert self.get(url='/?%23=%23')['status'] == 200
- assert self.get(url='/?%23=%23#')['status'] == 200
- assert self.get(url='/?#=#')['status'] == 404
- assert self.get(url='/?%23=#')['status'] == 404
-
- def test_routes_match_arguments_wildcard(self):
- self.route_match({"arguments": {"foo": "*"}})
- assert self.get(url='/?foo')['status'] == 200
- assert self.get(url='/?foo=')['status'] == 200
- assert self.get(url='/?foo=blah')['status'] == 200
- assert self.get(url='/?blah=foo')['status'] == 404
-
- self.route_match({"arguments": {"foo": "%25*"}})
- assert self.get(url='/?foo=%xx')['status'] == 200
-
- self.route_match({"arguments": {"foo": "%2A*"}})
- assert self.get(url='/?foo=*xx')['status'] == 200
- assert self.get(url='/?foo=xx')['status'] == 404
-
- self.route_match({"arguments": {"foo": "*%2A"}})
- assert self.get(url='/?foo=xx*')['status'] == 200
- assert self.get(url='/?foo=xx*x')['status'] == 404
-
- self.route_match({"arguments": {"foo": "1*2"}})
- assert self.get(url='/?foo=12')['status'] == 200
- assert self.get(url='/?foo=1blah2')['status'] == 200
- assert self.get(url='/?foo=1%2A2')['status'] == 200
- assert self.get(url='/?foo=x12')['status'] == 404
-
- self.route_match({"arguments": {"foo": "bar*", "%25": "%25"}})
- assert self.get(url='/?foo=barxx&%=%')['status'] == 200
- assert self.get(url='/?foo=barxx&x%=%')['status'] == 404
-
- def test_routes_match_arguments_negative(self):
- self.route_match({"arguments": {"foo": "!"}})
- assert self.get(url='/?bar')['status'] == 404
- assert self.get(url='/?foo')['status'] == 404
- assert self.get(url='/?foo=')['status'] == 404
- assert self.get(url='/?foo=%25')['status'] == 200
-
- self.route_match({"arguments": {"foo": "!*"}})
- assert self.get(url='/?bar')['status'] == 404
- assert self.get(url='/?foo')['status'] == 404
- assert self.get(url='/?foo=')['status'] == 404
- assert self.get(url='/?foo=blah')['status'] == 404
-
- self.route_match({"arguments": {"foo": "!%25"}})
- assert self.get(url='/?foo=blah')['status'] == 200
- assert self.get(url='/?foo=%')['status'] == 404
-
- self.route_match({"arguments": {"foo": "%21blah"}})
- assert self.get(url='/?foo=%21blah')['status'] == 200
- assert self.get(url='/?foo=!blah')['status'] == 200
- assert self.get(url='/?foo=bar')['status'] == 404
-
- self.route_match({"arguments": {"foo": "!!%21*a"}})
- assert self.get(url='/?foo=blah')['status'] == 200
- assert self.get(url='/?foo=!blah')['status'] == 200
- assert self.get(url='/?foo=!!a')['status'] == 404
- assert self.get(url='/?foo=!!bla')['status'] == 404
-
- def test_routes_match_arguments_percent(self):
- self.route_match({"arguments": {"%25": "%25"}})
- assert self.get(url='/?%=%')['status'] == 200
- assert self.get(url='/?%25=%25')['status'] == 200
- assert self.get(url='/?%25=%')['status'] == 200
-
- self.route_match({"arguments": {"%251": "%252"}})
- assert self.get(url='/?%1=%2')['status'] == 200
- assert self.get(url='/?%251=%252')['status'] == 200
- assert self.get(url='/?%251=%2')['status'] == 200
-
- self.route_match({"arguments": {"%25%21%251": "%25%24%252"}})
- assert self.get(url='/?%!%1=%$%2')['status'] == 200
- assert self.get(url='/?%25!%251=%25$%252')['status'] == 200
- assert self.get(url='/?%25!%1=%$%2')['status'] == 200
-
- def test_routes_match_arguments_ampersand(self):
- self.route_match({"arguments": {"foo": "&"}})
- assert self.get(url='/?foo=%26')['status'] == 200
- assert self.get(url='/?foo=%26&')['status'] == 200
- assert self.get(url='/?foo=%26%26')['status'] == 404
- assert self.get(url='/?foo=&')['status'] == 404
-
- self.route_match({"arguments": {"&": ""}})
- assert self.get(url='/?%26=')['status'] == 200
- assert self.get(url='/?%26=&')['status'] == 200
- assert self.get(url='/?%26=%26')['status'] == 404
- assert self.get(url='/?&=')['status'] == 404
-
- def test_routes_match_arguments_complex(self):
- self.route_match({"arguments": {"foo": ""}})
-
- assert self.get(url='/?foo')['status'] == 200, 'complex'
- assert self.get(url='/?blah=blah&foo=')['status'] == 200, 'complex 2'
- assert self.get(url='/?&&&foo&&&')['status'] == 200, 'complex 3'
- assert self.get(url='/?foo&foo=bar&foo')['status'] == 404, 'complex 4'
- assert self.get(url='/?foo=&foo')['status'] == 200, 'complex 5'
- assert self.get(url='/?&=&foo&==&')['status'] == 200, 'complex 6'
- assert self.get(url='/?&=&bar&==&')['status'] == 404, 'complex 7'
-
- def test_routes_match_arguments_multiple(self):
- self.route_match({"arguments": {"foo": "bar", "blah": "test"}})
-
- assert self.get()['status'] == 404, 'multiple'
- assert (
- self.get(url='/?foo=bar&blah=test')['status'] == 200
- ), 'multiple 2'
- assert self.get(url='/?foo=bar&blah')['status'] == 404, 'multiple 3'
- assert self.get(url='/?foo=bar&blah=tes')['status'] == 404, 'multiple 4'
- assert (
- self.get(url='/?foo=b%61r&bl%61h=t%65st')['status'] == 200
- ), 'multiple 5'
+ assert 'success' in client.conf_delete('routes/main/0'), 'redefine 5'
+ assert client.get()['status'] == 404, 'redefine request 5'
- def test_routes_match_arguments_multiple_rules(self):
- self.route_match({"arguments": {"foo": ["bar", "blah"]}})
+ assert 'success' in client.conf_post(
+ {"action": {"return": 200}}, 'routes/main'
+ ), 'redefine 6'
+ assert client.get()['status'] == 200, 'redefine request 6'
- assert self.get()['status'] == 404, 'rules'
- assert self.get(url='/?foo=bar')['status'] == 200, 'rules 2'
- assert self.get(url='/?foo=blah')['status'] == 200, 'rules 3'
- assert (
- self.get(url='/?foo=blah&foo=bar&foo=blah')['status'] == 200
- ), 'rules 4'
- assert (
- self.get(url='/?foo=blah&foo=bar&foo=')['status'] == 404
- ), 'rules 5'
+ assert 'error' in client.conf(
+ {"action": {"return": 200}}, 'routes/main/2'
+ ), 'redefine 7'
+ assert 'success' in client.conf(
+ {"action": {"return": 201}}, 'routes/main/1'
+ ), 'redefine 8'
- def test_routes_match_arguments_array(self):
- self.route_match(
- {
- "arguments": [
- {"var1": "val1*"},
- {"var2": "val2"},
- {"var3": ["foo", "bar"]},
- {"var1": "bar", "var4": "foo"},
- ]
+ assert len(client.conf_get('routes/main')) == 2, 'redefine conf 8'
+ assert client.get()['status'] == 200, 'redefine request 8'
+
+
+def test_routes_edit():
+ route_match({"method": "GET"})
+
+ assert client.get()['status'] == 200, 'routes edit GET'
+ assert client.post()['status'] == 404, 'routes edit POST'
+
+ assert 'success' in client.conf_post(
+ {"match": {"method": "POST"}, "action": {"return": 200}},
+ 'routes',
+ ), 'routes edit configure 2'
+ assert 'GET' == client.conf_get(
+ 'routes/0/match/method'
+ ), 'routes edit configure 2 check'
+ assert 'POST' == client.conf_get(
+ 'routes/1/match/method'
+ ), 'routes edit configure 2 check 2'
+
+ assert client.get()['status'] == 200, 'routes edit GET 2'
+ assert client.post()['status'] == 200, 'routes edit POST 2'
+
+ assert 'success' in client.conf_delete(
+ 'routes/0'
+ ), 'routes edit configure 3'
+
+ assert client.get()['status'] == 404, 'routes edit GET 3'
+ assert client.post()['status'] == 200, 'routes edit POST 3'
+
+ assert 'error' in client.conf_delete(
+ 'routes/1'
+ ), 'routes edit configure invalid'
+ assert 'error' in client.conf_delete(
+ 'routes/-1'
+ ), 'routes edit configure invalid 2'
+ assert 'error' in client.conf_delete(
+ 'routes/blah'
+ ), 'routes edit configure invalid 3'
+
+ assert client.get()['status'] == 404, 'routes edit GET 4'
+ assert client.post()['status'] == 200, 'routes edit POST 4'
+
+ assert 'success' in client.conf_delete(
+ 'routes/0'
+ ), 'routes edit configure 5'
+
+ assert client.get()['status'] == 404, 'routes edit GET 5'
+ assert client.post()['status'] == 404, 'routes edit POST 5'
+
+ assert 'success' in client.conf_post(
+ {"match": {"method": "POST"}, "action": {"return": 200}},
+ 'routes',
+ ), 'routes edit configure 6'
+
+ assert client.get()['status'] == 404, 'routes edit GET 6'
+ assert client.post()['status'] == 200, 'routes edit POST 6'
+
+ assert 'success' in client.conf(
+ {
+ "listeners": {"*:7080": {"pass": "routes/main"}},
+ "routes": {"main": [{"action": {"return": 200}}]},
+ "applications": {},
+ }
+ ), 'route edit configure 7'
+
+ assert 'error' in client.conf_delete(
+ 'routes/0'
+ ), 'routes edit configure invalid 4'
+ assert 'error' in client.conf_delete(
+ 'routes/main'
+ ), 'routes edit configure invalid 5'
+
+ assert client.get()['status'] == 200, 'routes edit GET 7'
+
+ assert 'success' in client.conf_delete(
+ 'listeners/*:7080'
+ ), 'route edit configure 8'
+ assert 'success' in client.conf_delete(
+ 'routes/main'
+ ), 'route edit configure 9'
+
+
+def test_match_edit(skip_alert):
+ skip_alert(r'failed to apply new conf')
+
+ route_match({"method": ["GET", "POST"]})
+
+ assert client.get()['status'] == 200, 'match edit GET'
+ assert client.post()['status'] == 200, 'match edit POST'
+ assert client.put()['status'] == 404, 'match edit PUT'
+
+ assert 'success' in client.conf_post(
+ '\"PUT\"', 'routes/0/match/method'
+ ), 'match edit configure 2'
+ assert ['GET', 'POST', 'PUT'] == client.conf_get(
+ 'routes/0/match/method'
+ ), 'match edit configure 2 check'
+
+ assert client.get()['status'] == 200, 'match edit GET 2'
+ assert client.post()['status'] == 200, 'match edit POST 2'
+ assert client.put()['status'] == 200, 'match edit PUT 2'
+
+ assert 'success' in client.conf_delete(
+ 'routes/0/match/method/1'
+ ), 'match edit configure 3'
+ assert ['GET', 'PUT'] == client.conf_get(
+ 'routes/0/match/method'
+ ), 'match edit configure 3 check'
+
+ assert client.get()['status'] == 200, 'match edit GET 3'
+ assert client.post()['status'] == 404, 'match edit POST 3'
+ assert client.put()['status'] == 200, 'match edit PUT 3'
+
+ assert 'success' in client.conf_delete(
+ 'routes/0/match/method/1'
+ ), 'match edit configure 4'
+ assert ['GET'] == client.conf_get(
+ 'routes/0/match/method'
+ ), 'match edit configure 4 check'
+
+ assert client.get()['status'] == 200, 'match edit GET 4'
+ assert client.post()['status'] == 404, 'match edit POST 4'
+ assert client.put()['status'] == 404, 'match edit PUT 4'
+
+ assert 'error' in client.conf_delete(
+ 'routes/0/match/method/1'
+ ), 'match edit configure invalid'
+ assert 'error' in client.conf_delete(
+ 'routes/0/match/method/-1'
+ ), 'match edit configure invalid 2'
+ assert 'error' in client.conf_delete(
+ 'routes/0/match/method/blah'
+ ), 'match edit configure invalid 3'
+ assert ['GET'] == client.conf_get(
+ 'routes/0/match/method'
+ ), 'match edit configure 5 check'
+
+ assert client.get()['status'] == 200, 'match edit GET 5'
+ assert client.post()['status'] == 404, 'match edit POST 5'
+ assert client.put()['status'] == 404, 'match edit PUT 5'
+
+ assert 'success' in client.conf_delete(
+ 'routes/0/match/method/0'
+ ), 'match edit configure 6'
+ assert [] == client.conf_get(
+ 'routes/0/match/method'
+ ), 'match edit configure 6 check'
+
+ assert client.get()['status'] == 200, 'match edit GET 6'
+ assert client.post()['status'] == 200, 'match edit POST 6'
+ assert client.put()['status'] == 200, 'match edit PUT 6'
+
+ assert 'success' in client.conf(
+ '"GET"', 'routes/0/match/method'
+ ), 'match edit configure 7'
+
+ assert client.get()['status'] == 200, 'match edit GET 7'
+ assert client.post()['status'] == 404, 'match edit POST 7'
+ assert client.put()['status'] == 404, 'match edit PUT 7'
+
+ assert 'error' in client.conf_delete(
+ 'routes/0/match/method/0'
+ ), 'match edit configure invalid 5'
+ assert 'error' in client.conf(
+ {}, 'routes/0/action'
+ ), 'match edit configure invalid 6'
+
+ assert 'success' in client.conf(
+ {}, 'routes/0/match'
+ ), 'match edit configure 8'
+
+ assert client.get()['status'] == 200, 'match edit GET 8'
+
+
+def test_routes_match_rules():
+ route_match({"method": "GET", "host": "localhost", "uri": "/"})
+
+ assert client.get()['status'] == 200, 'routes match rules'
+
+
+def test_routes_loop():
+ assert 'success' in route(
+ {"match": {"uri": "/"}, "action": {"pass": "routes"}}
+ ), 'routes loop configure'
+
+ assert client.get()['status'] == 500, 'routes loop'
+
+
+def test_routes_match_headers():
+ route_match({"headers": {"host": "localhost"}})
+
+ assert client.get()['status'] == 200, 'match headers'
+ host('Localhost', 200)
+ host('localhost.com', 404)
+ host('llocalhost', 404)
+ host('host', 404)
+
+
+def test_routes_match_headers_multiple():
+ route_match({"headers": {"host": "localhost", "x-blah": "test"}})
+
+ assert client.get()['status'] == 404, 'match headers multiple'
+ assert (
+ client.get(
+ headers={
+ "Host": "localhost",
+ "X-blah": "test",
+ "Connection": "close",
}
- )
+ )['status']
+ == 200
+ ), 'match headers multiple 2'
+
+ assert (
+ client.get(
+ headers={
+ "Host": "localhost",
+ "X-blah": "",
+ "Connection": "close",
+ }
+ )['status']
+ == 404
+ ), 'match headers multiple 3'
- assert self.get()['status'] == 404, 'arr'
- assert self.get(url='/?var1=val123')['status'] == 200, 'arr 2'
- assert self.get(url='/?var2=val2')['status'] == 200, 'arr 3'
- assert self.get(url='/?var3=bar')['status'] == 200, 'arr 4'
- assert self.get(url='/?var1=bar')['status'] == 404, 'arr 5'
- assert self.get(url='/?var1=bar&var4=foo')['status'] == 200, 'arr 6'
-
- assert 'success' in self.conf_delete(
- 'routes/0/match/arguments/1'
- ), 'match arguments array configure 2'
-
- assert self.get(url='/?var2=val2')['status'] == 404, 'arr 7'
- assert self.get(url='/?var3=foo')['status'] == 200, 'arr 8'
-
- def test_routes_match_arguments_invalid(self):
- self.route_match_invalid({"arguments": ["var"]})
- self.route_match_invalid({"arguments": [{"var1": {}}]})
- self.route_match_invalid({"arguments": {"": "bar"}})
- self.route_match_invalid({"arguments": {"foo": "%"}})
- self.route_match_invalid({"arguments": {"foo": "%1G"}})
- self.route_match_invalid({"arguments": {"%": "bar"}})
- self.route_match_invalid({"arguments": {"foo": "%0"}})
- self.route_match_invalid({"arguments": {"foo": "%%1F"}})
- self.route_match_invalid({"arguments": {"%%1F": ""}})
- self.route_match_invalid({"arguments": {"%7%F": ""}})
-
- def test_routes_match_query(self):
- self.route_match({"query": "!"})
- assert self.get(url='/')['status'] == 404
- assert self.get(url='/?')['status'] == 404
- assert self.get(url='/?foo')['status'] == 200
- assert self.get(url='/?foo=')['status'] == 200
- assert self.get(url='/?foo=baz')['status'] == 200
-
- self.route_match({"query": "foo=%26"})
- assert self.get(url='/?foo=&')['status'] == 200
-
- self.route_match({"query": "a=b&c=d"})
- assert self.get(url='/?a=b&c=d')['status'] == 200
-
- self.route_match({"query": "a=b%26c%3Dd"})
- assert self.get(url='/?a=b%26c%3Dd')['status'] == 200
- assert self.get(url='/?a=b&c=d')['status'] == 200
-
- self.route_match({"query": "a=b%26c%3Dd+e"})
- assert self.get(url='/?a=b&c=d e')['status'] == 200
-
- def test_routes_match_query_array(self):
- self.route_match({"query": ["foo", "bar"]})
-
- assert self.get()['status'] == 404, 'no args'
- assert self.get(url='/?foo')['status'] == 200, 'arg first'
- assert self.get(url='/?bar')['status'] == 200, 'arg second'
-
- assert 'success' in self.conf_delete(
- 'routes/0/match/query/1'
- ), 'query array remove second'
-
- assert self.get(url='/?foo')['status'] == 200, 'still arg first'
- assert self.get(url='/?bar')['status'] == 404, 'no arg second'
-
- self.route_match({"query": ["!f", "foo"]})
-
- assert self.get(url='/?f')['status'] == 404, 'negative arg'
- assert self.get(url='/?fo')['status'] == 404, 'negative arg 2'
- assert self.get(url='/?foo')['status'] == 200, 'negative arg 3'
-
- self.route_match({"query": []})
- assert self.get()['status'] == 200, 'empty array'
-
- def test_routes_match_query_invalid(self):
- self.route_match_invalid({"query": [1]})
- self.route_match_invalid({"query": "%"})
- self.route_match_invalid({"query": "%1G"})
- self.route_match_invalid({"query": "%0"})
- self.route_match_invalid({"query": "%%1F"})
- self.route_match_invalid({"query": ["foo", "%3D", "%%1F"]})
-
- def test_routes_match_cookies(self):
- self.route_match({"cookies": {"foO": "bar"}})
-
- assert self.get()['status'] == 404, 'cookie'
- self.cookie('foO=bar', 200)
- self.cookie('foO=bar;1', 200)
- self.cookie(['foO=bar', 'blah=blah'], 200)
- self.cookie('foO=bar; blah=blah', 200)
- self.cookie('Foo=bar', 404)
- self.cookie('foO=Bar', 404)
- self.cookie('foO=bar1', 404)
- self.cookie('1foO=bar;', 404)
-
- def test_routes_match_cookies_empty(self):
- self.route_match({"cookies": {}})
- assert self.get()['status'] == 200, 'cookies empty'
-
- self.route_match({"cookies": []})
- assert self.get()['status'] == 200, 'cookies empty 2'
-
- def test_routes_match_cookies_invalid(self):
- self.route_match_invalid({"cookies": ["var"]})
- self.route_match_invalid({"cookies": [{"foo": {}}]})
-
- def test_routes_match_cookies_complex(self):
- self.route_match({"cookies": {"foo": "bar=baz"}})
- self.cookie('foo=bar=baz', 200)
- self.cookie(' foo=bar=baz ', 200)
- self.cookie('=foo=bar=baz', 404)
-
- self.route_match({"cookies": {"foo": ""}})
- self.cookie('foo=', 200)
- self.cookie('foo=;', 200)
- self.cookie(' foo=;', 200)
- self.cookie('foo', 404)
- self.cookie('', 404)
- self.cookie('=', 404)
-
- def test_routes_match_cookies_multiple(self):
- self.route_match({"cookies": {"foo": "bar", "blah": "blah"}})
-
- assert self.get()['status'] == 404, 'multiple'
- self.cookie('foo=bar; blah=blah', 200)
- self.cookie(['foo=bar', 'blah=blah'], 200)
- self.cookie(['foo=bar; blah', 'blah'], 404)
- self.cookie(['foo=bar; blah=test', 'blah=blah'], 404)
-
- def test_routes_match_cookies_multiple_values(self):
- self.route_match({"cookies": {"blah": "blah"}})
-
- self.cookie(['blah=blah', 'blah=blah', 'blah=blah'], 200)
- self.cookie(['blah=blah', 'blah=test', 'blah=blah'], 404)
- self.cookie(['blah=blah; blah=', 'blah=blah'], 404)
-
- def test_routes_match_cookies_multiple_rules(self):
- self.route_match({"cookies": {"blah": ["test", "blah"]}})
-
- assert self.get()['status'] == 404, 'multiple rules'
- self.cookie('blah=test', 200)
- self.cookie('blah=blah', 200)
- self.cookie(['blah=blah', 'blah=test', 'blah=blah'], 200)
- self.cookie(['blah=blah; blah=test', 'blah=blah'], 200)
- self.cookie(['blah=blah', 'blah'], 200) # invalid cookie
-
- def test_routes_match_cookies_array(self):
- self.route_match(
- {
- "cookies": [
- {"var1": "val1*"},
- {"var2": "val2"},
- {"var3": ["foo", "bar"]},
- {"var1": "bar", "var4": "foo"},
- ]
+
+def test_routes_match_headers_multiple_values():
+ route_match({"headers": {"x-blah": "test"}})
+
+ assert (
+ client.get(
+ headers={
+ "Host": "localhost",
+ "X-blah": ["test", "test", "test"],
+ "Connection": "close",
}
- )
+ )['status']
+ == 200
+ ), 'match headers multiple values'
+ assert (
+ client.get(
+ headers={
+ "Host": "localhost",
+ "X-blah": ["test", "blah", "test"],
+ "Connection": "close",
+ }
+ )['status']
+ == 404
+ ), 'match headers multiple values 2'
+ assert (
+ client.get(
+ headers={
+ "Host": "localhost",
+ "X-blah": ["test", "", "test"],
+ "Connection": "close",
+ }
+ )['status']
+ == 404
+ ), 'match headers multiple values 3'
- assert self.get()['status'] == 404, 'cookies array'
- self.cookie('var1=val123', 200)
- self.cookie('var2=val2', 200)
- self.cookie(' var2=val2 ', 200)
- self.cookie('var3=bar', 200)
- self.cookie('var3=bar;', 200)
- self.cookie('var1=bar', 404)
- self.cookie('var1=bar; var4=foo;', 200)
- self.cookie(['var1=bar', 'var4=foo'], 200)
-
- assert 'success' in self.conf_delete(
- 'routes/0/match/cookies/1'
- ), 'match cookies array configure 2'
-
- self.cookie('var2=val2', 404)
- self.cookie('var3=foo', 200)
-
- def test_routes_match_scheme(self):
- self.route_match({"scheme": "http"})
- self.route_match({"scheme": "https"})
- self.route_match({"scheme": "HtTp"})
- self.route_match({"scheme": "HtTpS"})
-
- def test_routes_match_scheme_invalid(self):
- self.route_match_invalid({"scheme": ["http"]})
- self.route_match_invalid({"scheme": "ftp"})
- self.route_match_invalid({"scheme": "ws"})
- self.route_match_invalid({"scheme": "*"})
- self.route_match_invalid({"scheme": ""})
-
- def test_routes_source_port(self):
- def sock_port():
- sock = self.http(b'', raw=True, no_recv=True)
- port = sock.getsockname()[1]
- return (sock, port)
-
- sock, port = sock_port()
- sock2, port2 = sock_port()
-
- self.route_match({"source": f'127.0.0.1:{port}'})
- assert self.get(sock=sock)['status'] == 200, 'exact'
- assert self.get(sock=sock2)['status'] == 404, 'exact 2'
-
- sock, port = sock_port()
- sock2, port2 = sock_port()
-
- self.route_match({"source": f'!127.0.0.1:{port}'})
- assert self.get(sock=sock)['status'] == 404, 'negative'
- assert self.get(sock=sock2)['status'] == 200, 'negative 2'
-
- sock, port = sock_port()
- sock2, port2 = sock_port()
-
- self.route_match({"source": [f'*:{port}', "!127.0.0.1"]})
- assert self.get(sock=sock)['status'] == 404, 'negative 3'
- assert self.get(sock=sock2)['status'] == 404, 'negative 4'
-
- sock, port = sock_port()
- sock2, port2 = sock_port()
-
- self.route_match({"source": f'127.0.0.1:{port}-{port}'})
- assert self.get(sock=sock)['status'] == 200, 'range single'
- assert self.get(sock=sock2)['status'] == 404, 'range single 2'
-
- socks = [
- sock_port(),
- sock_port(),
- sock_port(),
- sock_port(),
- sock_port(),
- ]
- socks.sort(key=lambda sock: sock[1])
-
- self.route_match({"source": f'127.0.0.1:{socks[1][1]}-{socks[3][1]}'})
- assert self.get(sock=socks[0][0])['status'] == 404, 'range'
- assert self.get(sock=socks[1][0])['status'] == 200, 'range 2'
- assert self.get(sock=socks[2][0])['status'] == 200, 'range 3'
- assert self.get(sock=socks[3][0])['status'] == 200, 'range 4'
- assert self.get(sock=socks[4][0])['status'] == 404, 'range 5'
-
- socks = [
- sock_port(),
- sock_port(),
- sock_port(),
- ]
- socks.sort(key=lambda sock: sock[1])
-
- self.route_match(
- {
- "source": [
- f'127.0.0.1:{socks[0][1]}',
- f'127.0.0.1:{socks[2][1]}',
- ]
+
+def test_routes_match_headers_multiple_rules():
+ route_match({"headers": {"x-blah": ["test", "blah"]}})
+
+ assert client.get()['status'] == 404, 'match headers multiple rules'
+ assert (
+ client.get(
+ headers={
+ "Host": "localhost",
+ "X-blah": "test",
+ "Connection": "close",
}
- )
- assert self.get(sock=socks[0][0])['status'] == 200, 'array'
- assert self.get(sock=socks[1][0])['status'] == 404, 'array 2'
- assert self.get(sock=socks[2][0])['status'] == 200, 'array 3'
+ )['status']
+ == 200
+ ), 'match headers multiple rules 2'
+ assert (
+ client.get(
+ headers={
+ "Host": "localhost",
+ "X-blah": "blah",
+ "Connection": "close",
+ }
+ )['status']
+ == 200
+ ), 'match headers multiple rules 3'
+ assert (
+ client.get(
+ headers={
+ "Host": "localhost",
+ "X-blah": ["test", "blah", "test"],
+ "Connection": "close",
+ }
+ )['status']
+ == 200
+ ), 'match headers multiple rules 4'
+
+ assert (
+ client.get(
+ headers={
+ "Host": "localhost",
+ "X-blah": ["blah", ""],
+ "Connection": "close",
+ }
+ )['status']
+ == 404
+ ), 'match headers multiple rules 5'
- def test_routes_source_addr(self):
- assert 'success' in self.conf(
- {
- "*:7080": {"pass": "routes"},
- "[::1]:7081": {"pass": "routes"},
- },
- 'listeners',
- ), 'source listeners configure'
- def get_ipv6():
- return self.get(sock_type='ipv6', port=7081)
+def test_routes_match_headers_case_insensitive():
+ route_match({"headers": {"X-BLAH": "TEST"}})
- self.route_match({"source": "127.0.0.1"})
- assert self.get()['status'] == 200, 'exact'
- assert get_ipv6()['status'] == 404, 'exact ipv6'
+ assert (
+ client.get(
+ headers={
+ "Host": "localhost",
+ "x-blah": "test",
+ "Connection": "close",
+ }
+ )['status']
+ == 200
+ ), 'match headers case insensitive'
- self.route_match({"source": ["127.0.0.1"]})
- assert self.get()['status'] == 200, 'exact 2'
- assert get_ipv6()['status'] == 404, 'exact 2 ipv6'
- self.route_match({"source": "!127.0.0.1"})
- assert self.get()['status'] == 404, 'exact neg'
- assert get_ipv6()['status'] == 200, 'exact neg ipv6'
+def test_routes_match_headers_invalid():
+ route_match_invalid({"headers": ["blah"]})
+ route_match_invalid({"headers": {"foo": ["bar", {}]}})
+ route_match_invalid({"headers": {"": "blah"}})
- self.route_match({"source": "127.0.0.2"})
- assert self.get()['status'] == 404, 'exact 3'
- assert get_ipv6()['status'] == 404, 'exact 3 ipv6'
- self.route_match({"source": "127.0.0.1-127.0.0.1"})
- assert self.get()['status'] == 200, 'range single'
- assert get_ipv6()['status'] == 404, 'range single ipv6'
+def test_routes_match_headers_empty_rule():
+ route_match({"headers": {"host": ""}})
- self.route_match({"source": "127.0.0.2-127.0.0.2"})
- assert self.get()['status'] == 404, 'range single 2'
- assert get_ipv6()['status'] == 404, 'range single 2 ipv6'
+ assert client.get()['status'] == 404, 'localhost'
+ host('', 200)
- self.route_match({"source": "127.0.0.2-127.0.0.3"})
- assert self.get()['status'] == 404, 'range'
- assert get_ipv6()['status'] == 404, 'range ipv6'
- self.route_match({"source": "127.0.0.1-127.0.0.2"})
- assert self.get()['status'] == 200, 'range 2'
- assert get_ipv6()['status'] == 404, 'range 2 ipv6'
+def test_routes_match_headers_empty():
+ route_match({"headers": {}})
+ assert client.get()['status'] == 200, 'empty'
- self.route_match({"source": "127.0.0.0-127.0.0.2"})
- assert self.get()['status'] == 200, 'range 3'
- assert get_ipv6()['status'] == 404, 'range 3 ipv6'
+ route_match({"headers": []})
+ assert client.get()['status'] == 200, 'empty 2'
- self.route_match({"source": "127.0.0.0-127.0.0.1"})
- assert self.get()['status'] == 200, 'range 4'
- assert get_ipv6()['status'] == 404, 'range 4 ipv6'
- self.route_match({"source": "126.0.0.0-127.0.0.0"})
- assert self.get()['status'] == 404, 'range 5'
- assert get_ipv6()['status'] == 404, 'range 5 ipv6'
+def test_routes_match_headers_rule_array_empty():
+ route_match({"headers": {"blah": []}})
- self.route_match({"source": "126.126.126.126-127.0.0.2"})
- assert self.get()['status'] == 200, 'range 6'
- assert get_ipv6()['status'] == 404, 'range 6 ipv6'
+ assert client.get()['status'] == 404, 'array empty'
+ assert (
+ client.get(
+ headers={
+ "Host": "localhost",
+ "blah": "foo",
+ "Connection": "close",
+ }
+ )['status']
+ == 200
+ ), 'match headers rule array empty 2'
+
+
+def test_routes_match_headers_array():
+ route_match(
+ {
+ "headers": [
+ {"x-header1": "foo*"},
+ {"x-header2": "bar"},
+ {"x-header3": ["foo", "bar"]},
+ {"x-header1": "bar", "x-header4": "foo"},
+ ]
+ }
+ )
+
+ def check_headers(hds):
+ hds = dict({"Host": "localhost", "Connection": "close"}, **hds)
+ assert client.get(headers=hds)['status'] == 200, 'headers array match'
+
+ def check_headers_404(hds):
+ hds = dict({"Host": "localhost", "Connection": "close"}, **hds)
+ assert (
+ client.get(headers=hds)['status'] == 404
+ ), 'headers array no match'
+
+ assert client.get()['status'] == 404, 'match headers array'
+ check_headers({"x-header1": "foo123"})
+ check_headers({"x-header2": "bar"})
+ check_headers({"x-header3": "bar"})
+ check_headers_404({"x-header1": "bar"})
+ check_headers({"x-header1": "bar", "x-header4": "foo"})
+
+ assert 'success' in client.conf_delete(
+ 'routes/0/match/headers/1'
+ ), 'match headers array configure 2'
+
+ check_headers_404({"x-header2": "bar"})
+ check_headers({"x-header3": "foo"})
+
+
+def test_routes_match_arguments():
+ route_match({"arguments": {"foo": "bar"}})
+
+ assert client.get()['status'] == 404, 'args'
+ assert client.get(url='/?foo=bar')['status'] == 200, 'args 2'
+ assert client.get(url='/?foo=bar1')['status'] == 404, 'args 3'
+ assert client.get(url='/?1foo=bar')['status'] == 404, 'args 4'
+ assert client.get(url='/?Foo=bar')['status'] == 404, 'case'
+ assert client.get(url='/?foo=Bar')['status'] == 404, 'case 2'
+
+
+def test_routes_match_arguments_chars():
+ chars = (
+ " !\"%23$%25%26'()*%2B,-./0123456789:;<%3D>?@"
+ "ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~"
+ )
+
+ chars_enc = ""
+ for h1 in ["2", "3", "4", "5", "6", "7"]:
+ for h2 in [
+ "0",
+ "1",
+ "2",
+ "3",
+ "4",
+ "5",
+ "6",
+ "7",
+ "8",
+ "9",
+ "A",
+ "B",
+ "C",
+ "D",
+ "E",
+ "F",
+ ]:
+ chars_enc += f'%{h1}{h2}'
+ chars_enc = chars_enc[:-3]
+
+ def check_args(args, query):
+ route_match({"arguments": args})
+ assert client.get(url=f'/?{query}')['status'] == 200
+
+ check_args({chars: chars}, f'{chars}={chars}')
+ check_args({chars: chars}, f'{chars}={chars_enc}')
+ check_args({chars: chars}, f'{chars_enc}={chars}')
+ check_args({chars: chars}, f'{chars_enc}={chars_enc}')
+ check_args({chars_enc: chars_enc}, f'{chars}={chars}')
+ check_args({chars_enc: chars_enc}, f'{chars}={chars_enc}')
+ check_args({chars_enc: chars_enc}, f'{chars_enc}={chars}')
+ check_args({chars_enc: chars_enc}, f'{chars_enc}={chars_enc}')
+
+
+def test_routes_match_arguments_empty():
+ route_match({"arguments": {}})
+ assert client.get()['status'] == 200, 'arguments empty'
+
+ route_match({"arguments": []})
+ assert client.get()['status'] == 200, 'arguments empty 2'
+
+
+def test_routes_match_arguments_space():
+ route_match({"arguments": {"+fo o%20": "%20b+a r"}})
+ assert client.get(url='/? fo o = b a r&')['status'] == 200
+ assert client.get(url='/?+fo+o+=+b+a+r&')['status'] == 200
+ assert client.get(url='/?%20fo%20o%20=%20b%20a%20r&')['status'] == 200
+
+ route_match({"arguments": {"%20foo": " bar"}})
+ assert client.get(url='/? foo= bar')['status'] == 200
+ assert client.get(url='/?+foo=+bar')['status'] == 200
+ assert client.get(url='/?%20foo=%20bar')['status'] == 200
+ assert client.get(url='/?+foo= bar')['status'] == 200
+ assert client.get(url='/?%20foo=+bar')['status'] == 200
+
+
+def test_routes_match_arguments_equal():
+ route_match({"arguments": {"=": "="}})
+ assert client.get(url='/?%3D=%3D')['status'] == 200
+ assert client.get(url='/?%3D==')['status'] == 200
+ assert client.get(url='/?===')['status'] == 404
+ assert client.get(url='/?%3D%3D%3D')['status'] == 404
+ assert client.get(url='/?==%3D')['status'] == 404
+
+
+def test_routes_match_arguments_enc():
+ route_match({"arguments": {"Ю": "н"}})
+ assert client.get(url='/?%D0%AE=%D0%BD')['status'] == 200
+ assert client.get(url='/?%d0%ae=%d0%Bd')['status'] == 200
+
+
+def test_routes_match_arguments_hash():
+ route_match({"arguments": {"#": "#"}})
+ assert client.get(url='/?%23=%23')['status'] == 200
+ assert client.get(url='/?%23=%23#')['status'] == 200
+ assert client.get(url='/?#=#')['status'] == 404
+ assert client.get(url='/?%23=#')['status'] == 404
+
+
+def test_routes_match_arguments_wildcard():
+ route_match({"arguments": {"foo": "*"}})
+ assert client.get(url='/?foo')['status'] == 200
+ assert client.get(url='/?foo=')['status'] == 200
+ assert client.get(url='/?foo=blah')['status'] == 200
+ assert client.get(url='/?blah=foo')['status'] == 404
+
+ route_match({"arguments": {"foo": "%25*"}})
+ assert client.get(url='/?foo=%xx')['status'] == 200
+
+ route_match({"arguments": {"foo": "%2A*"}})
+ assert client.get(url='/?foo=*xx')['status'] == 200
+ assert client.get(url='/?foo=xx')['status'] == 404
+
+ route_match({"arguments": {"foo": "*%2A"}})
+ assert client.get(url='/?foo=xx*')['status'] == 200
+ assert client.get(url='/?foo=xx*x')['status'] == 404
+
+ route_match({"arguments": {"foo": "1*2"}})
+ assert client.get(url='/?foo=12')['status'] == 200
+ assert client.get(url='/?foo=1blah2')['status'] == 200
+ assert client.get(url='/?foo=1%2A2')['status'] == 200
+ assert client.get(url='/?foo=x12')['status'] == 404
+
+ route_match({"arguments": {"foo": "bar*", "%25": "%25"}})
+ assert client.get(url='/?foo=barxx&%=%')['status'] == 200
+ assert client.get(url='/?foo=barxx&x%=%')['status'] == 404
+
+
+def test_routes_match_arguments_negative():
+ route_match({"arguments": {"foo": "!"}})
+ assert client.get(url='/?bar')['status'] == 404
+ assert client.get(url='/?foo')['status'] == 404
+ assert client.get(url='/?foo=')['status'] == 404
+ assert client.get(url='/?foo=%25')['status'] == 200
+
+ route_match({"arguments": {"foo": "!*"}})
+ assert client.get(url='/?bar')['status'] == 404
+ assert client.get(url='/?foo')['status'] == 404
+ assert client.get(url='/?foo=')['status'] == 404
+ assert client.get(url='/?foo=blah')['status'] == 404
+
+ route_match({"arguments": {"foo": "!%25"}})
+ assert client.get(url='/?foo=blah')['status'] == 200
+ assert client.get(url='/?foo=%')['status'] == 404
+
+ route_match({"arguments": {"foo": "%21blah"}})
+ assert client.get(url='/?foo=%21blah')['status'] == 200
+ assert client.get(url='/?foo=!blah')['status'] == 200
+ assert client.get(url='/?foo=bar')['status'] == 404
+
+ route_match({"arguments": {"foo": "!!%21*a"}})
+ assert client.get(url='/?foo=blah')['status'] == 200
+ assert client.get(url='/?foo=!blah')['status'] == 200
+ assert client.get(url='/?foo=!!a')['status'] == 404
+ assert client.get(url='/?foo=!!bla')['status'] == 404
+
+
+def test_routes_match_arguments_percent():
+ route_match({"arguments": {"%25": "%25"}})
+ assert client.get(url='/?%=%')['status'] == 200
+ assert client.get(url='/?%25=%25')['status'] == 200
+ assert client.get(url='/?%25=%')['status'] == 200
+
+ route_match({"arguments": {"%251": "%252"}})
+ assert client.get(url='/?%1=%2')['status'] == 200
+ assert client.get(url='/?%251=%252')['status'] == 200
+ assert client.get(url='/?%251=%2')['status'] == 200
+
+ route_match({"arguments": {"%25%21%251": "%25%24%252"}})
+ assert client.get(url='/?%!%1=%$%2')['status'] == 200
+ assert client.get(url='/?%25!%251=%25$%252')['status'] == 200
+ assert client.get(url='/?%25!%1=%$%2')['status'] == 200
+
+
+def test_routes_match_arguments_ampersand():
+ route_match({"arguments": {"foo": "&"}})
+ assert client.get(url='/?foo=%26')['status'] == 200
+ assert client.get(url='/?foo=%26&')['status'] == 200
+ assert client.get(url='/?foo=%26%26')['status'] == 404
+ assert client.get(url='/?foo=&')['status'] == 404
+
+ route_match({"arguments": {"&": ""}})
+ assert client.get(url='/?%26=')['status'] == 200
+ assert client.get(url='/?%26=&')['status'] == 200
+ assert client.get(url='/?%26=%26')['status'] == 404
+ assert client.get(url='/?&=')['status'] == 404
+
+
+def test_routes_match_arguments_complex():
+ route_match({"arguments": {"foo": ""}})
+
+ assert client.get(url='/?foo')['status'] == 200, 'complex'
+ assert client.get(url='/?blah=blah&foo=')['status'] == 200, 'complex 2'
+ assert client.get(url='/?&&&foo&&&')['status'] == 200, 'complex 3'
+ assert client.get(url='/?foo&foo=bar&foo')['status'] == 404, 'complex 4'
+ assert client.get(url='/?foo=&foo')['status'] == 200, 'complex 5'
+ assert client.get(url='/?&=&foo&==&')['status'] == 200, 'complex 6'
+ assert client.get(url='/?&=&bar&==&')['status'] == 404, 'complex 7'
+
+
+def test_routes_match_arguments_multiple():
+ route_match({"arguments": {"foo": "bar", "blah": "test"}})
+
+ assert client.get()['status'] == 404, 'multiple'
+ assert client.get(url='/?foo=bar&blah=test')['status'] == 200, 'multiple 2'
+ assert client.get(url='/?foo=bar&blah')['status'] == 404, 'multiple 3'
+ assert client.get(url='/?foo=bar&blah=tes')['status'] == 404, 'multiple 4'
+ assert (
+ client.get(url='/?foo=b%61r&bl%61h=t%65st')['status'] == 200
+ ), 'multiple 5'
+
+
+def test_routes_match_arguments_multiple_rules():
+ route_match({"arguments": {"foo": ["bar", "blah"]}})
+
+ assert client.get()['status'] == 404, 'rules'
+ assert client.get(url='/?foo=bar')['status'] == 200, 'rules 2'
+ assert client.get(url='/?foo=blah')['status'] == 200, 'rules 3'
+ assert (
+ client.get(url='/?foo=blah&foo=bar&foo=blah')['status'] == 200
+ ), 'rules 4'
+ assert client.get(url='/?foo=blah&foo=bar&foo=')['status'] == 404, 'rules 5'
+
+
+def test_routes_match_arguments_array():
+ route_match(
+ {
+ "arguments": [
+ {"var1": "val1*"},
+ {"var2": "val2"},
+ {"var3": ["foo", "bar"]},
+ {"var1": "bar", "var4": "foo"},
+ ]
+ }
+ )
+
+ assert client.get()['status'] == 404, 'arr'
+ assert client.get(url='/?var1=val123')['status'] == 200, 'arr 2'
+ assert client.get(url='/?var2=val2')['status'] == 200, 'arr 3'
+ assert client.get(url='/?var3=bar')['status'] == 200, 'arr 4'
+ assert client.get(url='/?var1=bar')['status'] == 404, 'arr 5'
+ assert client.get(url='/?var1=bar&var4=foo')['status'] == 200, 'arr 6'
+
+ assert 'success' in client.conf_delete(
+ 'routes/0/match/arguments/1'
+ ), 'match arguments array configure 2'
- def test_routes_source_ipv6(self):
- assert 'success' in self.conf(
- {
- "[::1]:7080": {"pass": "routes"},
- "127.0.0.1:7081": {"pass": "routes"},
- },
- 'listeners',
- ), 'source listeners configure'
+ assert client.get(url='/?var2=val2')['status'] == 404, 'arr 7'
+ assert client.get(url='/?var3=foo')['status'] == 200, 'arr 8'
- self.route_match({"source": "::1"})
- assert self.get(sock_type='ipv6')['status'] == 200, 'exact'
- assert self.get(port=7081)['status'] == 404, 'exact ipv4'
- self.route_match({"source": ["::1"]})
- assert self.get(sock_type='ipv6')['status'] == 200, 'exact 2'
- assert self.get(port=7081)['status'] == 404, 'exact 2 ipv4'
+def test_routes_match_arguments_invalid():
+ route_match_invalid({"arguments": ["var"]})
+ route_match_invalid({"arguments": [{"var1": {}}]})
+ route_match_invalid({"arguments": {"": "bar"}})
+ route_match_invalid({"arguments": {"foo": "%"}})
+ route_match_invalid({"arguments": {"foo": "%1G"}})
+ route_match_invalid({"arguments": {"%": "bar"}})
+ route_match_invalid({"arguments": {"foo": "%0"}})
+ route_match_invalid({"arguments": {"foo": "%%1F"}})
+ route_match_invalid({"arguments": {"%%1F": ""}})
+ route_match_invalid({"arguments": {"%7%F": ""}})
+
- self.route_match({"source": "!::1"})
- assert self.get(sock_type='ipv6')['status'] == 404, 'exact neg'
- assert self.get(port=7081)['status'] == 200, 'exact neg ipv4'
+def test_routes_match_query():
+ route_match({"query": "!"})
+ assert client.get(url='/')['status'] == 404
+ assert client.get(url='/?')['status'] == 404
+ assert client.get(url='/?foo')['status'] == 200
+ assert client.get(url='/?foo=')['status'] == 200
+ assert client.get(url='/?foo=baz')['status'] == 200
- self.route_match({"source": "::2"})
- assert self.get(sock_type='ipv6')['status'] == 404, 'exact 3'
- assert self.get(port=7081)['status'] == 404, 'exact 3 ipv4'
+ route_match({"query": "foo=%26"})
+ assert client.get(url='/?foo=&')['status'] == 200
- self.route_match({"source": "::1-::1"})
- assert self.get(sock_type='ipv6')['status'] == 200, 'range'
- assert self.get(port=7081)['status'] == 404, 'range ipv4'
+ route_match({"query": "a=b&c=d"})
+ assert client.get(url='/?a=b&c=d')['status'] == 200
- self.route_match({"source": "::2-::2"})
- assert self.get(sock_type='ipv6')['status'] == 404, 'range 2'
- assert self.get(port=7081)['status'] == 404, 'range 2 ipv4'
+ route_match({"query": "a=b%26c%3Dd"})
+ assert client.get(url='/?a=b%26c%3Dd')['status'] == 200
+ assert client.get(url='/?a=b&c=d')['status'] == 200
- self.route_match({"source": "::2-::3"})
- assert self.get(sock_type='ipv6')['status'] == 404, 'range 3'
- assert self.get(port=7081)['status'] == 404, 'range 3 ipv4'
+ route_match({"query": "a=b%26c%3Dd+e"})
+ assert client.get(url='/?a=b&c=d e')['status'] == 200
- self.route_match({"source": "::1-::2"})
- assert self.get(sock_type='ipv6')['status'] == 200, 'range 4'
- assert self.get(port=7081)['status'] == 404, 'range 4 ipv4'
- self.route_match({"source": "::0-::2"})
- assert self.get(sock_type='ipv6')['status'] == 200, 'range 5'
- assert self.get(port=7081)['status'] == 404, 'range 5 ipv4'
+def test_routes_match_query_array():
+ route_match({"query": ["foo", "bar"]})
- self.route_match({"source": "::0-::1"})
- assert self.get(sock_type='ipv6')['status'] == 200, 'range 6'
- assert self.get(port=7081)['status'] == 404, 'range 6 ipv4'
+ assert client.get()['status'] == 404, 'no args'
+ assert client.get(url='/?foo')['status'] == 200, 'arg first'
+ assert client.get(url='/?bar')['status'] == 200, 'arg second'
- def test_routes_source_cidr(self):
- assert 'success' in self.conf(
- {
- "*:7080": {"pass": "routes"},
- "[::1]:7081": {"pass": "routes"},
- },
- 'listeners',
- ), 'source listeners configure'
+ assert 'success' in client.conf_delete(
+ 'routes/0/match/query/1'
+ ), 'query array remove second'
- def get_ipv6():
- return self.get(sock_type='ipv6', port=7081)
+ assert client.get(url='/?foo')['status'] == 200, 'still arg first'
+ assert client.get(url='/?bar')['status'] == 404, 'no arg second'
- self.route_match({"source": "127.0.0.1/32"})
- assert self.get()['status'] == 200, '32'
- assert get_ipv6()['status'] == 404, '32 ipv6'
+ route_match({"query": ["!f", "foo"]})
- self.route_match({"source": "127.0.0.0/32"})
- assert self.get()['status'] == 404, '32 2'
- assert get_ipv6()['status'] == 404, '32 2 ipv6'
+ assert client.get(url='/?f')['status'] == 404, 'negative arg'
+ assert client.get(url='/?fo')['status'] == 404, 'negative arg 2'
+ assert client.get(url='/?foo')['status'] == 200, 'negative arg 3'
+
+ route_match({"query": []})
+ assert client.get()['status'] == 200, 'empty array'
+
+
+def test_routes_match_query_invalid():
+ route_match_invalid({"query": [1]})
+ route_match_invalid({"query": "%"})
+ route_match_invalid({"query": "%1G"})
+ route_match_invalid({"query": "%0"})
+ route_match_invalid({"query": "%%1F"})
+ route_match_invalid({"query": ["foo", "%3D", "%%1F"]})
+
+
+def test_routes_match_cookies():
+ route_match({"cookies": {"foO": "bar"}})
- self.route_match({"source": "127.0.0.0/31"})
- assert self.get()['status'] == 200, '31'
- assert get_ipv6()['status'] == 404, '31 ipv6'
+ assert client.get()['status'] == 404, 'cookie'
+ cookie('foO=bar', 200)
+ cookie('foO=bar;1', 200)
+ cookie(['foO=bar', 'blah=blah'], 200)
+ cookie('foO=bar; blah=blah', 200)
+ cookie('Foo=bar', 404)
+ cookie('foO=Bar', 404)
+ cookie('foO=bar1', 404)
+ cookie('1foO=bar;', 404)
- self.route_match({"source": "0.0.0.0/1"})
- assert self.get()['status'] == 200, '1'
- assert get_ipv6()['status'] == 404, '1 ipv6'
- self.route_match({"source": "0.0.0.0/0"})
- assert self.get()['status'] == 200, '0'
- assert get_ipv6()['status'] == 404, '0 ipv6'
+def test_routes_match_cookies_empty():
+ route_match({"cookies": {}})
+ assert client.get()['status'] == 200, 'cookies empty'
- def test_routes_source_cidr_ipv6(self):
- assert 'success' in self.conf(
- {
- "[::1]:7080": {"pass": "routes"},
- "127.0.0.1:7081": {"pass": "routes"},
- },
- 'listeners',
- ), 'source listeners configure'
+ route_match({"cookies": []})
+ assert client.get()['status'] == 200, 'cookies empty 2'
- self.route_match({"source": "::1/128"})
- assert self.get(sock_type='ipv6')['status'] == 200, '128'
- assert self.get(port=7081)['status'] == 404, '128 ipv4'
- self.route_match({"source": "::0/128"})
- assert self.get(sock_type='ipv6')['status'] == 404, '128 2'
- assert self.get(port=7081)['status'] == 404, '128 ipv4'
+def test_routes_match_cookies_invalid():
+ route_match_invalid({"cookies": ["var"]})
+ route_match_invalid({"cookies": [{"foo": {}}]})
- self.route_match({"source": "::0/127"})
- assert self.get(sock_type='ipv6')['status'] == 200, '127'
- assert self.get(port=7081)['status'] == 404, '127 ipv4'
- self.route_match({"source": "::0/32"})
- assert self.get(sock_type='ipv6')['status'] == 200, '32'
- assert self.get(port=7081)['status'] == 404, '32 ipv4'
+def test_routes_match_cookies_complex():
+ route_match({"cookies": {"foo": "bar=baz"}})
+ cookie('foo=bar=baz', 200)
+ cookie(' foo=bar=baz ', 200)
+ cookie('=foo=bar=baz', 404)
- self.route_match({"source": "::0/1"})
- assert self.get(sock_type='ipv6')['status'] == 200, '1'
- assert self.get(port=7081)['status'] == 404, '1 ipv4'
+ route_match({"cookies": {"foo": ""}})
+ cookie('foo=', 200)
+ cookie('foo=;', 200)
+ cookie(' foo=;', 200)
+ cookie('foo', 404)
+ cookie('', 404)
+ cookie('=', 404)
- self.route_match({"source": "::/0"})
- assert self.get(sock_type='ipv6')['status'] == 200, '0'
- assert self.get(port=7081)['status'] == 404, '0 ipv4'
- def test_routes_source_unix(self, temp_dir):
- addr = f'{temp_dir}/sock'
+def test_routes_match_cookies_multiple():
+ route_match({"cookies": {"foo": "bar", "blah": "blah"}})
- assert 'success' in self.conf(
- {
- "127.0.0.1:7081": {"pass": "routes"},
- f'unix:{addr}': {"pass": "routes"},
- },
- 'listeners',
- ), 'source listeners configure'
+ assert client.get()['status'] == 404, 'multiple'
+ cookie('foo=bar; blah=blah', 200)
+ cookie(['foo=bar', 'blah=blah'], 200)
+ cookie(['foo=bar; blah', 'blah'], 404)
+ cookie(['foo=bar; blah=test', 'blah=blah'], 404)
- self.route_match({"source": "!0.0.0.0/0"})
- assert (
- self.get(sock_type='unix', addr=addr)['status'] == 200
- ), 'unix ipv4 neg'
- self.route_match({"source": "!::/0"})
- assert (
- self.get(sock_type='unix', addr=addr)['status'] == 200
- ), 'unix ipv6 neg'
+def test_routes_match_cookies_multiple_values():
+ route_match({"cookies": {"blah": "blah"}})
- self.route_match({"source": "unix"})
- assert self.get(port=7081)['status'] == 404, 'unix ipv4'
- assert self.get(sock_type='unix', addr=addr)['status'] == 200, 'unix'
+ cookie(['blah=blah', 'blah=blah', 'blah=blah'], 200)
+ cookie(['blah=blah', 'blah=test', 'blah=blah'], 404)
+ cookie(['blah=blah; blah=', 'blah=blah'], 404)
- def test_routes_match_source(self):
- self.route_match({"source": "::"})
- self.route_match(
- {
- "source": [
- "127.0.0.1",
- "192.168.0.10:8080",
- "192.168.0.11:8080-8090",
- ]
- }
- )
- self.route_match(
- {
- "source": [
- "10.0.0.0/8",
- "10.0.0.0/7:1000",
- "10.0.0.0/32:8080-8090",
- ]
- }
- )
- self.route_match(
- {
- "source": [
- "10.0.0.0-10.0.0.1",
- "10.0.0.0-11.0.0.0:1000",
- "127.0.0.0-127.0.0.255:8080-8090",
- ]
- }
- )
- self.route_match(
- {"source": ["2001::", "[2002::]:8000", "[2003::]:8080-8090"]}
- )
- self.route_match(
- {
- "source": [
- "2001::-200f:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
- "[fe08::-feff::]:8000",
- "[fff0::-fff0::10]:8080-8090",
- ]
- }
- )
- self.route_match(
- {
- "source": [
- "2001::/16",
- "[0ff::/64]:8000",
- "[fff0:abcd:ffff:ffff:ffff::/128]:8080-8090",
- ]
- }
- )
- self.route_match({"source": "*:0-65535"})
- assert self.get()['status'] == 200, 'source any'
-
- def test_routes_match_source_invalid(self):
- self.route_match_invalid({"source": "127"})
- self.route_match_invalid({"source": "256.0.0.1"})
- self.route_match_invalid({"source": "127.0.0."})
- self.route_match_invalid({"source": " 127.0.0.1"})
- self.route_match_invalid({"source": "127.0.0.1:"})
- self.route_match_invalid({"source": "127.0.0.1/"})
- self.route_match_invalid({"source": "11.0.0.0/33"})
- self.route_match_invalid({"source": "11.0.0.0/65536"})
- self.route_match_invalid({"source": "11.0.0.0-10.0.0.0"})
- self.route_match_invalid({"source": "11.0.0.0:3000-2000"})
- self.route_match_invalid({"source": ["11.0.0.0:3000-2000"]})
- self.route_match_invalid({"source": "[2001::]:3000-2000"})
- self.route_match_invalid({"source": "2001::-2000::"})
- self.route_match_invalid({"source": "2001::/129"})
- self.route_match_invalid({"source": "::FFFFF"})
- self.route_match_invalid({"source": "[::1]:"})
- self.route_match_invalid({"source": "[:::]:7080"})
- self.route_match_invalid({"source": "*:"})
- self.route_match_invalid({"source": "*:1-a"})
- self.route_match_invalid({"source": "*:65536"})
-
- def test_routes_match_source_none(self):
- self.route_match({"source": []})
- assert self.get()['status'] == 404, 'source none'
-
- def test_routes_match_destination(self):
- assert 'success' in self.conf(
- {"*:7080": {"pass": "routes"}, "*:7081": {"pass": "routes"}},
- 'listeners',
- ), 'listeners configure'
-
- self.route_match({"destination": "*:7080"})
- assert self.get()['status'] == 200, 'dest'
- assert self.get(port=7081)['status'] == 404, 'dest 2'
-
- self.route_match({"destination": ["127.0.0.1:7080"]})
- assert self.get()['status'] == 200, 'dest 3'
- assert self.get(port=7081)['status'] == 404, 'dest 4'
-
- self.route_match({"destination": "!*:7080"})
- assert self.get()['status'] == 404, 'dest neg'
- assert self.get(port=7081)['status'] == 200, 'dest neg 2'
-
- self.route_match({"destination": ['!*:7080', '!*:7081']})
- assert self.get()['status'] == 404, 'dest neg 3'
- assert self.get(port=7081)['status'] == 404, 'dest neg 4'
-
- self.route_match({"destination": ['!*:7081', '!*:7082']})
- assert self.get()['status'] == 200, 'dest neg 5'
-
- self.route_match({"destination": ['*:7080', '!*:7080']})
- assert self.get()['status'] == 404, 'dest neg 6'
-
- self.route_match(
- {"destination": ['127.0.0.1:7080', '*:7081', '!*:7080']}
- )
- assert self.get()['status'] == 404, 'dest neg 7'
- assert self.get(port=7081)['status'] == 200, 'dest neg 8'
- self.route_match({"destination": ['!*:7081', '!*:7082', '*:7083']})
- assert self.get()['status'] == 404, 'dest neg 9'
+def test_routes_match_cookies_multiple_rules():
+ route_match({"cookies": {"blah": ["test", "blah"]}})
- self.route_match(
- {"destination": ['*:7081', '!127.0.0.1:7080', '*:7080']}
- )
- assert self.get()['status'] == 404, 'dest neg 10'
- assert self.get(port=7081)['status'] == 200, 'dest neg 11'
-
- assert 'success' in self.conf_delete(
- 'routes/0/match/destination/0'
- ), 'remove destination rule'
- assert self.get()['status'] == 404, 'dest neg 12'
- assert self.get(port=7081)['status'] == 404, 'dest neg 13'
-
- assert 'success' in self.conf_delete(
- 'routes/0/match/destination/0'
- ), 'remove destination rule 2'
- assert self.get()['status'] == 200, 'dest neg 14'
- assert self.get(port=7081)['status'] == 404, 'dest neg 15'
-
- assert 'success' in self.conf_post(
- "\"!127.0.0.1\"", 'routes/0/match/destination'
- ), 'add destination rule'
- assert self.get()['status'] == 404, 'dest neg 16'
- assert self.get(port=7081)['status'] == 404, 'dest neg 17'
-
- def test_routes_match_destination_proxy(self):
- assert 'success' in self.conf(
- {
- "listeners": {
- "*:7080": {"pass": "routes/first"},
- "*:7081": {"pass": "routes/second"},
- },
- "routes": {
- "first": [{"action": {"proxy": "http://127.0.0.1:7081"}}],
- "second": [
- {
- "match": {"destination": ["127.0.0.1:7081"]},
- "action": {"return": 200},
- }
- ],
- },
- "applications": {},
- }
- ), 'proxy configure'
+ assert client.get()['status'] == 404, 'multiple rules'
+ cookie('blah=test', 200)
+ cookie('blah=blah', 200)
+ cookie(['blah=blah', 'blah=test', 'blah=blah'], 200)
+ cookie(['blah=blah; blah=test', 'blah=blah'], 200)
+ cookie(['blah=blah', 'blah'], 200) # invalid cookie
+
+
+def test_routes_match_cookies_array():
+ route_match(
+ {
+ "cookies": [
+ {"var1": "val1*"},
+ {"var2": "val2"},
+ {"var3": ["foo", "bar"]},
+ {"var1": "bar", "var4": "foo"},
+ ]
+ }
+ )
+
+ assert client.get()['status'] == 404, 'cookies array'
+ cookie('var1=val123', 200)
+ cookie('var2=val2', 200)
+ cookie(' var2=val2 ', 200)
+ cookie('var3=bar', 200)
+ cookie('var3=bar;', 200)
+ cookie('var1=bar', 404)
+ cookie('var1=bar; var4=foo;', 200)
+ cookie(['var1=bar', 'var4=foo'], 200)
+
+ assert 'success' in client.conf_delete(
+ 'routes/0/match/cookies/1'
+ ), 'match cookies array configure 2'
+
+ cookie('var2=val2', 404)
+ cookie('var3=foo', 200)
+
+
+def test_routes_match_scheme():
+ route_match({"scheme": "http"})
+ route_match({"scheme": "https"})
+ route_match({"scheme": "HtTp"})
+ route_match({"scheme": "HtTpS"})
+
+
+def test_routes_match_scheme_invalid():
+ route_match_invalid({"scheme": ["http"]})
+ route_match_invalid({"scheme": "ftp"})
+ route_match_invalid({"scheme": "ws"})
+ route_match_invalid({"scheme": "*"})
+ route_match_invalid({"scheme": ""})
+
+
+def test_routes_source_port():
+ def sock_port():
+ sock = client.http(b'', raw=True, no_recv=True)
+ port = sock.getsockname()[1]
+ return (sock, port)
+
+ sock, port = sock_port()
+ sock2, _ = sock_port()
+
+ route_match({"source": f'127.0.0.1:{port}'})
+ assert client.get(sock=sock)['status'] == 200, 'exact'
+ assert client.get(sock=sock2)['status'] == 404, 'exact 2'
+
+ sock, port = sock_port()
+ sock2, _ = sock_port()
+
+ route_match({"source": f'!127.0.0.1:{port}'})
+ assert client.get(sock=sock)['status'] == 404, 'negative'
+ assert client.get(sock=sock2)['status'] == 200, 'negative 2'
+
+ sock, port = sock_port()
+ sock2, _ = sock_port()
+
+ route_match({"source": [f'*:{port}', "!127.0.0.1"]})
+ assert client.get(sock=sock)['status'] == 404, 'negative 3'
+ assert client.get(sock=sock2)['status'] == 404, 'negative 4'
+
+ sock, port = sock_port()
+ sock2, _ = sock_port()
+
+ route_match({"source": f'127.0.0.1:{port}-{port}'})
+ assert client.get(sock=sock)['status'] == 200, 'range single'
+ assert client.get(sock=sock2)['status'] == 404, 'range single 2'
+
+ socks = [
+ sock_port(),
+ sock_port(),
+ sock_port(),
+ sock_port(),
+ sock_port(),
+ ]
+ socks.sort(key=lambda sock: sock[1])
+
+ route_match({"source": f'127.0.0.1:{socks[1][1]}-{socks[3][1]}'})
+ assert client.get(sock=socks[0][0])['status'] == 404, 'range'
+ assert client.get(sock=socks[1][0])['status'] == 200, 'range 2'
+ assert client.get(sock=socks[2][0])['status'] == 200, 'range 3'
+ assert client.get(sock=socks[3][0])['status'] == 200, 'range 4'
+ assert client.get(sock=socks[4][0])['status'] == 404, 'range 5'
+
+ socks = [
+ sock_port(),
+ sock_port(),
+ sock_port(),
+ ]
+ socks.sort(key=lambda sock: sock[1])
+
+ route_match(
+ {
+ "source": [
+ f'127.0.0.1:{socks[0][1]}',
+ f'127.0.0.1:{socks[2][1]}',
+ ]
+ }
+ )
+ assert client.get(sock=socks[0][0])['status'] == 200, 'array'
+ assert client.get(sock=socks[1][0])['status'] == 404, 'array 2'
+ assert client.get(sock=socks[2][0])['status'] == 200, 'array 3'
+
+
+def test_routes_source_addr():
+ assert 'success' in client.conf(
+ {
+ "*:7080": {"pass": "routes"},
+ "[::1]:7081": {"pass": "routes"},
+ },
+ 'listeners',
+ ), 'source listeners configure'
+
+ def get_ipv6():
+ return client.get(sock_type='ipv6', port=7081)
+
+ route_match({"source": "127.0.0.1"})
+ assert client.get()['status'] == 200, 'exact'
+ assert get_ipv6()['status'] == 404, 'exact ipv6'
+
+ route_match({"source": ["127.0.0.1"]})
+ assert client.get()['status'] == 200, 'exact 2'
+ assert get_ipv6()['status'] == 404, 'exact 2 ipv6'
+
+ route_match({"source": "!127.0.0.1"})
+ assert client.get()['status'] == 404, 'exact neg'
+ assert get_ipv6()['status'] == 200, 'exact neg ipv6'
+
+ route_match({"source": "127.0.0.2"})
+ assert client.get()['status'] == 404, 'exact 3'
+ assert get_ipv6()['status'] == 404, 'exact 3 ipv6'
+
+ route_match({"source": "127.0.0.1-127.0.0.1"})
+ assert client.get()['status'] == 200, 'range single'
+ assert get_ipv6()['status'] == 404, 'range single ipv6'
+
+ route_match({"source": "127.0.0.2-127.0.0.2"})
+ assert client.get()['status'] == 404, 'range single 2'
+ assert get_ipv6()['status'] == 404, 'range single 2 ipv6'
+
+ route_match({"source": "127.0.0.2-127.0.0.3"})
+ assert client.get()['status'] == 404, 'range'
+ assert get_ipv6()['status'] == 404, 'range ipv6'
+
+ route_match({"source": "127.0.0.1-127.0.0.2"})
+ assert client.get()['status'] == 200, 'range 2'
+ assert get_ipv6()['status'] == 404, 'range 2 ipv6'
+
+ route_match({"source": "127.0.0.0-127.0.0.2"})
+ assert client.get()['status'] == 200, 'range 3'
+ assert get_ipv6()['status'] == 404, 'range 3 ipv6'
+
+ route_match({"source": "127.0.0.0-127.0.0.1"})
+ assert client.get()['status'] == 200, 'range 4'
+ assert get_ipv6()['status'] == 404, 'range 4 ipv6'
+
+ route_match({"source": "126.0.0.0-127.0.0.0"})
+ assert client.get()['status'] == 404, 'range 5'
+ assert get_ipv6()['status'] == 404, 'range 5 ipv6'
+
+ route_match({"source": "126.126.126.126-127.0.0.2"})
+ assert client.get()['status'] == 200, 'range 6'
+ assert get_ipv6()['status'] == 404, 'range 6 ipv6'
+
+
+def test_routes_source_ipv6():
+ assert 'success' in client.conf(
+ {
+ "[::1]:7080": {"pass": "routes"},
+ "127.0.0.1:7081": {"pass": "routes"},
+ },
+ 'listeners',
+ ), 'source listeners configure'
+
+ route_match({"source": "::1"})
+ assert client.get(sock_type='ipv6')['status'] == 200, 'exact'
+ assert client.get(port=7081)['status'] == 404, 'exact ipv4'
+
+ route_match({"source": ["::1"]})
+ assert client.get(sock_type='ipv6')['status'] == 200, 'exact 2'
+ assert client.get(port=7081)['status'] == 404, 'exact 2 ipv4'
+
+ route_match({"source": "!::1"})
+ assert client.get(sock_type='ipv6')['status'] == 404, 'exact neg'
+ assert client.get(port=7081)['status'] == 200, 'exact neg ipv4'
+
+ route_match({"source": "::2"})
+ assert client.get(sock_type='ipv6')['status'] == 404, 'exact 3'
+ assert client.get(port=7081)['status'] == 404, 'exact 3 ipv4'
+
+ route_match({"source": "::1-::1"})
+ assert client.get(sock_type='ipv6')['status'] == 200, 'range'
+ assert client.get(port=7081)['status'] == 404, 'range ipv4'
+
+ route_match({"source": "::2-::2"})
+ assert client.get(sock_type='ipv6')['status'] == 404, 'range 2'
+ assert client.get(port=7081)['status'] == 404, 'range 2 ipv4'
+
+ route_match({"source": "::2-::3"})
+ assert client.get(sock_type='ipv6')['status'] == 404, 'range 3'
+ assert client.get(port=7081)['status'] == 404, 'range 3 ipv4'
+
+ route_match({"source": "::1-::2"})
+ assert client.get(sock_type='ipv6')['status'] == 200, 'range 4'
+ assert client.get(port=7081)['status'] == 404, 'range 4 ipv4'
+
+ route_match({"source": "::0-::2"})
+ assert client.get(sock_type='ipv6')['status'] == 200, 'range 5'
+ assert client.get(port=7081)['status'] == 404, 'range 5 ipv4'
+
+ route_match({"source": "::0-::1"})
+ assert client.get(sock_type='ipv6')['status'] == 200, 'range 6'
+ assert client.get(port=7081)['status'] == 404, 'range 6 ipv4'
+
+
+def test_routes_source_cidr():
+ assert 'success' in client.conf(
+ {
+ "*:7080": {"pass": "routes"},
+ "[::1]:7081": {"pass": "routes"},
+ },
+ 'listeners',
+ ), 'source listeners configure'
+
+ def get_ipv6():
+ return client.get(sock_type='ipv6', port=7081)
+
+ route_match({"source": "127.0.0.1/32"})
+ assert client.get()['status'] == 200, '32'
+ assert get_ipv6()['status'] == 404, '32 ipv6'
+
+ route_match({"source": "127.0.0.0/32"})
+ assert client.get()['status'] == 404, '32 2'
+ assert get_ipv6()['status'] == 404, '32 2 ipv6'
+
+ route_match({"source": "127.0.0.0/31"})
+ assert client.get()['status'] == 200, '31'
+ assert get_ipv6()['status'] == 404, '31 ipv6'
+
+ route_match({"source": "0.0.0.0/1"})
+ assert client.get()['status'] == 200, '1'
+ assert get_ipv6()['status'] == 404, '1 ipv6'
+
+ route_match({"source": "0.0.0.0/0"})
+ assert client.get()['status'] == 200, '0'
+ assert get_ipv6()['status'] == 404, '0 ipv6'
+
+
+def test_routes_source_cidr_ipv6():
+ assert 'success' in client.conf(
+ {
+ "[::1]:7080": {"pass": "routes"},
+ "127.0.0.1:7081": {"pass": "routes"},
+ },
+ 'listeners',
+ ), 'source listeners configure'
+
+ route_match({"source": "::1/128"})
+ assert client.get(sock_type='ipv6')['status'] == 200, '128'
+ assert client.get(port=7081)['status'] == 404, '128 ipv4'
+
+ route_match({"source": "::0/128"})
+ assert client.get(sock_type='ipv6')['status'] == 404, '128 2'
+ assert client.get(port=7081)['status'] == 404, '128 ipv4'
+
+ route_match({"source": "::0/127"})
+ assert client.get(sock_type='ipv6')['status'] == 200, '127'
+ assert client.get(port=7081)['status'] == 404, '127 ipv4'
+
+ route_match({"source": "::0/32"})
+ assert client.get(sock_type='ipv6')['status'] == 200, '32'
+ assert client.get(port=7081)['status'] == 404, '32 ipv4'
+
+ route_match({"source": "::0/1"})
+ assert client.get(sock_type='ipv6')['status'] == 200, '1'
+ assert client.get(port=7081)['status'] == 404, '1 ipv4'
+
+ route_match({"source": "::/0"})
+ assert client.get(sock_type='ipv6')['status'] == 200, '0'
+ assert client.get(port=7081)['status'] == 404, '0 ipv4'
+
+
+def test_routes_source_unix(temp_dir):
+ addr = f'{temp_dir}/sock'
+
+ assert 'success' in client.conf(
+ {
+ "127.0.0.1:7081": {"pass": "routes"},
+ f'unix:{addr}': {"pass": "routes"},
+ },
+ 'listeners',
+ ), 'source listeners configure'
+
+ route_match({"source": "!0.0.0.0/0"})
+ assert (
+ client.get(sock_type='unix', addr=addr)['status'] == 200
+ ), 'unix ipv4 neg'
+
+ route_match({"source": "!::/0"})
+ assert (
+ client.get(sock_type='unix', addr=addr)['status'] == 200
+ ), 'unix ipv6 neg'
+
+ route_match({"source": "unix"})
+ assert client.get(port=7081)['status'] == 404, 'unix ipv4'
+ assert client.get(sock_type='unix', addr=addr)['status'] == 200, 'unix'
+
+
+def test_routes_match_source():
+ route_match({"source": "::"})
+ route_match(
+ {
+ "source": [
+ "127.0.0.1",
+ "192.168.0.10:8080",
+ "192.168.0.11:8080-8090",
+ ]
+ }
+ )
+ route_match(
+ {
+ "source": [
+ "10.0.0.0/8",
+ "10.0.0.0/7:1000",
+ "10.0.0.0/32:8080-8090",
+ ]
+ }
+ )
+ route_match(
+ {
+ "source": [
+ "10.0.0.0-10.0.0.1",
+ "10.0.0.0-11.0.0.0:1000",
+ "127.0.0.0-127.0.0.255:8080-8090",
+ ]
+ }
+ )
+ route_match({"source": ["2001::", "[2002::]:8000", "[2003::]:8080-8090"]})
+ route_match(
+ {
+ "source": [
+ "2001::-200f:ffff:ffff:ffff:ffff:ffff:ffff:ffff",
+ "[fe08::-feff::]:8000",
+ "[fff0::-fff0::10]:8080-8090",
+ ]
+ }
+ )
+ route_match(
+ {
+ "source": [
+ "2001::/16",
+ "[0ff::/64]:8000",
+ "[fff0:abcd:ffff:ffff:ffff::/128]:8080-8090",
+ ]
+ }
+ )
+ route_match({"source": "*:0-65535"})
+ assert client.get()['status'] == 200, 'source any'
+
+
+def test_routes_match_source_invalid():
+ route_match_invalid({"source": "127"})
+ route_match_invalid({"source": "256.0.0.1"})
+ route_match_invalid({"source": "127.0.0."})
+ route_match_invalid({"source": " 127.0.0.1"})
+ route_match_invalid({"source": "127.0.0.1:"})
+ route_match_invalid({"source": "127.0.0.1/"})
+ route_match_invalid({"source": "11.0.0.0/33"})
+ route_match_invalid({"source": "11.0.0.0/65536"})
+ route_match_invalid({"source": "11.0.0.0-10.0.0.0"})
+ route_match_invalid({"source": "11.0.0.0:3000-2000"})
+ route_match_invalid({"source": ["11.0.0.0:3000-2000"]})
+ route_match_invalid({"source": "[2001::]:3000-2000"})
+ route_match_invalid({"source": "2001::-2000::"})
+ route_match_invalid({"source": "2001::/129"})
+ route_match_invalid({"source": "::FFFFF"})
+ route_match_invalid({"source": "[::1]:"})
+ route_match_invalid({"source": "[:::]:7080"})
+ route_match_invalid({"source": "*:"})
+ route_match_invalid({"source": "*:1-a"})
+ route_match_invalid({"source": "*:65536"})
+
+
+def test_routes_match_source_none():
+ route_match({"source": []})
+ assert client.get()['status'] == 404, 'source none'
+
+
+def test_routes_match_destination():
+ assert 'success' in client.conf(
+ {"*:7080": {"pass": "routes"}, "*:7081": {"pass": "routes"}},
+ 'listeners',
+ ), 'listeners configure'
+
+ route_match({"destination": "*:7080"})
+ assert client.get()['status'] == 200, 'dest'
+ assert client.get(port=7081)['status'] == 404, 'dest 2'
+
+ route_match({"destination": ["127.0.0.1:7080"]})
+ assert client.get()['status'] == 200, 'dest 3'
+ assert client.get(port=7081)['status'] == 404, 'dest 4'
+
+ route_match({"destination": "!*:7080"})
+ assert client.get()['status'] == 404, 'dest neg'
+ assert client.get(port=7081)['status'] == 200, 'dest neg 2'
+
+ route_match({"destination": ['!*:7080', '!*:7081']})
+ assert client.get()['status'] == 404, 'dest neg 3'
+ assert client.get(port=7081)['status'] == 404, 'dest neg 4'
+
+ route_match({"destination": ['!*:7081', '!*:7082']})
+ assert client.get()['status'] == 200, 'dest neg 5'
+
+ route_match({"destination": ['*:7080', '!*:7080']})
+ assert client.get()['status'] == 404, 'dest neg 6'
+
+ route_match({"destination": ['127.0.0.1:7080', '*:7081', '!*:7080']})
+ assert client.get()['status'] == 404, 'dest neg 7'
+ assert client.get(port=7081)['status'] == 200, 'dest neg 8'
+
+ route_match({"destination": ['!*:7081', '!*:7082', '*:7083']})
+ assert client.get()['status'] == 404, 'dest neg 9'
+
+ route_match({"destination": ['*:7081', '!127.0.0.1:7080', '*:7080']})
+ assert client.get()['status'] == 404, 'dest neg 10'
+ assert client.get(port=7081)['status'] == 200, 'dest neg 11'
+
+ assert 'success' in client.conf_delete(
+ 'routes/0/match/destination/0'
+ ), 'remove destination rule'
+ assert client.get()['status'] == 404, 'dest neg 12'
+ assert client.get(port=7081)['status'] == 404, 'dest neg 13'
+
+ assert 'success' in client.conf_delete(
+ 'routes/0/match/destination/0'
+ ), 'remove destination rule 2'
+ assert client.get()['status'] == 200, 'dest neg 14'
+ assert client.get(port=7081)['status'] == 404, 'dest neg 15'
+
+ assert 'success' in client.conf_post(
+ "\"!127.0.0.1\"", 'routes/0/match/destination'
+ ), 'add destination rule'
+ assert client.get()['status'] == 404, 'dest neg 16'
+ assert client.get(port=7081)['status'] == 404, 'dest neg 17'
+
+
+def test_routes_match_destination_proxy():
+ assert 'success' in client.conf(
+ {
+ "listeners": {
+ "*:7080": {"pass": "routes/first"},
+ "*:7081": {"pass": "routes/second"},
+ },
+ "routes": {
+ "first": [{"action": {"proxy": "http://127.0.0.1:7081"}}],
+ "second": [
+ {
+ "match": {"destination": ["127.0.0.1:7081"]},
+ "action": {"return": 200},
+ }
+ ],
+ },
+ "applications": {},
+ }
+ ), 'proxy configure'
- assert self.get()['status'] == 200, 'proxy'
+ assert client.get()['status'] == 200, 'proxy'