gixy/gixy/directives/block.py

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)]