You can not select more than 25 topics
			Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
		
		
		
		
			
				
					629 lines
				
				22 KiB
			
		
		
			
		
	
	
					629 lines
				
				22 KiB
			| 
								 
											8 years ago
										 
									 | 
							
								# -*- coding: utf-8 -*-
							 | 
						||
| 
								 | 
							
								"""
							 | 
						||
| 
								 | 
							
								    werkzeug.utils
							 | 
						||
| 
								 | 
							
								    ~~~~~~~~~~~~~~
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    This module implements various utilities for WSGI applications.  Most of
							 | 
						||
| 
								 | 
							
								    them are used by the request and response wrappers but especially for
							 | 
						||
| 
								 | 
							
								    middleware development it makes sense to use them without the wrappers.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    :copyright: (c) 2014 by the Werkzeug Team, see AUTHORS for more details.
							 | 
						||
| 
								 | 
							
								    :license: BSD, see LICENSE for more details.
							 | 
						||
| 
								 | 
							
								"""
							 | 
						||
| 
								 | 
							
								import re
							 | 
						||
| 
								 | 
							
								import os
							 | 
						||
| 
								 | 
							
								import sys
							 | 
						||
| 
								 | 
							
								import pkgutil
							 | 
						||
| 
								 | 
							
								try:
							 | 
						||
| 
								 | 
							
								    from html.entities import name2codepoint
							 | 
						||
| 
								 | 
							
								except ImportError:
							 | 
						||
| 
								 | 
							
								    from htmlentitydefs import name2codepoint
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								from werkzeug._compat import unichr, text_type, string_types, iteritems, \
							 | 
						||
| 
								 | 
							
								    reraise, PY2
							 | 
						||
| 
								 | 
							
								from werkzeug._internal import _DictAccessorProperty, \
							 | 
						||
| 
								 | 
							
								    _parse_signature, _missing
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								_format_re = re.compile(r'\$(?:(%s)|\{(%s)\})' % (('[a-zA-Z_][a-zA-Z0-9_]*',) * 2))
							 | 
						||
| 
								 | 
							
								_entity_re = re.compile(r'&([^;]+);')
							 | 
						||
| 
								 | 
							
								_filename_ascii_strip_re = re.compile(r'[^A-Za-z0-9_.-]')
							 | 
						||
| 
								 | 
							
								_windows_device_files = ('CON', 'AUX', 'COM1', 'COM2', 'COM3', 'COM4', 'LPT1',
							 | 
						||
| 
								 | 
							
								                         'LPT2', 'LPT3', 'PRN', 'NUL')
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class cached_property(property):
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    """A decorator that converts a function into a lazy property.  The
							 | 
						||
| 
								 | 
							
								    function wrapped is called the first time to retrieve the result
							 | 
						||
| 
								 | 
							
								    and then that calculated result is used the next time you access
							 | 
						||
| 
								 | 
							
								    the value::
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        class Foo(object):
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            @cached_property
							 | 
						||
| 
								 | 
							
								            def foo(self):
							 | 
						||
| 
								 | 
							
								                # calculate something important here
							 | 
						||
| 
								 | 
							
								                return 42
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    The class has to have a `__dict__` in order for this property to
							 | 
						||
| 
								 | 
							
								    work.
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    # implementation detail: A subclass of python's builtin property
							 | 
						||
| 
								 | 
							
								    # decorator, we override __get__ to check for a cached value. If one
							 | 
						||
| 
								 | 
							
								    # choses to invoke __get__ by hand the property will still work as
							 | 
						||
| 
								 | 
							
								    # expected because the lookup logic is replicated in __get__ for
							 | 
						||
| 
								 | 
							
								    # manual invocation.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def __init__(self, func, name=None, doc=None):
							 | 
						||
| 
								 | 
							
								        self.__name__ = name or func.__name__
							 | 
						||
| 
								 | 
							
								        self.__module__ = func.__module__
							 | 
						||
| 
								 | 
							
								        self.__doc__ = doc or func.__doc__
							 | 
						||
| 
								 | 
							
								        self.func = func
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def __set__(self, obj, value):
							 | 
						||
| 
								 | 
							
								        obj.__dict__[self.__name__] = value
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def __get__(self, obj, type=None):
							 | 
						||
| 
								 | 
							
								        if obj is None:
							 | 
						||
| 
								 | 
							
								            return self
							 | 
						||
| 
								 | 
							
								        value = obj.__dict__.get(self.__name__, _missing)
							 | 
						||
| 
								 | 
							
								        if value is _missing:
							 | 
						||
| 
								 | 
							
								            value = self.func(obj)
							 | 
						||
| 
								 | 
							
								            obj.__dict__[self.__name__] = value
							 | 
						||
| 
								 | 
							
								        return value
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class environ_property(_DictAccessorProperty):
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    """Maps request attributes to environment variables. This works not only
							 | 
						||
