def parse_xml(cls, el, source_location): """Parse this document from an XML/etree element""" assert el.tag == 'proxy' match = ProxyMatch.parse_xml(el, source_location) dest = None request_modifications = [] response_modifications = [] strip_script_name = True keep_host = False editable = asbool(el.get('editable')) for child in el: if child.tag == 'dest': if dest is not None: raise DeliveranceSyntaxError( "You cannot have more than one <dest> tag (second tag: %s)" % xml_tostring(child), element=child, source_location=source_location) dest = ProxyDest.parse_xml(child, source_location) elif child.tag == 'transform': if child.get('strip-script-name'): strip_script_name = asbool(child.get('strip-script-name')) if child.get('keep-host'): keep_host = asbool(child.get('keep-host')) ## FIXME: error on other attrs elif child.tag == 'request': request_modifications.append( ProxyRequestModification.parse_xml(child, source_location)) elif child.tag == 'response': response_modifications.append( ProxyResponseModification.parse_xml(child, source_location)) elif child.tag is Comment: continue else: raise DeliveranceSyntaxError( "Unknown tag in <proxy>: %s" % xml_tostring(child), element=child, source_location=source_location) if editable: if not dest: ## FIXME: should this always be a test? raise DeliveranceSyntaxError("You must have a <dest> tag", element=el, source_location=source_location) try: href = uri_template_substitute( dest.href, dict(here=posixpath.dirname(source_location))) except KeyError: raise DeliveranceSyntaxError( 'You can only use <proxy editable="1"> if you have a <dest href="..."> that only contains {here} (you have %s)' % (dest.href)) if not href.startswith('file:'): raise DeliveranceSyntaxError( 'You can only use <proxy editable="1"> if you have a <dest href="file:///..."> (you have %s)' % (dest)) classes = el.get('class', '').split() or None inst = cls(match, dest, request_modifications, response_modifications, strip_script_name=strip_script_name, keep_host=keep_host, source_location=source_location, classes=classes, editable=editable) match.proxy = inst return inst
def parse_xml(cls, el, source_location): """ Creates a Rule object from a parsed XML <rule> element. """ assert el.tag == 'rule' classes = el.get('class', '').split() if not classes: classes = ['default'] theme = None actions = [] suppress_standard = asbool(el.get('suppress-standard')) for child in el.iterchildren(): if child.tag == 'theme': ## FIXME: error if more than one theme theme = Theme.parse_xml(child, source_location) continue if child.tag is etree.Comment: continue action = parse_action(child, source_location) actions.append(action) match = None inst = cls(classes, actions, theme, match, suppress_standard, source_location) for attr in RuleMatch.match_attrs: if el.get(attr): inst.match = RuleMatch.parse_xml(inst, el, source_location) ## FIXME: would last="1" be a good alternative to suppress-standard? break return inst
def __init__(self, pattern): pattern = pattern.strip() super(BooleanMatcher, self).__init__(pattern) if pattern.lower() == 'not': pattern = 'false' if not pattern: pattern = 'true' self.boolean = asbool(pattern)
def __call__(self, s): try: value = asbool(s) except ValueError: value = False if self.boolean: return value else: return not value
def from_xml(cls, tag, source_location): """ Creates an instance of this object from the given parsed XML element """ content = cls.compile_selector(tag, 'content', source_location) theme = cls.compile_selector(tag, 'theme', source_location) if_content = cls.compile_selector(tag, 'if-content', source_location, invertable=True) content_href = tag.get('href') move = asbool(tag.get('move', '1')) collapse_sources = asbool(tag.get('collapse-sources', '0')) return cls(source_location, content, theme, if_content=if_content, content_href=content_href, move=move, nocontent=tag.get('nocontent'), notheme=tag.get('notheme'), manytheme=tag.get('manytheme'), manycontent=tag.get('manycontent'), collapse_sources=collapse_sources)
def parse_xml(cls, el, source_location): """ Parses the <match> element into a match object """ matchargs = cls.parse_match_xml(el, source_location) assert el.tag == cls.element_name classes = el.get('class', '').split() abort = asbool(el.get('abort')) if not abort and not classes: ## FIXME: source location raise DeliveranceSyntaxError( "You must provide some classes in the class attribute") if abort and classes: ## FIXME: source location raise DeliveranceSyntaxError( 'You cannot provide both abort="1" and class="%s"' % (' '.join(classes))) last = asbool(el.get('last')) return cls(classes=classes, abort=abort, last=last, **matchargs)
def parse_xml(cls, el, source_location): """ Parses the <match> element into a match object """ matchargs = cls.parse_match_xml(el, source_location) assert el.tag == cls.element_name classes = el.get('class', '').split() abort = asbool(el.get('abort')) if not abort and not classes: ## FIXME: source location raise DeliveranceSyntaxError( "You must provide some classes in the class attribute") if abort and classes: ## FIXME: source location raise DeliveranceSyntaxError( 'You cannot provide both abort="1" and class="%s"' % (' '.join(classes))) last = asbool(el.get('last')) return cls( classes=classes, abort=abort, last=last, **matchargs)
def parse_xml(cls, el, source_location): """Parse an instance from an etree XML element""" href = el.get('href') pyref = PyReference.parse_xml( el, source_location, default_function='get_proxy_dest', default_objs=dict(AbortProxy=AbortProxy)) next = asbool(el.get('next')) if next and (href or pyref): raise DeliveranceSyntaxError( 'If you have a next="1" attribute you cannot also have an href ' 'or pyref attribute', element=el, source_location=source_location) return cls(href, pyref, next=next, source_location=source_location)
def parse_xml(cls, el, source_location): """Create an instance from a parsed element""" assert el.tag == 'response' pyref = PyReference.parse_xml( el, source_location, default_function='modify_proxy_response', default_objs=dict(AbortProxy=AbortProxy)) header = el.get('header') content = el.get('content') if (not header and content) or (not content and header): raise DeliveranceSyntaxError( "If you provide a header attribute you must provide a content " "attribute, and vice versa", element=el, source_location=source_location) rewrite_links = asbool(el.get('rewrite-links')) return cls(pyref=pyref, header=header, content=content, rewrite_links=rewrite_links, source_location=source_location)
def parse_xml(cls, el, source_location, environ=None, traverse=False): """Parse an instance from an etree XML element""" middleware_factory = None middleware_factory_kwargs = None if traverse and el.tag != 'server-settings': try: el = el.xpath('//server-settings')[0] except IndexError: raise DeliveranceSyntaxError( "There is no <server-settings> element", element=el) if environ is None: environ = os.environ assert el.tag == 'server-settings' server_host = 'localhost:8080' ## FIXME: should these defaults be passed in: execute_pyref = True display_local_files = True edit_local_files = True dev_allow_ips = [] dev_deny_ips = [] dev_htpasswd = None dev_expiration = 0 dev_users = {} dev_secret_file = os.path.join(tempfile.gettempdir(), 'deliverance', 'devauth.txt') for child in el: if child.tag is Comment: continue ## FIXME: should some of these be attributes? elif child.tag == 'server': server_host = cls.substitute(child.text, environ) elif child.tag == 'execute-pyref': execute_pyref = asbool(cls.substitute(child.text, environ)) elif child.tag == 'dev-allow': dev_allow_ips.extend( cls.substitute(child.text, environ).split()) elif child.tag == 'dev-deny': dev_deny_ips.extend( cls.substitute(child.text, environ).split()) elif child.tag == 'dev-htpasswd': dev_htpasswd = os.path.join( os.path.dirname(url_to_filename(source_location)), cls.substitute(child.text, environ)) elif child.tag == 'dev-expiration': dev_expiration = cls.substitute(child.text, environ) if dev_expiration: dev_expiration = int(dev_expiration) elif child.tag == 'display-local-files': display_local_files = asbool( cls.substitute(child.text, environ)) elif child.tag == 'edit-local-files': edit_local_files = asbool(cls.substitute(child.text, environ)) elif child.tag == 'dev-user': username = cls.substitute(child.get('username', ''), environ) ## FIXME: allow hashed password? password = cls.substitute(child.get('password', ''), environ) if not username or not password: raise DeliveranceSyntaxError( "<dev-user> must have both a username and password attribute", element=child) if username in dev_users: raise DeliveranceSyntaxError( '<dev-user username="******"> appears more than once' % username, element=el) dev_users[username] = password elif child.tag == 'dev-secret-file': dev_secret_file = cls.substitute(child.text, environ) elif child.tag == 'middleware-factory': ref = PyReference.parse_xml(child, source_location) middleware_factory = ref.function middleware_factory_kwargs = ref.args or None else: raise DeliveranceSyntaxError( 'Unknown element in <server-settings>: <%s>' % child.tag, element=child) if dev_users and dev_htpasswd: raise DeliveranceSyntaxError( "You can use <dev-htpasswd> or <dev-user>, but not both", element=el) if not dev_users and not dev_htpasswd: ## FIXME: not sure this is the best way to warn print( 'Warning: no <dev-users> or <dev-htpasswd>; logging is inaccessible' ) ## FIXME: add a default allow_ips of 127.0.0.1? return cls(server_host, execute_pyref=execute_pyref, display_local_files=display_local_files, edit_local_files=edit_local_files, dev_allow_ips=dev_allow_ips, dev_deny_ips=dev_deny_ips, dev_users=dev_users, dev_htpasswd=dev_htpasswd, dev_expiration=dev_expiration, source_location=source_location, dev_secret_file=dev_secret_file, middleware_factory=middleware_factory, middleware_factory_kwargs=middleware_factory_kwargs)
def parse_xml(cls, el, source_location): """Parse this document from an XML/etree element""" assert el.tag == 'proxy' match = ProxyMatch.parse_xml(el, source_location) dest = None wsgi = None request_modifications = [] response_modifications = [] strip_script_name = True keep_host = False editable = asbool(el.get('editable')) rewriting_links = None ## FIXME: this inline validation is a bit brittle because it is ## order-dependent, but validation errors generally aren't for child in el: if child.tag == 'dest': if dest is not None: raise DeliveranceSyntaxError( "You cannot have more than one <dest> tag (second tag: %s)" % xml_tostring(child), element=child, source_location=source_location) if wsgi is not None: raise DeliveranceSyntaxError( "You cannot have both a <dest> tag and a <wsgi> tag (second tag: %s)" % xml_tostring(child), element=child, source_location=source_location) dest = ProxyDest.parse_xml(child, source_location) elif child.tag == 'wsgi': if wsgi is not None: raise DeliveranceSyntaxError( "You cannot have more than one <wsgi> tag (second tag: %s)" % xml_tostring(child), element=child, source_location=source_location) if dest is not None: raise DeliveranceSyntaxError( "You cannot have both a <dest> tag and a <wsgi> tag (second tag: %s)" % xml_tostring(child), element=child, source_location=source_location) if rewriting_links is not None: raise DeliveranceSyntaxError( "You cannot use ``<response rewrite-links='1'>`` in a proxy with a ``<wsgi>`` tag", element=child, source_location=source_location) wsgi = ProxyWsgi.parse_xml(child, source_location) elif child.tag == 'transform': if child.get('strip-script-name'): strip_script_name = asbool(child.get('strip-script-name')) if child.get('keep-host'): keep_host = asbool(child.get('keep-host')) ## FIXME: error on other attrs elif child.tag == 'request': request_modifications.append( ProxyRequestModification.parse_xml(child, source_location)) elif child.tag == 'response': mod = ProxyResponseModification.parse_xml( child, source_location) if mod.rewrite_links == True: rewriting_links = mod if wsgi is not None: raise DeliveranceSyntaxError( "You cannot use ``<response rewrite-links='1'>`` in a proxy with a ``<wsgi>`` tag", element=child, source_location=source_location) response_modifications.append(mod) elif child.tag is Comment: continue else: raise DeliveranceSyntaxError("Unknown tag in <proxy>: %s" % xml_tostring(child), element=child, source_location=source_location) if editable: if not dest: ## FIXME: should this always be a test? raise DeliveranceSyntaxError("You must have a <dest> tag", element=el, source_location=source_location) try: href = uri_template_substitute( dest.href, dict(here=posixpath.dirname(source_location))) except KeyError: raise DeliveranceSyntaxError( 'You can only use <proxy editable="1"> if you have a <dest href="..."> that only contains {here} (you have %s)' % (dest.href)) if not href.startswith('file:'): raise DeliveranceSyntaxError( 'You can only use <proxy editable="1"> if you have a <dest href="file:///..."> (you have %s)' % (dest)) classes = el.get('class', '').split() or None inst = cls(match, dest, request_modifications, response_modifications, strip_script_name=strip_script_name, keep_host=keep_host, source_location=source_location, classes=classes, editable=editable, wsgi=wsgi) match.proxy = inst return inst
def parse_xml(cls, el, source_location, environ=None, traverse=False): """Parse an instance from an etree XML element""" if traverse and el.tag != "server-settings": try: el = el.xpath("//server-settings")[0] except IndexError: raise DeliveranceSyntaxError("There is no <server-settings> element", element=el) if environ is None: environ = os.environ assert el.tag == "server-settings" server_host = "localhost:8080" ## FIXME: should these defaults be passed in: execute_pyref = True display_local_files = True edit_local_files = True dev_allow_ips = [] dev_deny_ips = [] dev_htpasswd = None dev_expiration = 0 dev_users = {} dev_secret_file = os.path.join(tempfile.gettempdir(), "deliverance", "devauth.txt") for child in el: if child.tag is Comment: continue ## FIXME: should some of these be attributes? elif child.tag == "server": server_host = cls.substitute(child.text, environ) elif child.tag == "execute-pyref": execute_pyref = asbool(cls.substitute(child.text, environ)) elif child.tag == "dev-allow": dev_allow_ips.extend(cls.substitute(child.text, environ).split()) elif child.tag == "dev-deny": dev_deny_ips.extend(cls.substitute(child.text, environ).split()) elif child.tag == "dev-htpasswd": dev_htpasswd = os.path.join( os.path.dirname(url_to_filename(source_location)), cls.substitute(child.text, environ) ) elif child.tag == "dev-expiration": dev_expiration = cls.substitute(child.text, environ) if dev_expiration: dev_expiration = int(dev_expiration) elif child.tag == "display-local-files": display_local_files = asbool(cls.substitute(child.text, environ)) elif child.tag == "edit-local-files": edit_local_files = asbool(cls.substitute(child.text, environ)) elif child.tag == "dev-user": username = cls.substitute(child.get("username", ""), environ) ## FIXME: allow hashed password? password = cls.substitute(child.get("password", ""), environ) if not username or not password: raise DeliveranceSyntaxError( "<dev-user> must have both a username and password attribute", element=child ) if username in dev_users: raise DeliveranceSyntaxError( '<dev-user username="******"> appears more than once' % username, element=el ) dev_users[username] = password elif child.tag == "dev-secret-file": dev_secret_file = cls.substitute(child.text, environ) else: raise DeliveranceSyntaxError("Unknown element in <server-settings>: <%s>" % child.tag, element=child) if dev_users and dev_htpasswd: raise DeliveranceSyntaxError("You can use <dev-htpasswd> or <dev-user>, but not both", element=el) if not dev_users and not dev_htpasswd: ## FIXME: not sure this is the best way to warn print "Warning: no <dev-users> or <dev-htpasswd>; logging is inaccessible" ## FIXME: add a default allow_ips of 127.0.0.1? return cls( server_host, execute_pyref=execute_pyref, display_local_files=display_local_files, edit_local_files=edit_local_files, dev_allow_ips=dev_allow_ips, dev_deny_ips=dev_deny_ips, dev_users=dev_users, dev_htpasswd=dev_htpasswd, dev_expiration=dev_expiration, source_location=source_location, dev_secret_file=dev_secret_file, )
def parse_xml(cls, el, source_location): """Parse this document from an XML/etree element""" assert el.tag == 'proxy' match = ProxyMatch.parse_xml(el, source_location) dest = None wsgi = None request_modifications = [] response_modifications = [] strip_script_name = True keep_host = False editable = asbool(el.get('editable')) rewriting_links = None ## FIXME: this inline validation is a bit brittle because it is ## order-dependent, but validation errors generally aren't for child in el: if child.tag == 'dest': if dest is not None: raise DeliveranceSyntaxError( "You cannot have more than one <dest> tag (second tag: %s)" % xml_tostring(child), element=child, source_location=source_location) if wsgi is not None: raise DeliveranceSyntaxError( "You cannot have both a <dest> tag and a <wsgi> tag (second tag: %s)" % xml_tostring(child), element=child, source_location=source_location) dest = ProxyDest.parse_xml(child, source_location) elif child.tag == 'wsgi': if wsgi is not None: raise DeliveranceSyntaxError( "You cannot have more than one <wsgi> tag (second tag: %s)" % xml_tostring(child), element=child, source_location=source_location) if dest is not None: raise DeliveranceSyntaxError( "You cannot have both a <dest> tag and a <wsgi> tag (second tag: %s)" % xml_tostring(child), element=child, source_location=source_location) if rewriting_links is not None: raise DeliveranceSyntaxError( "You cannot use ``<response rewrite-links='1'>`` in a proxy with a ``<wsgi>`` tag", element=child, source_location=source_location) wsgi = ProxyWsgi.parse_xml(child, source_location) elif child.tag == 'transform': if child.get('strip-script-name'): strip_script_name = asbool(child.get('strip-script-name')) if child.get('keep-host'): keep_host = asbool(child.get('keep-host')) ## FIXME: error on other attrs elif child.tag == 'request': request_modifications.append( ProxyRequestModification.parse_xml(child, source_location)) elif child.tag == 'response': mod = ProxyResponseModification.parse_xml(child, source_location) if mod.rewrite_links == True: rewriting_links = mod if wsgi is not None: raise DeliveranceSyntaxError( "You cannot use ``<response rewrite-links='1'>`` in a proxy with a ``<wsgi>`` tag", element=child, source_location=source_location) response_modifications.append(mod) elif child.tag is Comment: continue else: raise DeliveranceSyntaxError( "Unknown tag in <proxy>: %s" % xml_tostring(child), element=child, source_location=source_location) if editable: if not dest: ## FIXME: should this always be a test? raise DeliveranceSyntaxError("You must have a <dest> tag", element=el, source_location=source_location) try: href = uri_template_substitute( dest.href, dict(here=posixpath.dirname(source_location))) except KeyError: raise DeliveranceSyntaxError( 'You can only use <proxy editable="1"> if you have a <dest href="..."> that only contains {here} (you have %s)' % (dest.href)) if not href.startswith('file:'): raise DeliveranceSyntaxError( 'You can only use <proxy editable="1"> if you have a <dest href="file:///..."> (you have %s)' % (dest)) classes = el.get('class', '').split() or None inst = cls(match, dest, request_modifications, response_modifications, strip_script_name=strip_script_name, keep_host=keep_host, source_location=source_location, classes=classes, editable=editable, wsgi=wsgi) match.proxy = inst return inst
def parse_xml(cls, el, source_location, environ=None, traverse=False): """Parse an instance from an etree XML element""" middleware_factory = None middleware_factory_kwargs = None if traverse and el.tag != 'server-settings': try: el = el.xpath('//server-settings')[0] except IndexError: raise DeliveranceSyntaxError( "There is no <server-settings> element", element=el) if environ is None: environ = os.environ assert el.tag == 'server-settings' server_host = 'localhost:8080' ## FIXME: should these defaults be passed in: execute_pyref = True display_local_files = True edit_local_files = True dev_allow_ips = [] dev_deny_ips = [] dev_htpasswd = None dev_expiration = 0 dev_users = {} dev_secret_file = os.path.join(tempfile.gettempdir(), 'deliverance', 'devauth.txt') for child in el: if child.tag is Comment: continue ## FIXME: should some of these be attributes? elif child.tag == 'server': server_host = cls.substitute(child.text, environ) elif child.tag == 'execute-pyref': execute_pyref = asbool(cls.substitute(child.text, environ)) elif child.tag == 'dev-allow': dev_allow_ips.extend(cls.substitute(child.text, environ).split()) elif child.tag == 'dev-deny': dev_deny_ips.extend(cls.substitute(child.text, environ).split()) elif child.tag == 'dev-htpasswd': dev_htpasswd = os.path.join(os.path.dirname(url_to_filename(source_location)), cls.substitute(child.text, environ)) elif child.tag == 'dev-expiration': dev_expiration = cls.substitute(child.text, environ) if dev_expiration: dev_expiration = int(dev_expiration) elif child.tag == 'display-local-files': display_local_files = asbool(cls.substitute(child.text, environ)) elif child.tag == 'edit-local-files': edit_local_files = asbool(cls.substitute(child.text, environ)) elif child.tag == 'dev-user': username = cls.substitute(child.get('username', ''), environ) ## FIXME: allow hashed password? password = cls.substitute(child.get('password', ''), environ) if not username or not password: raise DeliveranceSyntaxError( "<dev-user> must have both a username and password attribute", element=child) if username in dev_users: raise DeliveranceSyntaxError( '<dev-user username="******"> appears more than once' % username, element=el) dev_users[username] = password elif child.tag == 'dev-secret-file': dev_secret_file = cls.substitute(child.text, environ) elif child.tag == 'middleware-factory': ref = PyReference.parse_xml(child, source_location) middleware_factory = ref.function middleware_factory_kwargs = ref.args or None else: raise DeliveranceSyntaxError( 'Unknown element in <server-settings>: <%s>' % child.tag, element=child) if dev_users and dev_htpasswd: raise DeliveranceSyntaxError( "You can use <dev-htpasswd> or <dev-user>, but not both", element=el) if not dev_users and not dev_htpasswd: ## FIXME: not sure this is the best way to warn print 'Warning: no <dev-users> or <dev-htpasswd>; logging is inaccessible' ## FIXME: add a default allow_ips of 127.0.0.1? return cls(server_host, execute_pyref=execute_pyref, display_local_files=display_local_files, edit_local_files=edit_local_files, dev_allow_ips=dev_allow_ips, dev_deny_ips=dev_deny_ips, dev_users=dev_users, dev_htpasswd=dev_htpasswd, dev_expiration=dev_expiration, source_location=source_location, dev_secret_file=dev_secret_file, middleware_factory=middleware_factory, middleware_factory_kwargs=middleware_factory_kwargs)