Skip to content

Commit 4f57e06

Browse files
committed
Merge remote-tracking branch 'upstream/master'
2 parents 5dabc30 + cb02c5f commit 4f57e06

File tree

5 files changed

+53
-17
lines changed

5 files changed

+53
-17
lines changed

CHANGELOG

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,15 @@
22
All notable changes to this project will be documented in this file.
33
This project adheres to [Semantic Versioning](http://semver.org/).
44

5+
## [1.5.5] - 2021-03-11
6+
### Fixed
7+
- Fixed bugs in parsing lines that contain a semicolon or curly brace inside of quotes
8+
- Fixed bug in creating new Keys in which the value isn't a string but is still stringable (int)
9+
10+
## [1.5.4] - 2020-08-21
11+
### Fixed
12+
- Warn user if successful parsing of a config is impossible due to missing semicolon (thanks @fulder!)
13+
514
## [1.5.3] - 2018-12-10
615
### Fixed
716
- Fixed bug in parsing Type directives as well as misidentifying certain possible key names (thanks @SGamoff and @fulder!)

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ Create an nginx serverblock and save it to file:
2929
... nginx.Key('allow', 'all'),
3030
... nginx.Key('log_not_found', 'off'),
3131
... nginx.Key('access_log', 'off')
32-
... )
32+
... ),
3333
... nginx.Location('~ \.php$',
3434
... nginx.Key('include', 'fastcgi.conf'),
3535
... nginx.Key('fastcgi_intercept_errors', 'on'),

nginx.py

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -399,7 +399,7 @@ def as_strings(self):
399399
"""Return key as nginx config string."""
400400
if self.value == '' or self.value is None:
401401
return '{0};\n'.format(self.name)
402-
if '"' not in self.value and (';' in self.value or '#' in self.value):
402+
if type(self.value) == str and '"' not in self.value and (';' in self.value or '#' in self.value):
403403
return '{0} "{1}";\n'.format(self.name, self.value)
404404
return '{0} {1};\n'.format(self.name, self.value)
405405

@@ -444,43 +444,44 @@ def loads(data, conf=True):
444444
index += m.end()
445445
continue
446446

447-
m = re.compile(r'^\s*location\s*([^;]*?)\s*{', re.S).search(data[index:])
448-
if m:
447+
n = re.compile(r'(?!\B"[^"]*);(?![^"]*"\B)')
448+
m = re.compile(r'^\s*location\s+(.*?)\s*(?!\B"[^"]*){(?![^"]*"\B)', re.S).search(data[index:])
449+
if m and not n.search(m.group()):
449450
l = Location(m.group(1))
450451
lopen.insert(0, l)
451452
index += m.end()
452453
continue
453454

454-
m = re.compile(r'^\s*if\s*([^;]*?)\s*{', re.S).search(data[index:])
455-
if m:
455+
m = re.compile(r'^\s*if\s+(.*?)\s*(?!\B"[^"]*){(?![^"]*"\B)', re.S).search(data[index:])
456+
if m and not n.search(m.group()):
456457
ifs = If(m.group(1))
457458
lopen.insert(0, ifs)
458459
index += m.end()
459460
continue
460461

461-
m = re.compile(r'^\s*upstream\s*([^;]*?)\s*{', re.S).search(data[index:])
462-
if m:
462+
m = re.compile(r'^\s*upstream\s+(.*?)\s*(?!\B"[^"]*){(?![^"]*"\B)', re.S).search(data[index:])
463+
if m and not n.search(m.group()):
463464
u = Upstream(m.group(1))
464465
lopen.insert(0, u)
465466
index += m.end()
466467
continue
467468

468-
m = re.compile(r'^\s*geo\s*([^;]*?)\s*{', re.S).search(data[index:])
469-
if m:
469+
m = re.compile(r'^\s*geo\s+(.*?)\s*(?!\B"[^"]*){(?![^"]*"\B)', re.S).search(data[index:])
470+
if m and not n.search(m.group()):
470471
g = Geo(m.group(1))
471472
lopen.insert(0, g)
472473
index += m.end()
473474
continue
474475

475-
m = re.compile(r'^\s*map\s*([^;]*?)\s*{', re.S).search(data[index:])
476-
if m:
476+
m = re.compile(r'^\s*map\s+(.*?)\s*(?!\B"[^"]*){(?![^"]*"\B)', re.S).search(data[index:])
477+
if m and not n.search(m.group()):
477478
g = Map(m.group(1))
478479
lopen.insert(0, g)
479480
index += m.end()
480481
continue
481482

482-
m = re.compile(r'^\s*limit_except\s*([^;]*?)\s*{', re.S).search(data[index:])
483-
if m:
483+
m = re.compile(r'^\s*limit_except\s+(.*?)\s*(?!\B"[^"]*){(?![^"]*"\B)', re.S).search(data[index:])
484+
if m and not n.search(m.group()):
484485
l = LimitExcept(m.group(1))
485486
lopen.insert(0, l)
486487
index += m.end()

setup.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@
44

55
setup(
66
name='python-nginx',
7-
version='1.5.3',
7+
version='1.5.5',
88
description='Create and modify nginx serverblock configs in Python',
99
author='Jacob Cook',
1010
author_email='jacob@peakwinter.net',
1111
url='https://github.com/peakwinter/python-nginx',
1212
py_modules=['nginx'],
1313
keywords=['nginx', 'web servers', 'serverblock', 'server block'],
14-
download_url='https://github.com/peakwinter/python-nginx/archive/1.5.3.zip',
14+
download_url='https://github.com/peakwinter/python-nginx/archive/1.5.4.zip',
1515
license='GPLv3',
1616
classifiers=[
1717
"Development Status :: 5 - Production/Stable",

tests.py

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,10 @@
167167
location test9 {
168168
add_header X-XSS-Protection "1;mode-block";
169169
}
170+
171+
if ( $http_user_agent = "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)" ) {
172+
return 403;
173+
}
170174
"""
171175

172176
TESTBLOCK_CASE_10 = """
@@ -195,6 +199,21 @@
195199
"""
196200

197201
TESTBLOCK_CASE_12 = """
202+
server {
203+
listen 80;
204+
server_name test.example.com;
205+
206+
location ~ "^/(test|[0-9a-zA-Z]{6})$" {
207+
if ($query_string ~ pid=(111)) {
208+
return 403;
209+
}
210+
211+
proxy_pass http://127.0.0.1:81;
212+
}
213+
}
214+
"""
215+
216+
TESTBLOCK_CASE_13 = """
198217
server{
199218
}"""
200219

@@ -302,6 +321,8 @@ def test_semicolon_in_second_key_value(self):
302321
self.assertEqual(len(location_children), 1)
303322
self.assertEqual(location_children[0].name, "add_header")
304323
self.assertEqual(location_children[0].value, 'X-XSS-Protection "1;mode-block"')
324+
self.assertEqual(len(inp_data.filter("If")), 1)
325+
self.assertEqual(inp_data.filter("If")[0].value, "( $http_user_agent = \"Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.1; SV1)\" )")
305326

306327
def test_types_block(self):
307328
inp_data = nginx.loads(TESTBLOCK_CASE_10)
@@ -316,8 +337,13 @@ def test_missing_semi_colon(self):
316337
nginx.loads(TESTBLOCK_CASE_11)
317338
self.assertEqual(str(e.value), "Config syntax, missing ';' at index: 189")
318339

340+
def test_brace_inside_block_param(self):
341+
inp_data = nginx.loads(TESTBLOCK_CASE_12)
342+
self.assertEqual(len(inp_data.server.filter("Location")), 1)
343+
self.assertEqual(inp_data.server.filter("Location")[0].value, "~ \"^/(test|[0-9a-zA-Z]{6})$\"")
344+
319345
def test_server_without_last_linebreak(self):
320-
self.assertTrue(nginx.loads(TESTBLOCK_CASE_12) is not None)
346+
self.assertTrue(nginx.loads(TESTBLOCK_CASE_13) is not None)
321347

322348

323349
if __name__ == '__main__':

0 commit comments

Comments
 (0)