| 
								 | 
							
								    for the Werzeug request object, but also any other class with an
							 | 
						||
| 
								 | 
							
								    environ attribute:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    >>> class Test(object):
							 | 
						||
| 
								 | 
							
								    ...     environ = {'key': 'value'}
							 | 
						||
| 
								 | 
							
								    ...     test = environ_property('key')
							 | 
						||
| 
								 | 
							
								    >>> var = Test()
							 | 
						||
| 
								 | 
							
								    >>> var.test
							 | 
						||
| 
								 | 
							
								    'value'
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    If you pass it a second value it's used as default if the key does not
							 | 
						||
| 
								 | 
							
								    exist, the third one can be a converter that takes a value and converts
							 | 
						||
| 
								 | 
							
								    it.  If it raises :exc:`ValueError` or :exc:`TypeError` the default value
							 | 
						||
| 
								 | 
							
								    is used. If no default value is provided `None` is used.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Per default the property is read only.  You have to explicitly enable it
							 | 
						||
| 
								 | 
							
								    by passing ``read_only=False`` to the constructor.
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    read_only = True
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def lookup(self, obj):
							 | 
						||
| 
								 | 
							
								        return obj.environ
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class header_property(_DictAccessorProperty):
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    """Like `environ_property` but for headers."""
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def lookup(self, obj):
							 | 
						||
| 
								 | 
							
								        return obj.headers
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class HTMLBuilder(object):
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    """Helper object for HTML generation.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Per default there are two instances of that class.  The `html` one, and
							 | 
						||
| 
								 | 
							
								    the `xhtml` one for those two dialects.  The class uses keyword parameters
							 | 
						||
| 
								 | 
							
								    and positional parameters to generate small snippets of HTML.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Keyword parameters are converted to XML/SGML attributes, positional
							 | 
						||
| 
								 | 
							
								    arguments are used as children.  Because Python accepts positional
							 | 
						||
| 
								 | 
							
								    arguments before keyword arguments it's a good idea to use a list with the
							 | 
						||
| 
								 | 
							
								    star-syntax for some children:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    >>> html.p(class_='foo', *[html.a('foo', href='foo.html'), ' ',
							 | 
						||
| 
								 | 
							
								    ...                        html.a('bar', href='bar.html')])
							 | 
						||
| 
								 | 
							
								    u'<p class="foo"><a href="foo.html">foo</a> <a href="bar.html">bar</a></p>'
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    This class works around some browser limitations and can not be used for
							 | 
						||
| 
								 | 
							
								    arbitrary SGML/XML generation.  For that purpose lxml and similar
							 | 
						||
| 
								 | 
							
								    libraries exist.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Calling the builder escapes the string passed:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    >>> html.p(html("<foo>"))
							 | 
						||
| 
								 | 
							
								    u'<p><foo></p>'
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    _entity_re = re.compile(r'&([^;]+);')
							 | 
						||
| 
								 | 
							
								    _entities = name2codepoint.copy()
							 | 
						||
| 
								 | 
							
								    _entities['apos'] = 39
							 | 
						||
| 
								 | 
							
								    _empty_elements = set([
							 | 
						||
| 
								 | 
							
								        'area', 'base', 'basefont', 'br', 'col', 'command', 'embed', 'frame',
							 | 
						||
| 
								 | 
							
								        'hr', 'img', 'input', 'keygen', 'isindex', 'link', 'meta', 'param',
							 | 
						||
| 
								 | 
							
								        'source', 'wbr'
							 | 
						||
| 
								 | 
							
								    ])
							 | 
						||
| 
								 | 
							
								    _boolean_attributes = set([
							 | 
						||
| 
								 | 
							
								        'selected', 'checked', 'compact', 'declare', 'defer', 'disabled',
							 | 
						||
| 
								 | 
							
								        'ismap', 'multiple', 'nohref', 'noresize', 'noshade', 'nowrap'
							 | 
						||
| 
								 | 
							
								    ])
							 | 
						||
| 
								 | 
							
								    _plaintext_elements = set(['textarea'])
							 | 
						||
| 
								 | 
							
								    _c_like_cdata = set(['script', 'style'])
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def __init__(self, dialect):
							 | 
						||
| 
								 | 
							
								        self._dialect = dialect
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def __call__(self, s):
							 | 
						||
| 
								 | 
							
								        return escape(s)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def __getattr__(self, tag):
							 | 
						||
| 
								 | 
							
								        if tag[:2] == '__':
							 | 
						||
| 
								 | 
							
								            raise AttributeError(tag)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        def proxy(*children, **arguments):
							 | 
						||
| 
								 | 
							
								            buffer = '<' + tag
							 | 
						||
| 
								 | 
							
								            for key, value in iteritems(arguments):
							 | 
						||
| 
								 | 
							
								                if value is None:
							 | 
						||
| 
								 | 
							
								                    continue
							 | 
						||
| 
								 | 
							
								                if key[-1] == '_':
							 | 
						||
| 
								 | 
							
								                    key = key[:-1]
							 | 
						||
| 
								 | 
							
								                if key in self._boolean_attributes:
							 | 
						||
| 
								 | 
							
								                    if not value:
							 | 
						||
| 
								 | 
							
								                        continue
							 | 
						||
| 
								 | 
							
								                    if self._dialect == 'xhtml':
							 | 
						||
| 
								 | 
							
								                        value = '="' + key + '"'
							 | 
						||
| 
								 | 
							
								                    else:
							 | 
						||
| 
								 | 
							
								                        value = ''
							 | 
						||
| 
								 | 
							
								                else:
							 | 
						||
| 
								 | 
							
								                    value = '="' + escape(value) + '"'
							 | 
						||
| 
								 | 
							
								                buffer += ' ' + key + value
							 | 
						||
| 
								 | 
							
								            if not children and tag in self._empty_elements:
							 | 
						||
| 
								 | 
							
								                if self._dialect == 'xhtml':
							 | 
						||
| 
								 | 
							
								                    buffer += ' />'
							 | 
						||
| 
								 | 
							
								                else:
							 | 
						||
| 
								 | 
							
								                    buffer += '>'
							 | 
						||
| 
								 | 
							
								                return buffer
							 | 
						||
| 
								 | 
							
								            buffer += '>'
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            children_as_string = ''.join([text_type(x) for x in children
							 | 
						||
| 
								 | 
							
								                                          if x is not None])
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								            if children_as_string:
							 | 
						||
| 
								 | 
							
								                if tag in self._plaintext_elements:
							 | 
						||
| 
								 | 
							
								                    children_as_string = escape(children_as_string)
							 | 
						||
| 
								 | 
							
								                elif tag in self._c_like_cdata and self._dialect == 'xhtml':
							 | 
						||
| 
								 | 
							
								                    children_as_string = '/*<![CDATA[*/' + \
							 | 
						||
| 
								 | 
							
								                                         children_as_string + '/*]]>*/'
							 | 
						||
| 
								 | 
							
								            buffer += children_as_string + '</' + tag + '>'
							 | 
						||
| 
								 | 
							
								            return buffer
							 | 
						||
| 
								 | 
							
								        return proxy
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def __repr__(self):
							 | 
						||
| 
								 | 
							
								        return '<%s for %r>' % (
							 | 
						||
| 
								 | 
							
								            self.__class__.__name__,
							 | 
						||
| 
								 | 
							
								            self._dialect
							 | 
						||
| 
								 | 
							
								        )
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								html = HTMLBuilder('html')
							 | 
						||
| 
								 | 
							
								xhtml = HTMLBuilder('xhtml')
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def get_content_type(mimetype, charset):
							 | 
						||
| 
								 | 
							
								    """Returns the full content type string with charset for a mimetype.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    If the mimetype represents text the charset will be appended as charset
							 | 
						||
