mirror of https://github.com/yandex/gixy
201 lines
5.4 KiB
Python
201 lines
5.4 KiB
Python
try:
|
|
from functools import cached_property
|
|
except ImportError:
|
|
from cached_property import cached_property
|
|
|
|
from gixy.directives.directive import Directive
|
|
from gixy.core.variable import Variable
|
|
from gixy.core.regexp import Regexp
|
|
|
|
|
|
def get_overrides():
|
|
result = {}
|
|
for klass in Block.__subclasses__():
|
|
if not klass.nginx_name:
|
|
continue
|
|
|
|
if not klass.__name__.endswith('Block'):
|
|
continue
|
|
|
|
result[klass.nginx_name] = klass
|
|
return result
|
|
|
|
|
|
class Block(Directive):
|
|
nginx_name = None
|
|
is_block = True
|
|
self_context = True
|
|
|
|
def __init__(self, name, args):
|
|
super(Block, self).__init__(name, args)
|
|
self.children = []
|
|
|
|
def some(self, name, flat=True):
|
|
for child in self.children:
|
|
if child.name == name:
|
|
return child
|
|
if flat and child.is_block and not child.self_context:
|
|
result = child.some(name, flat=flat)
|
|
if result:
|
|
return result
|
|
return None
|
|
|
|
def find(self, name, flat=False):
|
|
result = []
|
|
for child in self.children:
|
|
if child.name == name:
|
|
result.append(child)
|
|
if flat and child.is_block and not child.self_context:
|
|
result += child.find(name)
|
|
return result
|
|
|
|
def find_recursive(self, name):
|
|
result = []
|
|
for child in self.children:
|
|
if child.name == name:
|
|
result.append(child)
|
|
if child.is_block:
|
|
result += child.find_recursive(name)
|
|
return result
|
|
|
|
def append(self, directive):
|
|
directive.set_parent(self)
|
|
self.children.append(directive)
|
|
|
|
def __str__(self):
|
|
return '{name} {args} {{'.format(name=self.name, args=' '.join(self.args))
|
|
|
|
|
|
class Root(Block):
|
|
nginx_name = None
|
|
|
|
def __init__(self):
|
|
super(Root, self).__init__(None, [])
|
|
|
|
|
|
class HttpBlock(Block):
|
|
nginx_name = 'http'
|
|
|
|
def __init__(self, name, args):
|
|
super(HttpBlock, self).__init__(name, args)
|
|
|
|
|
|
class ServerBlock(Block):
|
|
nginx_name = 'server'
|
|
|
|
def __init__(self, name, args):
|
|
super(ServerBlock, self).__init__(name, args)
|
|
|
|
def get_names(self):
|
|
return self.find('server_name')
|
|
|
|
def __str__(self):
|
|
server_names = [str(sn) for sn in self.find('server_name')]
|
|
if server_names:
|
|
return 'server {{\n{0}'.format('\n'.join(server_names[:2]))
|
|
return 'server {'
|
|
|
|
|
|
class LocationBlock(Block):
|
|
nginx_name = 'location'
|
|
provide_variables = True
|
|
|
|
def __init__(self, name, args):
|
|
super(LocationBlock, self).__init__(name, args)
|
|
if len(args) == 2:
|
|
self.modifier, self.path = args
|
|
else:
|
|
self.modifier = None
|
|
self.path = args[0]
|
|
|
|
@property
|
|
def is_internal(self):
|
|
return self.some('internal') is not None
|
|
|
|
@cached_property
|
|
def variables(self):
|
|
if not self.modifier or self.modifier not in ('~', '~*'):
|
|
return []
|
|
|
|
regexp = Regexp(self.path, case_sensitive=self.modifier == '~')
|
|
result = []
|
|
for name, group in regexp.groups.items():
|
|
result.append(Variable(name=name, value=group, boundary=None, provider=self))
|
|
return result
|
|
|
|
|
|
class IfBlock(Block):
|
|
nginx_name = 'if'
|
|
self_context = False
|
|
|
|
def __init__(self, name, args):
|
|
super(IfBlock, self).__init__(name, args)
|
|
self.operand = None
|
|
self.value = None
|
|
self.variable = None
|
|
|
|
if len(args) == 1:
|
|
# if ($slow)
|
|
self.variable = args[0]
|
|
elif len(args) == 2:
|
|
# if (!-e $foo)
|
|
self.operand, self.value = args
|
|
elif len(args) == 3:
|
|
# if ($request_method = POST)
|
|
self.variable, self.operand, self.value = args
|
|
else:
|
|
raise Exception('Unknown "if" definition, args: {0!r}'.format(args))
|
|
|
|
def __str__(self):
|
|
return '{name} ({args}) {{'.format(name=self.name, args=' '.join(self.args))
|
|
|
|
|
|
class IncludeBlock(Block):
|
|
nginx_name = 'include'
|
|
self_context = False
|
|
|
|
def __init__(self, name, args):
|
|
super(IncludeBlock, self).__init__(name, args)
|
|
self.file_path = args[0]
|
|
|
|
def __str__(self):
|
|
return 'include {0};'.format(self.file_path)
|
|
|
|
|
|
class MapBlock(Block):
|
|
nginx_name = 'map'
|
|
self_context = False
|
|
provide_variables = True
|
|
|
|
def __init__(self, name, args):
|
|
super(MapBlock, self).__init__(name, args)
|
|
self.source = args[0]
|
|
self.variable = args[1].strip('$')
|
|
|
|
@cached_property
|
|
def variables(self):
|
|
# TODO(buglloc): Finish him!
|
|
return [Variable(name=self.variable, value='', boundary=None, provider=self, have_script=False)]
|
|
|
|
|
|
class GeoBlock(Block):
|
|
nginx_name = 'geo'
|
|
self_context = False
|
|
provide_variables = True
|
|
|
|
def __init__(self, name, args):
|
|
super(GeoBlock, self).__init__(name, args)
|
|
if len(args) == 1: # geo uses $remote_addr as default source of the value
|
|
source = '$remote_addr'
|
|
variable = args[0].strip('$')
|
|
else:
|
|
source = args[0]
|
|
variable = args[1].strip('$')
|
|
self.source = source
|
|
self.variable = variable
|
|
|
|
@cached_property
|
|
def variables(self):
|
|
# TODO(buglloc): Finish him! -- same as in MapBlock
|
|
return [Variable(name=self.variable, value='', boundary=None, provider=self, have_script=False)]
|