Skip to content

Commit 6675e6b

Browse files
authored
Merge pull request #36 from fulder/master
Quickfix for regexp catastrophic backtracking
2 parents 4ecd1cd + 74a71ee commit 6675e6b

File tree

2 files changed

+38
-2
lines changed

2 files changed

+38
-2
lines changed

nginx.py

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,14 @@
1111
INDENT = ' '
1212

1313

14+
class Error(Exception):
15+
pass
16+
17+
18+
class ParseError(Error):
19+
pass
20+
21+
1422
def bump_child_depth(obj, depth):
1523
children = getattr(obj, 'children', [])
1624
for child in children:
@@ -67,7 +75,7 @@ def filter(self, btype='', name=''):
6775
for x in self.children:
6876
if name and isinstance(x, Key) and x.name == name:
6977
filtered.append(x)
70-
elif isinstance(x, Container) and x.__class__.__name__ == btype\
78+
elif isinstance(x, Container) and x.__class__.__name__ == btype \
7179
and x.value == name:
7280
filtered.append(x)
7381
elif not name and btype and x.__class__.__name__ == btype:
@@ -164,7 +172,7 @@ def filter(self, btype='', name=''):
164172
for x in self.children:
165173
if name and isinstance(x, Key) and x.name == name:
166174
filtered.append(x)
167-
elif isinstance(x, Container) and x.__class__.__name__ == btype\
175+
elif isinstance(x, Container) and x.__class__.__name__ == btype \
168176
and x.value == name:
169177
filtered.append(x)
170178
elif not name and btype and x.__class__.__name__ == btype:
@@ -507,6 +515,11 @@ def loads(data, conf=True):
507515
index += m.end()
508516
continue
509517

518+
if ";" not in data[index:] and index+1 != len(data):
519+
# If there is still something to parse, expect ';' otherwise
520+
# the Key regexp can get stuck due to regexp catastrophic backtracking
521+
raise ParseError("Config syntax, missing ';' at index: {}".format(index))
522+
510523
double = r'\s*"[^"]*"'
511524
single = r'\s*\'[^\']*\''
512525
normal = r'\s*[^;\s]*'

tests.py

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
"""
88

99
# flake8: noqa
10+
import pytest
1011

1112
import nginx
1213
import unittest
@@ -177,6 +178,22 @@
177178
}
178179
"""
179180

181+
TESTBLOCK_CASE_11 = """
182+
server{
183+
listen 80;
184+
#OPEN-PORT-443
185+
listen 443 ssl;
186+
server_name www.xxx.com;
187+
root /wwww/wwww;
188+
189+
location ~ .*\.(js|css)?$ {
190+
expires 12h;
191+
error_log off;
192+
access_log /dev/null # MISSING SEMICOLON
193+
}
194+
}
195+
"""
196+
180197

181198
class TestPythonNginx(unittest.TestCase):
182199
def test_basic_load(self):
@@ -290,5 +307,11 @@ def test_types_block(self):
290307
data_type = inp_data.filter("Types")[0].filter("Key")[0]
291308
self.assertEqual(data_type.value, "cea")
292309

310+
def test_missing_semi_colon(self):
311+
with pytest.raises(nginx.ParseError) as e:
312+
nginx.loads(TESTBLOCK_CASE_11)
313+
self.assertEqual(str(e.value), "Config syntax, missing ';' at index: 189")
314+
315+
293316
if __name__ == '__main__':
294317
unittest.main()

0 commit comments

Comments
 (0)