| 
								 | 
							
								    parameter, otherwise the mimetype is returned unchanged.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    :param mimetype: the mimetype to be used as content type.
							 | 
						||
| 
								 | 
							
								    :param charset: the charset to be appended in case it was a text mimetype.
							 | 
						||
| 
								 | 
							
								    :return: the content type.
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    if mimetype.startswith('text/') or \
							 | 
						||
| 
								 | 
							
								       mimetype == 'application/xml' or \
							 | 
						||
| 
								 | 
							
								       (mimetype.startswith('application/') and
							 | 
						||
| 
								 | 
							
								            mimetype.endswith('+xml')):
							 | 
						||
| 
								 | 
							
								        mimetype += '; charset=' + charset
							 | 
						||
| 
								 | 
							
								    return mimetype
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def format_string(string, context):
							 | 
						||
| 
								 | 
							
								    """String-template format a string:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    >>> format_string('$foo and ${foo}s', dict(foo=42))
							 | 
						||
| 
								 | 
							
								    '42 and 42s'
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    This does not do any attribute lookup etc.  For more advanced string
							 | 
						||
| 
								 | 
							
								    formattings have a look at the `werkzeug.template` module.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    :param string: the format string.
							 | 
						||
| 
								 | 
							
								    :param context: a dict with the variables to insert.
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    def lookup_arg(match):
							 | 
						||
| 
								 | 
							
								        x = context[match.group(1) or match.group(2)]
							 | 
						||
| 
								 | 
							
								        if not isinstance(x, string_types):
							 | 
						||
| 
								 | 
							
								            x = type(string)(x)
							 | 
						||
| 
								 | 
							
								        return x
							 | 
						||
| 
								 | 
							
								    return _format_re.sub(lookup_arg, string)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def secure_filename(filename):
							 | 
						||
| 
								 | 
							
								    r"""Pass it a filename and it will return a secure version of it.  This
							 | 
						||
