Merge pull request #3230 from certbot/nginx-map-parsing

Permissive parsing of nginx map blocks
This commit is contained in:
schoen 2016-07-13 15:54:17 -07:00 committed by GitHub
commit 25ea215ad8
2 changed files with 29 additions and 8 deletions

View file

@ -0,0 +1,3 @@
map $uri $blogname{
~^(?P<blogpath>/[^/]+/)files/(.*) $blogpath ;
}

View file

@ -23,10 +23,12 @@ class RawNginxParser(object):
right_bracket = space.leaveWhitespace() + Literal("}").suppress()
semicolon = Literal(";").suppress()
key = Word(alphanums + "_/+-.")
dollar_var = Combine(Literal('$') + nonspace)
dollar_var = Combine(Literal('$') + Regex(r"[^\{\};,\s]+"))
condition = Regex(r"\(.+\)")
# Matches anything that is not a special character AND any chars in single
# or double quotes
# All of these COULD be upgraded to something like
# https://stackoverflow.com/a/16130746
value = Regex(r"((\".*\")?(\'.*\')?[^\{\};,]?)+")
location = CharsNotIn("{};," + string.whitespace)
# modifier for location uri [ = | ~ | ~* | ^~ ]
@ -38,19 +40,35 @@ class RawNginxParser(object):
assignment = space + key + Optional(space + value, default=None) + semicolon
location_statement = space + Optional(modifier) + Optional(space + location + space)
if_statement = space + Literal("if") + space + condition + space
map_statement = space + Literal("map") + space + nonspace + space + dollar_var + space
block = Forward()
map_statement = space + Literal("map") + space + nonspace + space + dollar_var + space
# This is NOT an accurate way to parse nginx map entries; it's almost
# certianly too permissive and may be wrong in other ways, but it should
# preserve things correctly in mmmmost or all cases.
#
# - I can neither prove nor disprove that it is corect wrt all escaped
# semicolon situations
# Addresses https://github.com/fatiherikli/nginxparser/issues/19
map_pattern = Regex(r'".*"') | Regex(r"'.*'") | nonspace
map_entry = space + map_pattern + space + value + space + semicolon
map_block = Group(
# key could for instance be "server" or "http", or "location" (in which case
# location_statement needs to have a non-empty location)
Group(map_statement).leaveWhitespace() +
left_bracket +
Group(ZeroOrMore(Group(comment | map_entry)) + space).leaveWhitespace() +
right_bracket)
block = Forward()
block << Group(
# key could for instance be "server" or "http", or "location" (in which case
# location_statement needs to have a non-empty location)
(Group(space + key + location_statement) ^ Group(if_statement) ^
Group(map_statement)).leaveWhitespace() +
(Group(space + key + location_statement) ^ Group(if_statement)).leaveWhitespace() +
left_bracket +
Group(ZeroOrMore(Group(comment | assignment) | block) + space).leaveWhitespace() +
right_bracket)
Group(ZeroOrMore(Group(comment | assignment) | block | map_block) + space).leaveWhitespace()
+ right_bracket)
script = OneOrMore(Group(comment | assignment) ^ block) + space + stringEnd
script = OneOrMore(Group(comment | assignment) ^ block ^ map_block) + space + stringEnd
script.parseWithTabs()
def __init__(self, source):