Skip to content

Commit 0709547

Browse files
Make http types directives analysable
The syntax of `http` `types` blocks is distinct, in that their child directives are arbitrary MIME types - they therefore can't be analysed when `strict` or `check_ctx` are enabled, and no meaningful analysis can be performed when `check_args` is enabled because the arity of child directives is unknown. Skip the checks performed when `strict` and `check_ctx` are enabled, and hint to the analyser that all directives inside a `types` block accept one or more arguments so that a meaningful check can be performed when `check_args` is enabled. Fixes nginxinc#101.
1 parent ad3d230 commit 0709547

File tree

4 files changed

+118
-10
lines changed

4 files changed

+118
-10
lines changed

crossplane/analyzer.py

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -2126,23 +2126,26 @@ def analyze(fname, stmt, term, ctx=(), strict=False, check_ctx=True,
21262126
directive = stmt['directive']
21272127
line = stmt['line']
21282128

2129-
# if strict and directive isn't recognized then throw error
2130-
if strict and directive not in DIRECTIVES:
2131-
reason = 'unknown directive "%s"' % directive
2132-
raise NgxParserDirectiveUnknownError(reason, fname, line)
2129+
ctx_http_types = len(ctx) >= 2 and ctx[0] == 'http' and ctx[-1] == 'types'
21332130

2134-
# if we don't know where this directive is allowed and how
2135-
# many arguments it can take then don't bother analyzing it
2136-
if ctx not in CONTEXTS or directive not in DIRECTIVES:
2137-
return
2131+
if not ctx_http_types:
2132+
# if strict and directive isn't recognized then throw error
2133+
if strict and directive not in DIRECTIVES:
2134+
reason = 'unknown directive "%s"' % directive
2135+
raise NgxParserDirectiveUnknownError(reason, fname, line)
2136+
2137+
# if we don't know where this directive is allowed and how
2138+
# many arguments it can take then don't bother analyzing it
2139+
if ctx not in CONTEXTS or directive not in DIRECTIVES:
2140+
return
21382141

21392142
args = stmt.get('args') or []
21402143
n_args = len(args)
21412144

2142-
masks = DIRECTIVES[directive]
2145+
masks = [NGX_CONF_1MORE] if ctx_http_types else DIRECTIVES[directive]
21432146

21442147
# if this directive can't be used in this context then throw an error
2145-
if check_ctx:
2148+
if not ctx_http_types and check_ctx:
21462149
masks = [mask for mask in masks if mask & CONTEXTS[ctx]]
21472150
if not masks:
21482151
reason = '"%s" directive is not allowed here' % directive

tests/configs/types/nginx.conf

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
http {
2+
types {
3+
text/html html;
4+
image/gif gif;
5+
image/jpeg jpg jpeg;
6+
}
7+
}

tests/test_build.py

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,49 @@ def test_build_multiple_comments_on_one_line():
226226
assert built == '#comment1\nuser root; #comment2 #comment3'
227227

228228

229+
def test_build_types():
230+
payload = [
231+
{
232+
'directive': 'http',
233+
'line': 1,
234+
'args': [],
235+
'block': [
236+
{
237+
'directive': 'types',
238+
'line': 2,
239+
'args': [],
240+
'block': [
241+
{
242+
'directive': 'text/html',
243+
'line': 3,
244+
'args': ['html']
245+
},
246+
{
247+
'directive': 'image/gif',
248+
'line': 4,
249+
'args': ['gif']
250+
},
251+
{
252+
'directive': 'image/jpeg',
253+
'line': 5,
254+
'args': ['jpg', 'jpeg']
255+
}
256+
]
257+
}
258+
]
259+
}
260+
]
261+
built = crossplane.build(payload, indent=4, tabs=False)
262+
assert built == '\n'.join([
263+
'http {',
264+
' types {',
265+
' text/html html;',
266+
' image/gif gif;',
267+
' image/jpeg jpg jpeg;',
268+
' }',
269+
'}'
270+
])
271+
229272

230273
def test_build_files_with_missing_status_and_errors(tmpdir):
231274
assert len(tmpdir.listdir()) == 0

tests/test_parse.py

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -975,3 +975,58 @@ def test_comments_between_args():
975975
}
976976
]
977977
}
978+
979+
980+
def test_types_checks():
981+
dirname = os.path.join(here, 'configs', 'types')
982+
config = os.path.join(dirname, 'nginx.conf')
983+
payload = crossplane.parse(
984+
config,
985+
strict=True,
986+
check_ctx=True,
987+
check_args=True,
988+
)
989+
990+
# Check that strict mode doesn't raise errors when parsing http types blocks
991+
assert payload == {
992+
'status': 'ok',
993+
'errors': [],
994+
'config': [
995+
{
996+
'file': os.path.join(dirname, 'nginx.conf'),
997+
'status': 'ok',
998+
'errors': [],
999+
'parsed': [
1000+
{
1001+
'directive': 'http',
1002+
'line': 1,
1003+
'args': [],
1004+
'block': [
1005+
{
1006+
'directive': 'types',
1007+
'line': 2,
1008+
'args': [],
1009+
'block': [
1010+
{
1011+
'directive': 'text/html',
1012+
'line': 3,
1013+
'args': ['html']
1014+
},
1015+
{
1016+
'directive': 'image/gif',
1017+
'line': 4,
1018+
'args': ['gif']
1019+
},
1020+
{
1021+
'directive': 'image/jpeg',
1022+
'line': 5,
1023+
'args': ['jpg', 'jpeg']
1024+
}
1025+
]
1026+
}
1027+
]
1028+
}
1029+
]
1030+
}
1031+
]
1032+
}

0 commit comments

Comments
 (0)