| 
								 | 
							
								    filename can then safely be stored on a regular file system and passed
							 | 
						||
| 
								 | 
							
								    to :func:`os.path.join`.  The filename returned is an ASCII only string
							 | 
						||
| 
								 | 
							
								    for maximum portability.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    On windows systems the function also makes sure that the file is not
							 | 
						||
| 
								 | 
							
								    named after one of the special device files.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    >>> secure_filename("My cool movie.mov")
							 | 
						||
| 
								 | 
							
								    'My_cool_movie.mov'
							 | 
						||
| 
								 | 
							
								    >>> secure_filename("../../../etc/passwd")
							 | 
						||
| 
								 | 
							
								    'etc_passwd'
							 | 
						||
| 
								 | 
							
								    >>> secure_filename(u'i contain cool \xfcml\xe4uts.txt')
							 | 
						||
| 
								 | 
							
								    'i_contain_cool_umlauts.txt'
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    The function might return an empty filename.  It's your responsibility
							 | 
						||
| 
								 | 
							
								    to ensure that the filename is unique and that you generate random
							 | 
						||
| 
								 | 
							
								    filename if the function returned an empty one.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    .. versionadded:: 0.5
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    :param filename: the filename to secure
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    if isinstance(filename, text_type):
							 | 
						||
| 
								 | 
							
								        from unicodedata import normalize
							 | 
						||
| 
								 | 
							
								        filename = normalize('NFKD', filename).encode('ascii', 'ignore')
							 | 
						||
| 
								 | 
							
								        if not PY2:
							 | 
						||
| 
								 | 
							
								            filename = filename.decode('ascii')
							 | 
						||
| 
								 | 
							
								    for sep in os.path.sep, os.path.altsep:
							 | 
						||
| 
								 | 
							
								        if sep:
							 | 
						||
| 
								 | 
							
								            filename = filename.replace(sep, ' ')
							 | 
						||
| 
								 | 
							
								    filename = str(_filename_ascii_strip_re.sub('', '_'.join(
							 | 
						||
| 
								 | 
							
								                   filename.split()))).strip('._')
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    # on nt a couple of special files are present in each folder.  We
							 | 
						||
| 
								 | 
							
								    # have to ensure that the target file is not such a filename.  In
							 | 
						||
| 
								 | 
							
								    # this case we prepend an underline
							 | 
						||
| 
								 | 
							
								    if os.name == 'nt' and filename and \
							 | 
						||
| 
								 | 
							
								       filename.split('.')[0].upper() in _windows_device_files:
							 | 
						||
| 
								 | 
							
								        filename = '_' + filename
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    return filename
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def escape(s, quote=None):
							 | 
						||
| 
								 | 
							
								    """Replace special characters "&", "<", ">" and (") to HTML-safe sequences.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    There is a special handling for `None` which escapes to an empty string.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    .. versionchanged:: 0.9
							 | 
						||
| 
								 | 
							
								       `quote` is now implicitly on.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    :param s: the string to escape.
							 | 
						||
| 
								 | 
							
								    :param quote: ignored.
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    if s is None:
							 | 
						||
| 
								 | 
							
								        return ''
							 | 
						||
| 
								 | 
							
								    elif hasattr(s, '__html__'):
							 | 
						||
| 
								 | 
							
								        return text_type(s.__html__())
							 | 
						||
| 
								 | 
							
								    elif not isinstance(s, string_types):
							 | 
						||
| 
								 | 
							
								        s = text_type(s)
							 | 
						||
| 
								 | 
							
								    if quote is not None:
							 | 
						||
| 
								 | 
							
								        from warnings import warn
							 | 
						||
| 
								 | 
							
								        warn(DeprecationWarning('quote parameter is implicit now'), stacklevel=2)
							 | 
						||
| 
								 | 
							
								    s = s.replace('&', '&').replace('<', '<') \
							 | 
						||
| 
								 | 
							
								        .replace('>', '>').replace('"', """)
							 | 
						||
| 
								 | 
							
								    return s
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def unescape(s):
							 | 
						||
