Skip to content

Commit

Permalink
Make http types directives analysable
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
chrisnovakovic committed Jul 18, 2022
1 parent ad3d230 commit 0709547
Show file tree
Hide file tree
Showing 4 changed files with 118 additions and 10 deletions.
23 changes: 13 additions & 10 deletions crossplane/analyzer.py
Original file line number Diff line number Diff line change
Expand Up @@ -2126,23 +2126,26 @@ def analyze(fname, stmt, term, ctx=(), strict=False, check_ctx=True,
directive = stmt['directive']
line = stmt['line']

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

# if we don't know where this directive is allowed and how
# many arguments it can take then don't bother analyzing it
if ctx not in CONTEXTS or directive not in DIRECTIVES:
return
if not ctx_http_types:
# if strict and directive isn't recognized then throw error
if strict and directive not in DIRECTIVES:
reason = 'unknown directive "%s"' % directive
raise NgxParserDirectiveUnknownError(reason, fname, line)

# if we don't know where this directive is allowed and how
# many arguments it can take then don't bother analyzing it
if ctx not in CONTEXTS or directive not in DIRECTIVES:
return

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

masks = DIRECTIVES[directive]
masks = [NGX_CONF_1MORE] if ctx_http_types else DIRECTIVES[directive]

# if this directive can't be used in this context then throw an error
if check_ctx:
if not ctx_http_types and check_ctx:
masks = [mask for mask in masks if mask & CONTEXTS[ctx]]
if not masks:
reason = '"%s" directive is not allowed here' % directive
Expand Down
7 changes: 7 additions & 0 deletions tests/configs/types/nginx.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
http {
types {
text/html html;
image/gif gif;
image/jpeg jpg jpeg;
}
}
43 changes: 43 additions & 0 deletions tests/test_build.py
Original file line number Diff line number Diff line change
Expand Up @@ -226,6 +226,49 @@ def test_build_multiple_comments_on_one_line():
assert built == '#comment1\nuser root; #comment2 #comment3'


def test_build_types():
payload = [
{
'directive': 'http',
'line': 1,
'args': [],
'block': [
{
'directive': 'types',
'line': 2,
'args': [],
'block': [
{
'directive': 'text/html',
'line': 3,
'args': ['html']
},
{
'directive': 'image/gif',
'line': 4,
'args': ['gif']
},
{
'directive': 'image/jpeg',
'line': 5,
'args': ['jpg', 'jpeg']
}
]
}
]
}
]
built = crossplane.build(payload, indent=4, tabs=False)
assert built == '\n'.join([
'http {',
' types {',
' text/html html;',
' image/gif gif;',
' image/jpeg jpg jpeg;',
' }',
'}'
])


def test_build_files_with_missing_status_and_errors(tmpdir):
assert len(tmpdir.listdir()) == 0
Expand Down
55 changes: 55 additions & 0 deletions tests/test_parse.py
Original file line number Diff line number Diff line change
Expand Up @@ -975,3 +975,58 @@ def test_comments_between_args():
}
]
}


def test_types_checks():
dirname = os.path.join(here, 'configs', 'types')
config = os.path.join(dirname, 'nginx.conf')
payload = crossplane.parse(
config,
strict=True,
check_ctx=True,
check_args=True,
)

# Check that strict mode doesn't raise errors when parsing http types blocks
assert payload == {
'status': 'ok',
'errors': [],
'config': [
{
'file': os.path.join(dirname, 'nginx.conf'),
'status': 'ok',
'errors': [],
'parsed': [
{
'directive': 'http',
'line': 1,
'args': [],
'block': [
{
'directive': 'types',
'line': 2,
'args': [],
'block': [
{
'directive': 'text/html',
'line': 3,
'args': ['html']
},
{
'directive': 'image/gif',
'line': 4,
'args': ['gif']
},
{
'directive': 'image/jpeg',
'line': 5,
'args': ['jpg', 'jpeg']
}
]
}
]
}
]
}
]
}

0 comments on commit 0709547

Please sign in to comment.