Merge pull request #3287 from certbot/nginx-charset-map

Nginx charset_map and ${VARIABLE_SUBSTITUTION} parsing
This commit is contained in:
schoen 2016-07-27 15:14:15 -07:00 committed by GitHub
commit 94ea424638

View file

@ -25,11 +25,19 @@ class RawNginxParser(object):
key = Word(alphanums + "_/+-.")
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
# Matches anything that is not a special character, and ${SHELL_VARS}, 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"((\".*\")?(\'.*\')?[^\{\};,]?)+")
dquoted = Regex(r'(\".*\")')
squoted = Regex(r"(\'.*\')")
nonspecial = Regex(r"[^\{\};,]")
varsub = Regex(r"(\$\{\w+\})")
# nonspecial nibbles one character at a time, but the other objects take
# precedence. We use ZeroOrMore to allow entries like "break ;" to be
# parsed as assignments
value = Combine(ZeroOrMore(dquoted | squoted | varsub | nonspecial))
location = CharsNotIn("{};," + string.whitespace)
# modifier for location uri [ = | ~ | ~* | ^~ ]
modifier = Literal("=") | Literal("~*") | Literal("~") | Literal("^~")
@ -40,6 +48,7 @@ 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
charset_map_statement = space + Literal("charset_map") + space + value + space + value
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
@ -52,24 +61,27 @@ class RawNginxParser(object):
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)).leaveWhitespace() +
left_bracket +
Group(ZeroOrMore(Group(comment | assignment) | block | map_block) + space).leaveWhitespace()
+ right_bracket)
# key could for instance be "server" or "http", or "location" (in which case
# location_statement needs to have a non-empty location)
block_begin = (Group(space + key + location_statement) ^
Group(if_statement) ^
Group(charset_map_statement)).leaveWhitespace()
block_innards = Group(ZeroOrMore(Group(comment | assignment) | block | map_block)
+ space).leaveWhitespace()
block << Group(block_begin + left_bracket + block_innards + right_bracket)
script = OneOrMore(Group(comment | assignment) ^ block ^ map_block) + space + stringEnd
script.parseWithTabs()
script.parseWithTabs().leaveWhitespace()
def __init__(self, source):
self.source = source