| 
								 | 
							
								    """The reverse function of `escape`.  This unescapes all the HTML
							 | 
						||
| 
								 | 
							
								    entities, not only the XML entities inserted by `escape`.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    :param s: the string to unescape.
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    def handle_match(m):
							 | 
						||
| 
								 | 
							
								        name = m.group(1)
							 | 
						||
| 
								 | 
							
								        if name in HTMLBuilder._entities:
							 | 
						||
| 
								 | 
							
								            return unichr(HTMLBuilder._entities[name])
							 | 
						||
| 
								 | 
							
								        try:
							 | 
						||
| 
								 | 
							
								            if name[:2] in ('#x', '#X'):
							 | 
						||
| 
								 | 
							
								                return unichr(int(name[2:], 16))
							 | 
						||
| 
								 | 
							
								            elif name.startswith('#'):
							 | 
						||
| 
								 | 
							
								                return unichr(int(name[1:]))
							 | 
						||
| 
								 | 
							
								        except ValueError:
							 | 
						||
| 
								 | 
							
								            pass
							 | 
						||
| 
								 | 
							
								        return u''
							 | 
						||
| 
								 | 
							
								    return _entity_re.sub(handle_match, s)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def redirect(location, code=302, Response=None):
							 | 
						||
| 
								 | 
							
								    """Returns a response object (a WSGI application) that, if called,
							 | 
						||
| 
								 | 
							
								    redirects the client to the target location.  Supported codes are 301,
							 | 
						||
| 
								 | 
							
								    302, 303, 305, and 307.  300 is not supported because it's not a real
							 | 
						||
| 
								 | 
							
								    redirect and 304 because it's the answer for a request with a request
							 | 
						||
| 
								 | 
							
								    with defined If-Modified-Since headers.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    .. versionadded:: 0.6
							 | 
						||
| 
								 | 
							
								       The location can now be a unicode string that is encoded using
							 | 
						||
| 
								 | 
							
								       the :func:`iri_to_uri` function.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    .. versionadded:: 0.10
							 | 
						||
| 
								 | 
							
								        The class used for the Response object can now be passed in.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    :param location: the location the response should redirect to.
							 | 
						||
| 
								 | 
							
								    :param code: the redirect status code. defaults to 302.
							 | 
						||
| 
								 | 
							
								    :param class Response: a Response class to use when instantiating a
							 | 
						||
| 
								 | 
							
								        response. The default is :class:`werkzeug.wrappers.Response` if
							 | 
						||
| 
								 | 
							
								        unspecified.
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    if Response is None:
							 | 
						||
| 
								 | 
							
								        from werkzeug.wrappers import Response
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    display_location = escape(location)
							 | 
						||
| 
								 | 
							
								    if isinstance(location, text_type):
							 | 
						||
| 
								 | 
							
								        # Safe conversion is necessary here as we might redirect
							 | 
						||
| 
								 | 
							
								        # to a broken URI scheme (for instance itms-services).
							 | 
						||
| 
								 | 
							
								        from werkzeug.urls import iri_to_uri
							 | 
						||
| 
								 | 
							
								        location = iri_to_uri(location, safe_conversion=True)
							 | 
						||
| 
								 | 
							
								    response = Response(
							 | 
						||
| 
								 | 
							
								        '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">\n'
							 | 
						||
| 
								 | 
							
								        '<title>Redirecting...</title>\n'
							 | 
						||
| 
								 | 
							
								        '<h1>Redirecting...</h1>\n'
							 | 
						||
| 
								 | 
							
								        '<p>You should be redirected automatically to target URL: '
							 | 
						||
| 
								 | 
							
								        '<a href="%s">%s</a>.  If not click the link.' %
							 | 
						||
| 
								 | 
							
								        (escape(location), display_location), code, mimetype='text/html')
							 | 
						||
| 
								 | 
							
								    response.headers['Location'] = location
							 | 
						||
| 
								 | 
							
								    return response
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def append_slash_redirect(environ, code=301):
							 | 
						||
| 
								 | 
							
								    """Redirects to the same URL but with a slash appended.  The behavior
							 | 
						||
| 
								 | 
							
								    of this function is undefined if the path ends with a slash already.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    :param environ: the WSGI environment for the request that triggers
							 | 
						||
| 
								 | 
							
								                    the redirect.
							 | 
						||
| 
								 | 
							
								    :param code: the status code for the redirect.
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    new_path = environ['PATH_INFO'].strip('/') + '/'
							 | 
						||
| 
								 | 
							
								    query_string = environ.get('QUERY_STRING')
							 | 
						||
| 
								 | 
							
								    if query_string:
							 | 
						||
| 
								 | 
							
								        new_path += '?' + query_string
							 | 
						||
| 
								 | 
							
								    return redirect(new_path, code)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def import_string(import_name, silent=False):
							 | 
						||
| 
								 | 
							
								    """Imports an object based on a string.  This is useful if you want to
							 | 
						||
| 
								 | 
							
								    use import paths as endpoints or something similar.  An import path can
							 | 
						||
| 
								 | 
							
								    be specified either in dotted notation (``xml.sax.saxutils.escape``)
							 | 
						||
| 
								 | 
							
								    or with a colon as object delimiter (``xml.sax.saxutils:escape``).
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    If `silent` is True the return value will be `None` if the import fails.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    :param import_name: the dotted name for the object to import.
							 | 
						||
