diff --git a/nginx.py b/nginx.py index 19b4798..b183f8f 100755 --- a/nginx.py +++ b/nginx.py @@ -382,7 +382,7 @@ def as_strings(self): """Return key as nginx config string.""" if self.value == '' or self.value is None: return '{0};\n'.format(self.name) - if ';' in self.value or '#' in self.value: + if '"' not in self.value and (';' in self.value or '#' in self.value): return '{0} "{1}";\n'.format(self.name, self.value) return '{0} {1};\n'.format(self.name, self.value) @@ -477,19 +477,13 @@ def loads(data, conf=True): index += m.end() continue - key_with_quoted = r'^\s*(\S*?)\s*"([^"]+)";?|\'([^\']+)\';?|\\S+;?' - key_wo_quoted = r'^\s*([a-zA-Z0-9-_]+?)\s+(.+?);' - m1 = re.compile(key_with_quoted, re.S).search(data[index:]) - m2 = re.compile(key_wo_quoted, re.S).search(data[index:]) - if m1 and m2: - if m1.start() <= m2.start(): - m = m1 - else: - m = m2 - else: - m = m1 or m2 + s1 = r'("[^"]+"|\'[^\']+\'|[^\s;]+)' + s2 = r'("[^"]*"|\'[^\']*\'|[^\s;]*)' + s3 = r'(\s*[^;]*?)' + key = r'^\s*{}\s*{}{};'.format(s1, s2, s3) + m = re.compile(key, re.S).search(data[index:]) if m: - k = Key(m.group(1), m.group(2)) + k = Key(m.group(1), m.group(2) + m.group(3)) if lopen and isinstance(lopen[0], (Container, Server)): lopen[0].add(k) else: diff --git a/tests.py b/tests.py index 6b14d85..126c32b 100755 --- a/tests.py +++ b/tests.py @@ -45,6 +45,7 @@ server_name localhost 127.0.0.1; root /srv/http; # And also this one mykey "myvalue; #notme myothervalue"; + "quoted_key" "quoted_value"; # This one too index index.php; if (!-e $request_filename) @@ -101,6 +102,61 @@ """ +TESTBLOCK_CASE_5 = """ +upstream test0 { + server 1.1.1.1:8080; + send "some request"; +} + +upstream test1 { + server 1.1.1.1:8080; + send 'some request'; +} + +server { + server_name "www.example.com"; + + location / { + root html; + } +} +""" + + +TESTBLOCK_CASE_6 = """ +upstream test0 { + server 1.1.1.1:8080; + check interval=3000 rise=2 fall=3 timeout=3000 type=http; + check_http_send "GET /alive.html HTTP/1.0\r\n\r\n"; + check_http_expect_alive http_2xx http_3xx; +} + +upstream test1 { + ip_hash; + server 2.2.2.2:9000; + check_http_send 'GET /alive.html HTTP/1.0\r\n\r\n'; +} +""" + +TESTBLOCK_CASE_7 = """ +upstream xx.com_backend { + server 10.193.2.2:9061 weight=1 max_fails=2 fail_timeout=30s; + server 10.193.2.1:9061 weight=1 max_fails=2 fail_timeout=30s; + session_sticky; +} + +server { + listen 80; + + location / { + set $xlocation 'test'; + proxy_pass http://xx.com_backend; + } +} +""" + + + class TestPythonNginx(unittest.TestCase): def test_basic_load(self): self.assertTrue(nginx.loads(TESTBLOCK_CASE_1) is not None) @@ -124,21 +180,24 @@ def test_key_parse(self): self.assertEqual(firstKey.name, 'listen') self.assertEqual(firstKey.value, '80') self.assertEqual(thirdKey.name, 'mykey') - self.assertEqual(thirdKey.value, 'myvalue; #notme myothervalue') + self.assertEqual(thirdKey.value, '"myvalue; #notme myothervalue"') def test_key_parse_complex(self): data = nginx.loads(TESTBLOCK_CASE_2) - self.assertEqual(len(data.server.keys), 5) + self.assertEqual(len(data.server.keys), 6) firstKey = data.server.keys[0] thirdKey = data.server.keys[3] + fourthKey = data.server.keys[4] self.assertEqual(firstKey.name, 'listen') self.assertEqual(firstKey.value, '80') self.assertEqual(thirdKey.name, 'mykey') - self.assertEqual(thirdKey.value, 'myvalue; #notme myothervalue') + self.assertEqual(thirdKey.value, '"myvalue; #notme myothervalue"') self.assertEqual( data.server.locations[-1].keys[0].value, "301 $scheme://$host:$server_port${request_uri}bitbucket/" ) + self.assertEqual(fourthKey.name, '"quoted_key"') + self.assertEqual(fourthKey.value, '"quoted_value"') def test_location_parse(self): data = nginx.loads(TESTBLOCK_CASE_1) @@ -162,6 +221,21 @@ def test_reflection(self): out_data = '\n' + nginx.dumps(inp_data) self.assertEqual(TESTBLOCK_CASE_1, out_data) + def test_quoted_key_value(self): + data = nginx.loads(TESTBLOCK_CASE_5) + out_data = '\n' + nginx.dumps(data) + self.assertEqual(out_data, TESTBLOCK_CASE_5) + + def test_complex_upstream(self): + inp_data = nginx.loads(TESTBLOCK_CASE_6) + out_data = '\n' + nginx.dumps(inp_data) + self.assertEqual(TESTBLOCK_CASE_6, out_data) + + def test_session_sticky(self): + inp_data = nginx.loads(TESTBLOCK_CASE_7) + out_data = '\n' + nginx.dumps(inp_data) + self.assertEqual(TESTBLOCK_CASE_7, out_data) + def test_filtering(self): data = nginx.loads(TESTBLOCK_CASE_1) self.assertEqual(len(data.server.filter('Key', 'mykey')), 1)