| 
								 | 
							
								    :param silent: if set to `True` import errors are ignored and
							 | 
						||
| 
								 | 
							
								                   `None` is returned instead.
							 | 
						||
| 
								 | 
							
								    :return: imported object
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    # force the import name to automatically convert to strings
							 | 
						||
| 
								 | 
							
								    # __import__ is not able to handle unicode strings in the fromlist
							 | 
						||
| 
								 | 
							
								    # if the module is a package
							 | 
						||
| 
								 | 
							
								    import_name = str(import_name).replace(':', '.')
							 | 
						||
| 
								 | 
							
								    try:
							 | 
						||
| 
								 | 
							
								        try:
							 | 
						||
| 
								 | 
							
								            __import__(import_name)
							 | 
						||
| 
								 | 
							
								        except ImportError:
							 | 
						||
| 
								 | 
							
								            if '.' not in import_name:
							 | 
						||
| 
								 | 
							
								                raise
							 | 
						||
| 
								 | 
							
								        else:
							 | 
						||
| 
								 | 
							
								            return sys.modules[import_name]
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        module_name, obj_name = import_name.rsplit('.', 1)
							 | 
						||
| 
								 | 
							
								        try:
							 | 
						||
| 
								 | 
							
								            module = __import__(module_name, None, None, [obj_name])
							 | 
						||
| 
								 | 
							
								        except ImportError:
							 | 
						||
| 
								 | 
							
								            # support importing modules not yet set up by the parent module
							 | 
						||
| 
								 | 
							
								            # (or package for that matter)
							 | 
						||
| 
								 | 
							
								            module = import_string(module_name)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        try:
							 | 
						||
| 
								 | 
							
								            return getattr(module, obj_name)
							 | 
						||
| 
								 | 
							
								        except AttributeError as e:
							 | 
						||
| 
								 | 
							
								            raise ImportError(e)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    except ImportError as e:
							 | 
						||
| 
								 | 
							
								        if not silent:
							 | 
						||
| 
								 | 
							
								            reraise(
							 | 
						||
| 
								 | 
							
								                ImportStringError,
							 | 
						||
| 
								 | 
							
								                ImportStringError(import_name, e),
							 | 
						||
| 
								 | 
							
								                sys.exc_info()[2])
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def find_modules(import_path, include_packages=False, recursive=False):
							 | 
						||
| 
								 | 
							
								    """Finds all the modules below a package.  This can be useful to
							 | 
						||
| 
								 | 
							
								    automatically import all views / controllers so that their metaclasses /
							 | 
						||
| 
								 | 
							
								    function decorators have a chance to register themselves on the
							 | 
						||
| 
								 | 
							
								    application.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    Packages are not returned unless `include_packages` is `True`.  This can
							 | 
						||
| 
								 | 
							
								    also recursively list modules but in that case it will import all the
							 | 
						||
| 
								 | 
							
								    packages to get the correct load path of that module.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    :param import_path: the dotted name for the package to find child modules.
							 | 
						||
| 
								 | 
							
								    :param include_packages: set to `True` if packages should be returned, too.
							 | 
						||
| 
								 | 
							
								    :param recursive: set to `True` if recursion should happen.
							 | 
						||
| 
								 | 
							
								    :return: generator
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    module = import_string(import_path)
							 | 
						||
| 
								 | 
							
								    path = getattr(module, '__path__', None)
							 | 
						||
| 
								 | 
							
								    if path is None:
							 | 
						||
| 
								 | 
							
								        raise ValueError('%r is not a package' % import_path)
							 | 
						||
| 
								 | 
							
								    basename = module.__name__ + '.'
							 | 
						||
| 
								 | 
							
								    for importer, modname, ispkg in pkgutil.iter_modules(path):
							 | 
						||
| 
								 | 
							
								        modname = basename + modname
							 | 
						||
| 
								 | 
							
								        if ispkg:
							 | 
						||
| 
								 | 
							
								            if include_packages:
							 | 
						||
| 
								 | 
							
								                yield modname
							 | 
						||
| 
								 | 
							
								            if recursive:
							 | 
						||
| 
								 | 
							
								                for item in find_modules(modname, include_packages, True):
							 | 
						||
| 
								 | 
							
								                    yield item
							 | 
						||
| 
								 | 
							
								        else:
							 | 
						||
| 
								 | 
							
								            yield modname
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def validate_arguments(func, args, kwargs, drop_extra=True):
							 | 
						||
| 
								 | 
							
								    """Checks if the function accepts the arguments and keyword arguments.
							 | 
						||
| 
								 | 
							
								    Returns a new ``(args, kwargs)`` tuple that can safely be passed to
							 | 
						||
| 
								 | 
							
								    the function without causing a `TypeError` because the function signature
							 | 
						||
| 
								 | 
							
								    is incompatible.  If `drop_extra` is set to `True` (which is the default)
							 | 
						||
| 
								 | 
							
								    any extra positional or keyword arguments are dropped automatically.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    The exception raised provides three attributes:
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    `missing`
							 | 
						||
| 
								 | 
							
								        A set of argument names that the function expected but where
							 | 
						||
| 
								 | 
							
								        missing.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    `extra`
							 | 
						||
| 
								 | 
							
								        A dict of keyword arguments that the function can not handle but
							 | 
						||
| 
								 | 
							
								        where provided.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    `extra_positional`
							 | 
						||
| 
								 | 
							
								        A list of values that where given by positional argument but the
							 | 
						||
| 
								 | 
							
								        function cannot accept.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    This can be useful for decorators that forward user submitted data to
							 | 
						||
| 
								 | 
							
								    a view function::
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        from werkzeug.utils import ArgumentValidationError, validate_arguments
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        def sanitize(f):
							 | 
						||
| 
								 | 
							
								            def proxy(request):
							 | 
						||
| 
								 | 
							
								                data = request.values.to_dict()
							 | 
						||
| 
								 | 
							
								                try:
							 | 
						||
| 
								 | 
							
								                    args, kwargs = validate_arguments(f, (request,), data)
							 | 
						||
| 
								 | 
							
								                except ArgumentValidationError:
							 | 
						||
| 
								 | 
							
								                    raise BadRequest('The browser failed to transmit all '
							 | 
						||
| 
								 | 
							
								                                     'the data expected.')
							 | 
						||
| 
								 | 
							
								                return f(*args, **kwargs)
							 | 
						||
| 
								 | 
							
								            return proxy
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    :param func: the function the validation is performed against.
							 | 
						||
| 
								 | 
							
								    :param args: a tuple of positional arguments.
							 | 
						||
| 
								 | 
							
								    :param kwargs: a dict of keyword arguments.
							 | 
						||
| 
								 | 
							
								    :param drop_extra: set to `False` if you don't want extra arguments
							 | 
						||
| 
								 | 
							
								                       to be silently dropped.
							 | 
						||
| 
								 | 
							
								    :return: tuple in the form ``(args, kwargs)``.
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    parser = _parse_signature(func)
							 | 
						||
| 
								 | 
							
								    args, kwargs, missing, extra, extra_positional = parser(args, kwargs)[:5]
							 | 
						||
| 
								 | 
							
								    if missing:
							 | 
						||
| 
								 | 
							
								        raise ArgumentValidationError(tuple(missing))
							 | 
						||
| 
								 | 
							
								    elif (extra or extra_positional) and not drop_extra:
							 | 
						||
| 
								 | 
							
								        raise ArgumentValidationError(None, extra, extra_positional)
							 | 
						||
| 
								 | 
							
								    return tuple(args), kwargs
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								def bind_arguments(func, args, kwargs):
							 | 
						||
| 
								 | 
							
								    """Bind the arguments provided into a dict.  When passed a function,
							 | 
						||
| 
								 | 
							
								    a tuple of arguments and a dict of keyword arguments `bind_arguments`
							 | 
						||
| 
								 | 
							
								    returns a dict of names as the function would see it.  This can be useful
							 | 
						||
| 
								 | 
							
								    to implement a cache decorator that uses the function arguments to build
							 | 
						||
| 
								 | 
							
								    the cache key based on the values of the arguments.
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    :param func: the function the arguments should be bound for.
							 | 
						||
| 
								 | 
							
								    :param args: tuple of positional arguments.
							 | 
						||
| 
								 | 
							
								    :param kwargs: a dict of keyword arguments.
							 | 
						||
| 
								 | 
							
								    :return: a :class:`dict` of bound keyword arguments.
							 | 
						||
| 
								 | 
							
								    """
							 | 
						||
| 
								 | 
							
								    args, kwargs, missing, extra, extra_positional, \
							 | 
						||
| 
								 | 
							
								        arg_spec, vararg_var, kwarg_var = _parse_signature(func)(args, kwargs)
							 | 
						||
| 
								 | 
							
								    values = {}
							 | 
						||
| 
								 | 
							
								    for (name, has_default, default), value in zip(arg_spec, args):
							 | 
						||
| 
								 | 
							
								        values[name] = value
							 | 
						||
| 
								 | 
							
								    if vararg_var is not None:
							 | 
						||
| 
								 | 
							
								        values[vararg_var] = tuple(extra_positional)
							 | 
						||
| 
								 | 
							
								    elif extra_positional:
							 | 
						||
| 
								 | 
							
								        raise TypeError('too many positional arguments')
							 | 
						||
| 
								 | 
							
								    if kwarg_var is not None:
							 | 
						||
| 
								 | 
							
								        multikw = set(extra) & set([x[0] for x in arg_spec])
							 | 
						||
| 
								 | 
							
								        if multikw:
							 | 
						||
| 
								 | 
							
								            raise TypeError('got multiple values for keyword argument ' +
							 | 
						||
| 
								 | 
							
								                            repr(next(iter(multikw))))
							 | 
						||
| 
								 | 
							
								        values[kwarg_var] = extra
							 | 
						||
| 
								 | 
							
								    elif extra:
							 | 
						||
| 
								 | 
							
								        raise TypeError('got unexpected keyword argument ' +
							 | 
						||
| 
								 | 
							
								                        repr(next(iter(extra))))
							 | 
						||
| 
								 | 
							
								    return values
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class ArgumentValidationError(ValueError):
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    """Raised if :func:`validate_arguments` fails to validate"""
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def __init__(self, missing=None, extra=None, extra_positional=None):
							 | 
						||
| 
								 | 
							
								        self.missing = set(missing or ())
							 | 
						||
| 
								 | 
							
								        self.extra = extra or {}
							 | 
						||
| 
								 | 
							
								        self.extra_positional = extra_positional or []
							 | 
						||
| 
								 | 
							
								        ValueError.__init__(self, 'function arguments invalid.  ('
							 | 
						||
| 
								 | 
							
								                            '%d missing, %d additional)' % (
							 | 
						||
| 
								 | 
							
								                                len(self.missing),
							 | 
						||
| 
								 | 
							
								                                len(self.extra) + len(self.extra_positional)
							 | 
						||
| 
								 | 
							
								                            ))
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								class ImportStringError(ImportError):
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    """Provides information about a failed :func:`import_string` attempt."""
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    #: String in dotted notation that failed to be imported.
							 | 
						||
| 
								 | 
							
								    import_name = None
							 | 
						||
| 
								 | 
							
								    #: Wrapped exception.
							 | 
						||
| 
								 | 
							
								    exception = None
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def __init__(self, import_name, exception):
							 | 
						||
| 
								 | 
							
								        self.import_name = import_name
							 | 
						||
| 
								 | 
							
								        self.exception = exception
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        msg = (
							 | 
						||
| 
								 | 
							
								            'import_string() failed for %r. Possible reasons are:\n\n'
							 | 
						||
| 
								 | 
							
								            '- missing __init__.py in a package;\n'
							 | 
						||
| 
								 | 
							
								            '- package or module path not included in sys.path;\n'
							 | 
						||
| 
								 | 
							
								            '- duplicated package or module name taking precedence in '
							 | 
						||
| 
								 | 
							
								            'sys.path;\n'
							 | 
						||
| 
								 | 
							
								            '- missing module, class, function or variable;\n\n'
							 | 
						||
| 
								 | 
							
								            'Debugged import:\n\n%s\n\n'
							 | 
						||
| 
								 | 
							
								            'Original exception:\n\n%s: %s')
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        name = ''
							 | 
						||
| 
								 | 
							
								        tracked = []
							 | 
						||
| 
								 | 
							
								        for part in import_name.replace(':', '.').split('.'):
							 | 
						||
| 
								 | 
							
								            name += (name and '.') + part
							 | 
						||
| 
								 | 
							
								            imported = import_string(name, silent=True)
							 | 
						||
| 
								 | 
							
								            if imported:
							 | 
						||
| 
								 | 
							
								                tracked.append((name, getattr(imported, '__file__', None)))
							 | 
						||
| 
								 | 
							
								            else:
							 | 
						||
| 
								 | 
							
								                track = ['- %r found in %r.' % (n, i) for n, i in tracked]
							 | 
						||
| 
								 | 
							
								                track.append('- %r not found.' % name)
							 | 
						||
| 
								 | 
							
								                msg = msg % (import_name, '\n'.join(track),
							 | 
						||
| 
								 | 
							
								                             exception.__class__.__name__, str(exception))
							 | 
						||
| 
								 | 
							
								                break
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								        ImportError.__init__(self, msg)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								    def __repr__(self):
							 | 
						||
| 
								 | 
							
								        return '<%s(%r, %r)>' % (self.__class__.__name__, self.import_name,
							 | 
						||
| 
								 | 
							
								                                 self.exception)
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								
							 | 
						||
| 
								 | 
							
								# DEPRECATED
							 | 
						||
| 
								 | 
							
								# these objects were previously in this module as well.  we import
							 | 
						||
| 
								 | 
							
								# them here for backwards compatibility with old pickles.
							 | 
						||
| 
								 | 
							
								from werkzeug.datastructures import (  # noqa
							 | 
						||
| 
								 | 
							
								    MultiDict, CombinedMultiDict, Headers, EnvironHeaders)
							 | 
						||
| 
								 | 
							
								from werkzeug.http import parse_cookie, dump_cookie  # noqa
							 |