1
# -*- coding: utf-8 -*-
6
This module implements various utilities for WSGI applications. Most of
7
them are used by the request and response wrappers but especially for
8
middleware development it makes sense to use them without the wrappers.
10
:copyright: (c) 2009 by the Werkzeug Team, see AUTHORS for more details.
11
:license: BSD, see LICENSE for more details.
20
from zlib import adler32
21
from time import time, mktime
22
from datetime import datetime, timedelta
24
from werkzeug._internal import _patch_wrapper, _decode_unicode, \
25
_empty_stream, _iter_modules, _ExtendedCookie, _ExtendedMorsel, \
26
_DictAccessorProperty, _dump_date, _parse_signature, _missing
29
_format_re = re.compile(r'\$(?:(%s)|\{(%s)\})' % (('[a-zA-Z_][a-zA-Z0-9_]*',) * 2))
30
_entity_re = re.compile(r'&([^;]+);')
31
_filename_ascii_strip_re = re.compile(r'[^A-Za-z0-9_.-]')
32
_windows_device_files = ('CON', 'AUX', 'COM1', 'COM2', 'COM3', 'COM4', 'LPT1',
33
'LPT2', 'LPT3', 'PRN', 'NUL')
36
class FileStorage(object):
37
"""The :class:`FileStorage` class is a thin wrapper over incoming files.
38
It is used by the request object to represent uploaded files. All the
39
attributes of the wrapper stream are proxied by the file storage so
40
it's possible to do ``storage.read()`` instead of the long form
41
``storage.stream.read()``.
44
def __init__(self, stream=None, filename=None, name=None,
45
content_type='application/octet-stream', content_length=-1):
47
self.stream = stream or _empty_stream
48
self.filename = filename or getattr(stream, 'name', None)
49
self.content_type = content_type
50
self.content_length = content_length
52
def save(self, dst, buffer_size=16384):
53
"""Save the file to a destination path or file object. If the
54
destination is a file object you have to close it yourself after the
55
call. The buffer size is the number of bytes held in memory during
56
the copy process. It defaults to 16KB.
58
For secure file saving also have a look at :func:`secure_filename`.
60
:param dst: a filename or open file object the uploaded file
62
:param buffer_size: the size of the buffer. This works the same as
63
the `length` parameter of
64
:func:`shutil.copyfileobj`.
66
from shutil import copyfileobj
68
if isinstance(dst, basestring):
72
copyfileobj(self.stream, dst, buffer_size)
78
"""Close the underlaying file if possible."""
84
def __nonzero__(self):
85
return bool(self.filename)
87
def __getattr__(self, name):
88
return getattr(self.stream, name)
91
return iter(self.readline, '')
94
return '<%s: %r (%r)>' % (
95
self.__class__.__name__,
101
class SharedDataMiddleware(object):
102
"""A WSGI middleware that provides static content for development
103
environments or simple server setups. Usage is quite simple::
106
from werkzeug import SharedDataMiddleware
108
app = SharedDataMiddleware(app, {
109
'/shared': os.path.join(os.path.dirname(__file__), 'shared')
112
The contents of the folder ``./shared`` will now be available on
113
``http://example.com/shared/``. This is pretty useful during development
114
because a standalone media server is not required. One can also mount
115
files on the root folder and still continue to use the application because
116
the shared data middleware forwards all unhandled requests to the
117
application, even if the requests are below one of the shared folders.
119
If `pkg_resources` is available you can also tell the middleware to serve
120
files from package data::
122
app = SharedDataMiddleware(app, {
123
'/shared': ('myapplication', 'shared_files')
126
This will then serve the ``shared_files`` folder in the `myapplication`
129
The optional `disallow` parameter can be a list of :func:`~fnmatch.fnmatch`
130
rules for files that are not accessible from the web. If `cache` is set to
131
`False` no caching headers are sent.
133
Currently the middleware does not support non ASCII filenames. If the
134
encoding on the file system happens to be the encoding of the URI it may
135
work but this could also be by accident. We strongly suggest using ASCII
136
only file names for static files.
138
.. versionchanged:: 0.5
139
The cache timeout is configurable now.
141
:param app: the application to wrap. If you don't want to wrap an
142
application you can pass it :exc:`NotFound`.
143
:param exports: a dict of exported files and folders.
144
:param diallow: a list of :func:`~fnmatch.fnmatch` rules.
145
:param cache: enable or disable caching headers.
146
:Param cache_timeout: the cache timeout in seconds for the headers.
149
def __init__(self, app, exports, disallow=None, cache=True,
150
cache_timeout=60 * 60 * 12):
154
self.cache_timeout = cache_timeout
155
for key, value in exports.iteritems():
156
if isinstance(value, tuple):
157
loader = self.get_package_loader(*value)
158
elif isinstance(value, basestring):
159
if os.path.isfile(value):
160
loader = self.get_file_loader(value)
162
loader = self.get_directory_loader(value)
164
raise TypeError('unknown def %r' % value)
165
self.exports[key] = loader
166
if disallow is not None:
167
from fnmatch import fnmatch
168
self.is_allowed = lambda x: not fnmatch(x, disallow)
170
def is_allowed(self, filename):
171
"""Subclasses can override this method to disallow the access to
172
certain files. However by providing `disallow` in the constructor
173
this method is overwritten.
177
def _opener(self, filename):
179
open(filename, 'rb'),
180
datetime.utcfromtimestamp(os.path.getmtime(filename)),
181
int(os.path.getsize(filename))
184
def get_file_loader(self, filename):
185
return lambda x: (os.path.basename(filename), self._opener(filename))
187
def get_package_loader(self, package, package_path):
188
from pkg_resources import DefaultProvider, ResourceManager, \
190
loadtime = datetime.utcnow()
191
provider = get_provider(package)
192
manager = ResourceManager()
193
filesystem_bound = isinstance(provider, DefaultProvider)
195
path = posixpath.join(package_path, path)
196
if path is None or not provider.has_resource(path):
198
basename = posixpath.basename(path)
200
return basename, self._opener(
201
provider.get_resource_filename(manager, path))
202
return basename, lambda: (
203
provider.get_resource_stream(manager, path),
209
def get_directory_loader(self, directory):
212
path = os.path.join(directory, path)
215
if os.path.isfile(path):
216
return os.path.basename(path), self._opener(path)
220
def generate_etag(self, mtime, file_size, real_filename):
221
return 'wzsdm-%d-%s-%s' % (
222
mktime(mtime.timetuple()),
224
adler32(real_filename) & 0xffffffff
227
def __call__(self, environ, start_response):
228
# sanitize the path for non unix systems
229
cleaned_path = environ.get('PATH_INFO', '').strip('/')
230
for sep in os.sep, os.altsep:
231
if sep and sep != '/':
232
cleaned_path = cleaned_path.replace(sep, '/')
233
path = '/'.join([''] + [x for x in cleaned_path.split('/')
236
for search_path, loader in self.exports.iteritems():
237
if search_path == path:
238
real_filename, file_loader = loader(None)
239
if file_loader is not None:
241
if not search_path.endswith('/'):
243
if path.startswith(search_path):
244
real_filename, file_loader = loader(path[len(search_path):])
245
if file_loader is not None:
247
if file_loader is None or not self.is_allowed(real_filename):
248
return self.app(environ, start_response)
250
guessed_type = mimetypes.guess_type(real_filename)
251
mime_type = guessed_type[0] or 'text/plain'
252
f, mtime, file_size = file_loader()
254
headers = [('Date', http_date())]
256
timeout = self.cache_timeout
257
etag = self.generate_etag(mtime, file_size, real_filename)
259
('Etag', '"%s"' % etag),
260
('Cache-Control', 'max-age=%d, public' % timeout)
262
if not is_resource_modified(environ, etag, last_modified=mtime):
264
start_response('304 Not Modified', headers)
266
headers.append(('Expires', http_date(time() + timeout)))
268
headers.append(('Cache-Control', 'public'))
271
('Content-Type', mime_type),
272
('Content-Length', str(file_size)),
273
('Last-Modified', http_date(mtime))
275
start_response('200 OK', headers)
276
return wrap_file(environ, f)
279
class DispatcherMiddleware(object):
280
"""Allows one to mount middlewares or application in a WSGI application.
281
This is useful if you want to combine multiple WSGI applications::
283
app = DispatcherMiddleware(app, {
289
def __init__(self, app, mounts=None):
291
self.mounts = mounts or {}
293
def __call__(self, environ, start_response):
294
script = environ.get('PATH_INFO', '')
297
if script in self.mounts:
298
app = self.mounts[script]
300
items = script.split('/')
301
script = '/'.join(items[:-1])
302
path_info = '/%s%s' % (items[-1], path_info)
304
app = self.mounts.get(script, self.app)
305
original_script_name = environ.get('SCRIPT_NAME', '')
306
environ['SCRIPT_NAME'] = original_script_name + script
307
environ['PATH_INFO'] = path_info
308
return app(environ, start_response)
311
class ClosingIterator(object):
312
"""The WSGI specification requires that all middlewares and gateways
313
respect the `close` callback of an iterator. Because it is useful to add
314
another close action to a returned iterator and adding a custom iterator
315
is a boring task this class can be used for that::
317
return ClosingIterator(app(environ, start_response), [cleanup_session,
320
If there is just one close function it can be passed instead of the list.
322
A closing iterator is not needed if the application uses response objects
323
and finishes the processing if the response is started::
326
return response(environ, start_response)
332
def __init__(self, iterable, callbacks=None):
333
iterator = iter(iterable)
334
self._next = iterator.next
335
if callbacks is None:
337
elif callable(callbacks):
338
callbacks = [callbacks]
340
callbacks = list(callbacks)
341
iterable_close = getattr(iterator, 'close', None)
343
callbacks.insert(0, iterable_close)
344
self._callbacks = callbacks
353
for callback in self._callbacks:
357
class FileWrapper(object):
358
"""This class can be used to convert a :class:`file`-like object into
359
an iterable. It yields `buffer_size` blocks until the file is fully
362
You should not use this class directly but rather use the
363
:func:`wrap_file` function that uses the WSGI server's file wrapper
364
support if it's available.
366
.. versionadded:: 0.5
368
:param file: a :class:`file`-like object with a :meth:`~file.read` method.
369
:param buffer_size: number of bytes for one iteration.
372
def __init__(self, file, buffer_size=8192):
374
self.buffer_size = buffer_size
377
if hasattr(self.file, 'close'):
384
data = self.file.read(self.buffer_size)
387
raise StopIteration()
391
def make_line_iter(stream, limit=None, buffer_size=10 * 1024):
392
"""Savely iterates line-based over an input stream. If the input stream
393
is not a :class:`LimitedStream` the `limit` parameter is mandatory.
395
This uses the stream's :meth:`~file.read` method internally as opposite
396
to the :meth:`~file.readline` method that is unsafe and can only be used
397
in violation of the WSGI specification. The same problem applies to the
398
`__iter__` function of the input stream which calls :meth:`~file.readline`
401
If you need line-by-line processing it's strongly recommended to iterate
402
over the input stream using this helper function.
404
:param stream: the stream to iterate over.
405
:param limit: the limit in bytes for the stream. (Usually
406
content length. Not necessary if the `stream`
407
is a :class:`LimitedStream`.
408
:param buffer_size: The optional buffer size.
410
if not isinstance(stream, LimitedStream):
412
raise TypeError('stream not limited and no limit provided.')
413
stream = LimitedStream(stream, limit)
419
chunks = stream.read(buffer_size).splitlines(True)
420
first_chunk = buffer and buffer[0] or ''
422
first_chunk += chunks.pop(0)
429
class LimitedStream(object):
430
"""Wraps a stream so that it doesn't read more than n bytes. If the
431
stream is exhausted and the caller tries to get more bytes from it
432
:func:`on_exhausted` is called which by default returns an empty
433
string or raises :exc:`~werkzeug.exceptions.BadRequest` if silent
434
is set to `False`. The return value of that function is forwarded
435
to the reader function. So if it returns an empty string
436
:meth:`read` will return an empty string as well.
438
The limit however must never be higher than what the stream can
439
output. Otherwise :meth:`readlines` will try to read past the
442
The `silent` parameter has no effect if :meth:`is_exhausted` is
443
overriden by a subclass.
445
.. admonition:: Note on WSGI compliance
447
calls to :meth:`readline` and :meth:`readlines` are not
448
WSGI compliant because it passes a size argument to the
449
readline methods. Unfortunately the WSGI PEP is not safely
450
implementable without a size argument to :meth:`readline`
451
because there is no EOF marker in the stream. As a result
452
of that the use of :meth:`readline` is discouraged.
454
For the same reason iterating over the :class:`LimitedStream`
455
is not portable. It internally calls :meth:`readline`.
457
We strongly suggest using :meth:`read` only or using the
458
:func:`make_line_iter` which savely iterates line-based
459
over a WSGI input stream.
461
:param stream: the stream to wrap.
462
:param limit: the limit for the stream, must not be longer than
463
what the string can provide if the stream does not
464
end with `EOF` (like `wsgi.input`)
465
:param silent: If set to `True` the stream will allow reading
466
past the limit and will return an empty string.
469
def __init__(self, stream, limit, silent=True):
470
self._stream = stream
479
def is_exhausted(self):
480
"""If the stream is exhausted this attribute is `True`."""
481
return self._pos >= self.limit
483
def on_exhausted(self):
484
"""This is called when the stream tries to read past the limit.
485
The return value of this function is returned from the reading
488
Per default this raises a :exc:`~werkzeug.exceptions.BadRequest`.
492
raise BadRequest('input stream exhausted')
494
def exhaust(self, chunk_size=1024 * 16):
495
"""Exhaust the stream. This consumes all the data left until the
498
:param chunk_size: the size for a chunk. It will read the chunk
499
until the stream is exhausted and throw away
502
to_read = self.limit - self._pos
505
chunk = min(to_read, chunk)
509
def read(self, size=None):
510
"""Read `size` bytes or if size is not provided everything is read.
512
:param size: the number of bytes read.
514
if self._pos >= self.limit:
515
return self.on_exhausted()
518
read = self._stream.read(min(self.limit - self._pos, size))
519
self._pos += len(read)
522
def readline(self, size=None):
523
"""Reads one line from the stream."""
524
if self._pos >= self.limit:
525
return self.on_exhausted()
527
size = self.limit - self._pos
529
size = min(size, self.limit - self._pos)
530
line = self._stream.readline(size)
531
self._pos += len(line)
534
def readlines(self, size=None):
535
"""Reads a file into a list of strings. It calls :meth:`readline`
536
until the file is read to the end. It does support the optional
537
`size` argument if the underlaying stream supports it for
543
end = min(self.limit, last_pos + size)
548
size -= last_pos - self._pos
551
result.append(self.readline(size))
557
line = self.readline()
559
raise StopIteration()
564
"""Implements a callable that constructs URLs with the given base. The
565
function can be called with any number of positional and keyword
566
arguments which than are used to assemble the URL. Works with URLs
569
Positional arguments are appended as individual segments to
572
>>> href = Href('/foo')
575
>>> href('foo', bar=23)
578
If any of the arguments (positional or keyword) evaluates to `None` it
579
will be skipped. If no keyword arguments are given the last argument
580
can be a :class:`dict` or :class:`MultiDict` (or any other dict subclass),
581
otherwise the keyword arguments are used for the query parameters, cutting
582
off the first trailing underscore of the parameter name:
586
>>> href({'foo': 'bar'})
589
Combining of both methods is not allowed:
591
>>> href({'foo': 'bar'}, bar=42)
592
Traceback (most recent call last):
594
TypeError: keyword arguments and query-dicts can't be combined
596
Accessing attributes on the href object creates a new href object with
597
the attribute name as prefix:
599
>>> bar_href = href.bar
603
If `sort` is set to `True` the items are sorted by `key` or the default
606
>>> href = Href("/", sort=True)
607
>>> href(a=1, b=2, c=3)
610
.. versionadded:: 0.5
611
`sort` and `key` were added.
614
def __init__(self, base='./', charset='utf-8', sort=False, key=None):
618
self.charset = charset
622
def __getattr__(self, name):
624
raise AttributeError(name)
628
return Href(urlparse.urljoin(base, name), self.charset, self.sort,
631
def __call__(self, *path, **query):
632
if path and isinstance(path[-1], dict):
634
raise TypeError('keyword arguments and query-dicts '
635
'can\'t be combined')
636
query, path = path[-1], path[:-1]
638
query = dict([(k.endswith('_') and k[:-1] or k, v)
639
for k, v in query.items()])
640
path = '/'.join([url_quote(x, self.charset) for x in path
641
if x is not None]).lstrip('/')
644
if not rv.endswith('/'):
646
rv = urlparse.urljoin(rv, path)
648
rv += '?' + url_encode(query, self.charset, sort=self.sort,
653
class cached_property(object):
654
"""A decorator that converts a function into a lazy property. The
655
function wrapped is called the first time to retrieve the result
656
and than that calculated result is used the next time you access
663
# calculate something important here
666
.. versionchanged:: 0.5
667
cached properties are now optionally writeable.
670
def __init__(self, func, name=None, doc=None, writeable=False):
672
self.writeable = writeable
673
self.__name__ = name or func.__name__
674
self.__doc__ = doc or func.__doc__
676
def __get__(self, obj, type=None):
679
value = obj.__dict__.get(self.__name__, _missing)
680
if value is _missing:
681
value = self.func(obj)
682
obj.__dict__[self.__name__] = value
685
def __set__(self, obj, value):
686
if not self.writeable:
687
raise TypeError('read only attribute')
688
obj.__dict__[self.__name__] = value
691
class environ_property(_DictAccessorProperty):
692
"""Maps request attributes to environment variables. This works not only
693
for the Werzeug request object, but also any other class with an
696
>>> class Test(object):
697
... environ = {'key': 'value'}
698
... test = environ_property('key')
703
If you pass it a second value it's used as default if the key does not
704
exist, the third one can be a converter that takes a value and converts
705
it. If it raises :exc:`ValueError` or :exc:`TypeError` the default value
706
is used. If no default value is provided `None` is used.
708
Per default the property is read only. You have to explicitly enable it
709
by passing ``read_only=False`` to the constructor.
714
def lookup(self, obj):
718
class header_property(_DictAccessorProperty):
719
"""Like `environ_property` but for headers."""
721
def lookup(self, obj):
725
class HTMLBuilder(object):
726
"""Helper object for HTML generation.
728
Per default there are two instances of that class. The `html` one, and
729
the `xhtml` one for those two dialects. The class uses keyword parameters
730
and positional parameters to generate small snippets of HTML.
732
Keyword parameters are converted to XML/SGML attributes, positional
733
arguments are used as children. Because Python accepts positional
734
arguments before keyword arguments it's a good idea to use a list with the
735
star-syntax for some children:
737
>>> html.p(class_='foo', *[html.a('foo', href='foo.html'), ' ',
738
... html.a('bar', href='bar.html')])
739
u'<p class="foo"><a href="foo.html">foo</a> <a href="bar.html">bar</a></p>'
741
This class works around some browser limitations and can not be used for
742
arbitrary SGML/XML generation. For that purpose lxml and similar
745
Calling the builder escapes the string passed:
747
>>> html.p(html("<foo>"))
748
u'<p><foo></p>'
751
from htmlentitydefs import name2codepoint
752
_entity_re = re.compile(r'&([^;]+);')
753
_entities = name2codepoint.copy()
754
_entities['apos'] = 39
755
_empty_elements = set([
756
'area', 'base', 'basefont', 'br', 'col', 'frame', 'hr', 'img',
757
'input', 'isindex', 'link', 'meta', 'param'
759
_boolean_attributes = set([
760
'selected', 'checked', 'compact', 'declare', 'defer', 'disabled',
761
'ismap', 'multiple', 'nohref', 'noresize', 'noshade', 'nowrap'
763
_plaintext_elements = set(['textarea'])
764
_c_like_cdata = set(['script', 'style'])
767
def __init__(self, dialect):
768
self._dialect = dialect
770
def __call__(self, s):
773
def __getattr__(self, tag):
775
raise AttributeError(tag)
776
def proxy(*children, **arguments):
778
write = buffer.append
779
for key, value in arguments.iteritems():
782
if key.endswith('_'):
784
if key in self._boolean_attributes:
787
value = self._dialect == 'xhtml' and '="%s"' % key or ''
789
value = '="%s"' % escape(value, True)
790
write(' ' + key + value)
791
if not children and tag in self._empty_elements:
792
write(self._dialect == 'xhtml' and ' />' or '>')
793
return ''.join(buffer)
795
children_as_string = ''.join(unicode(x) for x in children
797
if children_as_string:
798
if tag in self._plaintext_elements:
799
children_as_string = escape(children_as_string)
800
elif tag in self._c_like_cdata and self._dialect == 'xhtml':
801
children_as_string = '/*<![CDATA[*/%s/*]]>*/' % \
803
buffer.extend((children_as_string, '</%s>' % tag))
804
return ''.join(buffer)
808
return '<%s for %r>' % (
809
self.__class__.__name__,
814
html = HTMLBuilder('html')
815
xhtml = HTMLBuilder('xhtml')
818
def parse_form_data(environ, stream_factory=None, charset='utf-8',
819
errors='ignore', max_form_memory_size=None,
820
max_content_length=None, cls=None,
822
"""Parse the form data in the environ and return it as tuple in the form
823
``(stream, form, files)``. You should only call this method if the
824
transport method is `POST` or `PUT`.
826
If the mimetype of the data transmitted is `multipart/form-data` the
827
files multidict will be filled with `FileStorage` objects. If the
828
mimetype is unknown the input stream is wrapped and returned as first
829
argument, else the stream is empty.
831
This function does not raise exceptions, even if the input data is
834
Have a look at :ref:`dealing-with-request-data` for more details.
836
.. versionadded:: 0.5
837
The `max_form_memory_size`, `max_content_length` and
838
`cls` parameters were added.
840
.. versionadded:: 0.5.1
841
The optional `silent` flag was added.
843
:param environ: the WSGI environment to be used for parsing.
844
:param stream_factory: An optional callable that returns a new read and
845
writeable file descriptor. This callable works
846
the same as :meth:`~BaseResponse._get_file_stream`.
847
:param charset: The character set for URL and url encoded form data.
848
:param errors: The encoding error behavior.
849
:param max_form_memory_size: the maximum number of bytes to be accepted for
850
in-memory stored form data. If the data
851
exceeds the value specified an
852
:exc:`~exceptions.RequestURITooLarge`
854
:param max_content_length: If this is provided and the transmitted data
855
is longer than this value an
856
:exc:`~exceptions.RequestEntityTooLarge`
858
:param cls: an optional dict class to use. If this is not specified
859
or `None` the default :class:`MultiDict` is used.
860
:param silent: If set to False parsing errors will not be catched.
861
:return: A tuple in the form ``(stream, form, files)``.
863
content_type, extra = parse_options_header(environ.get('CONTENT_TYPE', ''))
865
content_length = int(environ['CONTENT_LENGTH'])
866
except (KeyError, ValueError):
872
if max_content_length is not None and content_length > max_content_length:
873
raise RequestEntityTooLarge()
875
stream = _empty_stream
878
if content_type == 'multipart/form-data':
880
form, files = parse_multipart(environ['wsgi.input'],
881
extra.get('boundary'),
882
content_length, stream_factory,
884
max_form_memory_size=max_form_memory_size)
885
except ValueError, e:
891
elif content_type == 'application/x-www-form-urlencoded' or \
892
content_type == 'application/x-url-encoded':
893
if max_form_memory_size is not None and \
894
content_length > max_form_memory_size:
895
raise RequestEntityTooLarge()
896
form = url_decode(environ['wsgi.input'].read(content_length),
897
charset, errors=errors, cls=cls)
900
stream = LimitedStream(environ['wsgi.input'], content_length)
902
return stream, form, cls(files)
905
def get_content_type(mimetype, charset):
906
"""Return the full content type string with charset for a mimetype.
908
If the mimetype represents text the charset will be appended as charset
909
parameter, otherwise the mimetype is returned unchanged.
911
:param mimetype: the mimetype to be used as content type.
912
:param charset: the charset to be appended in case it was a text mimetype.
913
:return: the content type.
915
if mimetype.startswith('text/') or \
916
mimetype == 'application/xml' or \
917
(mimetype.startswith('application/') and
918
mimetype.endswith('+xml')):
919
mimetype += '; charset=' + charset
923
def format_string(string, context):
924
"""String-template format a string:
926
>>> format_string('$foo and ${foo}s', dict(foo=42))
929
This does not do any attribute lookup etc. For more advanced string
930
formattings have a look at the `werkzeug.template` module.
932
:param string: the format string.
933
:param context: a dict with the variables to insert.
935
def lookup_arg(match):
936
x = context[match.group(1) or match.group(2)]
937
if not isinstance(x, basestring):
940
return _format_re.sub(lookup_arg, string)
943
def url_decode(s, charset='utf-8', decode_keys=False, include_empty=True,
944
errors='ignore', separator='&', cls=None):
945
"""Parse a querystring and return it as :class:`MultiDict`. Per default
946
only values are decoded into unicode strings. If `decode_keys` is set to
947
`True` the same will happen for keys.
949
Per default a missing value for a key will default to an empty key. If
950
you don't want that behavior you can set `include_empty` to `False`.
952
Per default encoding errors are ignored. If you want a different behavior
953
you can set `errors` to ``'replace'`` or ``'strict'``. In strict mode a
954
`HTTPUnicodeError` is raised.
956
.. versionchanged:: 0.5
957
In previous versions ";" and "&" could be used for url decoding.
958
This changed in 0.5 where only "&" is supported. If you want to
959
use ";" instead a different `separator` can be provided.
961
The `cls` parameter was added.
963
:param s: a string with the query string to decode.
964
:param charset: the charset of the query string.
965
:param decode_keys: set to `True` if you want the keys to be decoded
967
:param include_empty: Set to `False` if you don't want empty values to
969
:param errors: the decoding error behavior.
970
:param separator: the pair separator to be used, defaults to ``&``
971
:param cls: an optional dict class to use. If this is not specified
972
or `None` the default :class:`MultiDict` is used.
977
for pair in str(s).split(separator):
981
key, value = pair.split('=', 1)
985
key = urllib.unquote_plus(key)
987
key = _decode_unicode(key, charset, errors)
988
result.append((key, url_unquote_plus(value, charset, errors)))
992
def url_encode(obj, charset='utf-8', encode_keys=False, sort=False, key=None,
994
"""URL encode a dict/`MultiDict`. If a value is `None` it will not appear
995
in the result string. Per default only values are encoded into the target
996
charset strings. If `encode_keys` is set to ``True`` unicode keys are
999
If `sort` is set to `True` the items are sorted by `key` or the default
1002
.. versionadded:: 0.5
1003
`sort`, `key`, and `separator` were added.
1005
:param obj: the object to encode into a query string.
1006
:param charset: the charset of the query string.
1007
:param encode_keys: set to `True` if you have unicode keys.
1008
:param sort: set to `True` if you want parameters to be sorted by `key`.
1009
:param separator: the separator to be used for the pairs.
1010
:param key: an optional function to be used for sorting. For more details
1011
check out the :func:`sorted` documentation.
1013
if isinstance(obj, MultiDict):
1015
elif isinstance(obj, dict):
1017
for k, v in obj.iteritems():
1018
if not isinstance(v, (tuple, list)):
1020
items.append((k, v))
1026
for key, values in items:
1027
if encode_keys and isinstance(key, unicode):
1028
key = key.encode(charset)
1031
for value in values:
1034
elif isinstance(value, unicode):
1035
value = value.encode(charset)
1038
tmp.append('%s=%s' % (urllib.quote(key),
1039
urllib.quote_plus(value)))
1040
return separator.join(tmp)
1043
def url_quote(s, charset='utf-8', safe='/:'):
1044
"""URL encode a single string with a given encoding.
1046
:param s: the string to quote.
1047
:param charset: the charset to be used.
1048
:param safe: an optional sequence of safe characters.
1050
if isinstance(s, unicode):
1051
s = s.encode(charset)
1052
elif not isinstance(s, str):
1054
return urllib.quote(s, safe=safe)
1057
def url_quote_plus(s, charset='utf-8', safe=''):
1058
"""URL encode a single string with the given encoding and convert
1061
:param s: the string to quote.
1062
:param charset: the charset to be used.
1063
:param safe: an optional sequence of safe characters.
1065
if isinstance(s, unicode):
1066
s = s.encode(charset)
1067
elif not isinstance(s, str):
1069
return urllib.quote_plus(s, safe=safe)
1072
def url_unquote(s, charset='utf-8', errors='ignore'):
1073
"""URL decode a single string with a given decoding.
1075
Per default encoding errors are ignored. If you want a different behavior
1076
you can set `errors` to ``'replace'`` or ``'strict'``. In strict mode a
1077
`HTTPUnicodeError` is raised.
1079
:param s: the string to unquote.
1080
:param charset: the charset to be used.
1081
:param errors: the error handling for the charset decoding.
1083
return _decode_unicode(urllib.unquote(s), charset, errors)
1086
def url_unquote_plus(s, charset='utf-8', errors='ignore'):
1087
"""URL decode a single string with the given decoding and decode
1088
a "+" to whitespace.
1090
Per default encoding errors are ignored. If you want a different behavior
1091
you can set `errors` to ``'replace'`` or ``'strict'``. In strict mode a
1092
`HTTPUnicodeError` is raised.
1094
:param s: the string to unquote.
1095
:param charset: the charset to be used.
1096
:param errors: the error handling for the charset decoding.
1098
return _decode_unicode(urllib.unquote_plus(s), charset, errors)
1101
def url_fix(s, charset='utf-8'):
1102
r"""Sometimes you get an URL by a user that just isn't a real URL because
1103
it contains unsafe characters like ' ' and so on. This function can fix
1104
some of the problems in a similar way browsers handle data entered by the
1107
>>> url_fix(u'http://de.wikipedia.org/wiki/Elf (Begriffskl\xe4rung)')
1108
'http://de.wikipedia.org/wiki/Elf%20%28Begriffskl%C3%A4rung%29'
1110
:param s: the string with the URL to fix.
1111
:param charset: The target charset for the URL if the url was given as
1114
if isinstance(s, unicode):
1115
s = s.encode(charset, 'ignore')
1116
scheme, netloc, path, qs, anchor = urlparse.urlsplit(s)
1117
path = urllib.quote(path, '/%')
1118
qs = urllib.quote_plus(qs, ':&=')
1119
return urlparse.urlunsplit((scheme, netloc, path, qs, anchor))
1122
def secure_filename(filename):
1123
r"""Pass it a filename and it will return a secure version of it. This
1124
filename can then savely be stored on a regular file system and passed
1125
to :func:`os.path.join`. The filename returned is an ASCII only string
1126
for maximum portability.
1128
On windows system the function also makes sure that the file is not
1129
named after one of the special device files.
1131
>>> secure_filename("My cool movie.mov")
1133
>>> secure_filename("../../../etc/passwd")
1135
>>> secure_filename(u'i contain cool \xfcml\xe4uts.txt')
1136
'i_contain_cool_umlauts.txt'
1138
.. versionadded:: 0.5
1140
:param filename: the filename to secure
1142
if isinstance(filename, unicode):
1143
from unicodedata import normalize
1144
filename = normalize('NFKD', filename).encode('ascii', 'ignore')
1145
for sep in os.path.sep, os.path.altsep:
1147
filename = filename.replace(sep, ' ')
1148
filename = str(_filename_ascii_strip_re.sub('', '_'.join(
1149
filename.split()))).strip('._')
1151
# on nt a couple of special files are present in each folder. We
1152
# have to ensure that the target file is not such a filename. In
1153
# this case we prepend an underline
1155
if filename.split('.')[0].upper() in _windows_device_files:
1156
filename = '_' + filename
1161
def escape(s, quote=False):
1162
"""Replace special characters "&", "<" and ">" to HTML-safe sequences. If
1163
the optional flag `quote` is `True`, the quotation mark character (") is
1166
There is a special handling for `None` which escapes to an empty string.
1168
:param s: the string to escape.
1169
:param quote: set to true to also escape double quotes.
1173
elif hasattr(s, '__html__'):
1175
elif not isinstance(s, basestring):
1177
s = s.replace('&', '&').replace('<', '<').replace('>', '>')
1179
s = s.replace('"', """)
1184
"""The reverse function of `escape`. This unescapes all the HTML
1185
entities, not only the XML entities inserted by `escape`.
1187
:param s: the string to unescape.
1189
def handle_match(m):
1191
if name in HTMLBuilder._entities:
1192
return unichr(HTMLBuilder._entities[name])
1194
if name[:2] in ('#x', '#X'):
1195
return unichr(int(name[2:], 16))
1196
elif name.startswith('#'):
1197
return unichr(int(name[1:]))
1201
return _entity_re.sub(handle_match, s)
1204
def get_host(environ):
1205
"""Return the real host for the given WSGI environment. This takes care
1206
of the `X-Forwarded-Host` header.
1208
:param environ: the WSGI environment to get the host of.
1210
if 'HTTP_X_FORWARDED_HOST' in environ:
1211
return environ['HTTP_X_FORWARDED_HOST']
1212
elif 'HTTP_HOST' in environ:
1213
return environ['HTTP_HOST']
1214
result = environ['SERVER_NAME']
1215
if (environ['wsgi.url_scheme'], environ['SERVER_PORT']) not \
1216
in (('https', '443'), ('http', '80')):
1217
result += ':' + environ['SERVER_PORT']
1221
def get_current_url(environ, root_only=False, strip_querystring=False,
1223
"""A handy helper function that recreates the full URL for the current
1224
request or parts of it. Here an example:
1226
>>> env = create_environ("/?param=foo", "http://localhost/script")
1227
>>> get_current_url(env)
1228
'http://localhost/script/?param=foo'
1229
>>> get_current_url(env, root_only=True)
1230
'http://localhost/script/'
1231
>>> get_current_url(env, host_only=True)
1233
>>> get_current_url(env, strip_querystring=True)
1234
'http://localhost/script/'
1236
:param environ: the WSGI environment to get the current URL from.
1237
:param root_only: set `True` if you only want the root URL.
1238
:param strip_querystring: set to `True` if you don't want the querystring.
1239
:param host_only: set to `True` if the host URL should be returned.
1241
tmp = [environ['wsgi.url_scheme'], '://', get_host(environ)]
1244
return ''.join(tmp) + '/'
1245
cat(urllib.quote(environ.get('SCRIPT_NAME', '').rstrip('/')))
1249
cat(urllib.quote('/' + environ.get('PATH_INFO', '').lstrip('/')))
1250
if not strip_querystring:
1251
qs = environ.get('QUERY_STRING')
1257
def pop_path_info(environ):
1258
"""Removes and returns the next segment of `PATH_INFO`, pushing it onto
1259
`SCRIPT_NAME`. Returns `None` if there is nothing left on `PATH_INFO`.
1261
If there are empty segments (``'/foo//bar``) these are ignored but
1262
properly pushed to the `SCRIPT_NAME`:
1264
>>> env = {'SCRIPT_NAME': '/foo', 'PATH_INFO': '/a/b'}
1265
>>> pop_path_info(env)
1267
>>> env['SCRIPT_NAME']
1269
>>> pop_path_info(env)
1271
>>> env['SCRIPT_NAME']
1274
.. versionadded:: 0.5
1276
:param environ: the WSGI environment that is modified.
1278
path = environ.get('PATH_INFO')
1282
script_name = environ.get('SCRIPT_NAME', '')
1284
# shift multiple leading slashes over
1286
path = path.lstrip('/')
1287
if path != old_path:
1288
script_name += '/' * (len(old_path) - len(path))
1291
environ['PATH_INFO'] = ''
1292
environ['SCRIPT_NAME'] = script_name + path
1295
segment, path = path.split('/', 1)
1296
environ['PATH_INFO'] = '/' + path
1297
environ['SCRIPT_NAME'] = script_name + segment
1301
def peek_path_info(environ):
1302
"""Returns the next segment on the `PATH_INFO` or `None` if there
1303
is none. Works like :func:`pop_path_info` without modifying the
1306
>>> env = {'SCRIPT_NAME': '/foo', 'PATH_INFO': '/a/b'}
1307
>>> peek_path_info(env)
1309
>>> peek_path_info(env)
1312
.. versionadded:: 0.5
1314
:param environ: the WSGI environment that is checked.
1316
segments = environ.get('PATH_INFO', '').lstrip('/').split('/', 1)
1321
def cookie_date(expires=None):
1322
"""Formats the time to ensure compatibility with Netscape's cookie
1325
Accepts a floating point number expressed in seconds since the epoc in, a
1326
datetime object or a timetuple. All times in UTC. The :func:`parse_date`
1327
function can be used to parse such a date.
1329
Outputs a string in the format ``Wdy, DD-Mon-YYYY HH:MM:SS GMT``.
1331
:param expires: If provided that date is used, otherwise the current.
1333
return _dump_date(expires, '-')
1336
def parse_cookie(header, charset='utf-8', errors='ignore',
1338
"""Parse a cookie. Either from a string or WSGI environ.
1340
Per default encoding errors are ignored. If you want a different behavior
1341
you can set `errors` to ``'replace'`` or ``'strict'``. In strict mode a
1342
:exc:`HTTPUnicodeError` is raised.
1344
.. versionchanged:: 0.5
1345
This function now returns a :class:`TypeConversionDict` instead of a
1346
regular dict. The `cls` parameter was added.
1348
:param header: the header to be used to parse the cookie. Alternatively
1349
this can be a WSGI environment.
1350
:param charset: the charset for the cookie values.
1351
:param errors: the error behavior for the charset decoding.
1352
:param cls: an optional dict class to use. If this is not specified
1353
or `None` the default :class:`TypeConversionDict` is
1356
if isinstance(header, dict):
1357
header = header.get('HTTP_COOKIE', '')
1359
cls = TypeConversionDict
1360
cookie = _ExtendedCookie()
1364
# decode to unicode and skip broken items. Our extended morsel
1365
# and extended cookie will catch CookieErrors and convert them to
1366
# `None` items which we have to skip here.
1367
for key, value in cookie.iteritems():
1368
if value.value is not None:
1369
result[key] = _decode_unicode(value.value, charset, errors)
1374
def dump_cookie(key, value='', max_age=None, expires=None, path='/',
1375
domain=None, secure=None, httponly=False, charset='utf-8',
1377
"""Creates a new Set-Cookie header without the ``Set-Cookie`` prefix
1378
The parameters are the same as in the cookie Morsel object in the
1379
Python standard library but it accepts unicode data, too.
1381
:param max_age: should be a number of seconds, or `None` (default) if
1382
the cookie should last only as long as the client's
1383
browser session. Additionally `timedelta` objects
1385
:param expires: should be a `datetime` object or unix timestamp.
1386
:param path: limits the cookie to a given path, per default it will
1387
span the whole domain.
1388
:param domain: Use this if you want to set a cross-domain cookie. For
1389
example, ``domain=".example.com"`` will set a cookie
1390
that is readable by the domain ``www.example.com``,
1391
``foo.example.com`` etc. Otherwise, a cookie will only
1392
be readable by the domain that set it.
1393
:param secure: The cookie will only be available via HTTPS
1394
:param httponly: disallow JavaScript to access the cookie. This is an
1395
extension to the cookie standard and probably not
1396
supported by all browsers.
1397
:param charset: the encoding for unicode values.
1398
:param sync_expires: automatically set expires if max_age is defined
1403
except UnicodeError:
1404
raise TypeError('invalid key %r' % key)
1405
if isinstance(value, unicode):
1406
value = value.encode(charset)
1407
morsel = _ExtendedMorsel(key, value)
1408
if isinstance(max_age, timedelta):
1409
max_age = (max_age.days * 60 * 60 * 24) + max_age.seconds
1410
if expires is not None:
1411
if not isinstance(expires, basestring):
1412
expires = cookie_date(expires)
1413
morsel['expires'] = expires
1414
elif max_age is not None and sync_expires:
1415
morsel['expires'] = cookie_date(time() + max_age)
1416
for k, v in (('path', path), ('domain', domain), ('secure', secure),
1417
('max-age', max_age), ('httponly', httponly)):
1418
if v is not None and v is not False:
1420
return morsel.output(header='').lstrip()
1423
def http_date(timestamp=None):
1424
"""Formats the time to match the RFC1123 date format.
1426
Accepts a floating point number expressed in seconds since the epoc in, a
1427
datetime object or a timetuple. All times in UTC. The :func:`parse_date`
1428
function can be used to parse such a date.
1430
Outputs a string in the format ``Wdy, DD Mon YYYY HH:MM:SS GMT``.
1432
:param timestamp: If provided that date is used, otherwise the current.
1434
return _dump_date(timestamp, ' ')
1437
def redirect(location, code=302):
1438
"""Return a response object (a WSGI application) that, if called,
1439
redirects the client to the target location. Supported codes are 301,
1440
302, 303, 305, and 307. 300 is not supported because it's not a real
1441
redirect and 304 because it's the answer for a request with a request
1442
with defined If-Modified-Since headers.
1444
:param location: the location the response should redirect to.
1445
:param code: the redirect status code.
1447
assert code in (301, 302, 303, 305, 307), 'invalid code'
1448
from werkzeug.wrappers import BaseResponse
1449
response = BaseResponse(
1450
'<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">\n'
1451
'<title>Redirecting...</title>\n'
1452
'<h1>Redirecting...</h1>\n'
1453
'<p>You should be redirected automatically to target URL: '
1454
'<a href="%s">%s</a>. If not click the link.' %
1455
((escape(location),) * 2), code, mimetype='text/html')
1456
response.headers['Location'] = location
1460
def append_slash_redirect(environ, code=301):
1461
"""Redirect to the same URL but with a slash appended. The behavior
1462
of this function is undefined if the path ends with a slash already.
1464
:param environ: the WSGI environment for the request that triggers
1466
:param code: the status code for the redirect.
1468
new_path = environ['PATH_INFO'].strip('/') + '/'
1469
query_string = environ['QUERY_STRING']
1471
new_path += '?' + query_string
1472
return redirect(new_path, code)
1476
"""Marks a function as responder. Decorate a function with it and it
1477
will automatically call the return value as WSGI application.
1482
def application(environ, start_response):
1483
return Response('Hello World!')
1485
return _patch_wrapper(f, lambda *a: f(*a)(*a[-2:]))
1488
def wrap_file(environ, file, buffer_size=8192):
1489
"""Wraps a file. This uses the WSGI server's file wrapper if available
1490
or otherwise the generic :class:`FileWrapper`.
1492
.. versionadded:: 0.5
1494
If the file wrapper from the WSGI server is used it's important to not
1495
iterate over it from inside the application but to pass it through
1496
unchanged. If you want to pass out a file wrapper inside a response
1497
object you have to set :attr:`~BaseResponse.direct_passthrough` to `True`.
1499
More information about file wrappers are available in :pep:`333`.
1501
:param file: a :class:`file`-like object with a :meth:`~file.read` method.
1502
:param buffer_size: number of bytes for one iteration.
1504
return environ.get('wsgi.file_wrapper', FileWrapper)(file, buffer_size)
1507
def import_string(import_name, silent=False):
1508
"""Imports an object based on a string. This is useful if you want to
1509
use import paths as endpoints or something similar. An import path can
1510
be specified either in dotted notation (``xml.sax.saxutils.escape``)
1511
or with a colon as object delimiter (``xml.sax.saxutils:escape``).
1513
If `silent` is True the return value will be `None` if the import fails.
1515
:param import_name: the dotted name for the object to import.
1516
:param silent: if set to `True` import errors are ignored and
1517
`None` is returned instead.
1518
:return: imported object
1521
if ':' in import_name:
1522
module, obj = import_name.split(':', 1)
1523
elif '.' in import_name:
1524
module, obj = import_name.rsplit('.', 1)
1526
return __import__(import_name)
1527
return getattr(__import__(module, None, None, [obj]), obj)
1528
except (ImportError, AttributeError):
1533
def find_modules(import_path, include_packages=False, recursive=False):
1534
"""Find all the modules below a package. This can be useful to
1535
automatically import all views / controllers so that their metaclasses /
1536
function decorators have a chance to register themselves on the
1539
Packages are not returned unless `include_packages` is `True`. This can
1540
also recursively list modules but in that case it will import all the
1541
packages to get the correct load path of that module.
1543
:param import_name: the dotted name for the package to find child modules.
1544
:param include_packages: set to `True` if packages should be returned, too.
1545
:param recursive: set to `True` if recursion should happen.
1548
module = import_string(import_path)
1549
path = getattr(module, '__path__', None)
1551
raise ValueError('%r is not a package' % import_path)
1552
basename = module.__name__ + '.'
1553
for modname, ispkg in _iter_modules(path):
1554
modname = basename + modname
1556
if include_packages:
1559
for item in find_modules(modname, include_packages, True):
1565
def validate_arguments(func, args, kwargs, drop_extra=True):
1566
"""Check if the function accepts the arguments and keyword arguments.
1567
Returns a new ``(args, kwargs)`` tuple that can savely be passed to
1568
the function without causing a `TypeError` because the function signature
1569
is incompatible. If `drop_extra` is set to `True` (which is the default)
1570
any extra positional or keyword arguments are dropped automatically.
1572
The exception raised provides three attributes:
1575
A set of argument names that the function expected but where
1579
A dict of keyword arguments that the function can not handle but
1583
A list of values that where given by positional argument but the
1584
function cannot accept.
1586
This can be useful for decorators that forward user submitted data to
1589
from werkzeug import ArgumentValidationError, validate_arguments
1593
data = request.values.to_dict()
1595
args, kwargs = validate_arguments(f, (request,), data)
1596
except ArgumentValidationError:
1597
raise BadRequest('The browser failed to transmit all '
1598
'the data expected.')
1599
return f(*args, **kwargs)
1602
:param func: the function the validation is performed against.
1603
:param args: a tuple of positional arguments.
1604
:param kwargs: a dict of keyword arguments.
1605
:param drop_extra: set to `False` if you don't want extra arguments
1606
to be silently dropped.
1607
:return: tuple in the form ``(args, kwargs)``.
1609
parser = _parse_signature(func)
1610
args, kwargs, missing, extra, extra_positional = parser(args, kwargs)[:5]
1612
raise ArgumentValidationError(tuple(missing))
1613
elif (extra or extra_positional) and not drop_extra:
1614
raise ArgumentValidationError(None, extra, extra_positional)
1615
return tuple(args), kwargs
1618
def bind_arguments(func, args, kwargs):
1619
"""Bind the arguments provided into a dict. When passed a function,
1620
a tuple of arguments and a dict of keyword arguments `bind_arguments`
1621
returns a dict of names as the function would see it. This can be useful
1622
to implement a cache decorator that uses the function arguments to build
1623
the cache key based on the values of the arguments.
1625
:param func: the function the arguments should be bound for.
1626
:param args: tuple of positional arguments.
1627
:param kwargs: a dict of keyword arguments.
1628
:return: a :class:`dict` of bound keyword arguments.
1630
args, kwargs, missing, extra, extra_positional, \
1631
arg_spec, vararg_var, kwarg_var = _parse_signature(func)(args, kwargs)
1633
for (name, has_default, default), value in zip(arg_spec, args):
1634
values[name] = value
1635
if vararg_var is not None:
1636
values[vararg_var] = tuple(extra_positional)
1637
elif extra_positional:
1638
raise TypeError('too many positional arguments')
1639
if kwarg_var is not None:
1640
multikw = set(extra) & set([x[0] for x in arg_spec])
1642
raise TypeError('got multiple values for keyword argument ' +
1643
repr(iter(multikw).next()))
1644
values[kwarg_var] = extra
1646
raise TypeError('got unexpected keyword argument ' +
1647
repr(iter(extra).next()))
1651
class ArgumentValidationError(ValueError):
1652
"""Raised if :func:`validate_arguments` fails to validate"""
1654
def __init__(self, missing=None, extra=None, extra_positional=None):
1655
self.missing = set(missing or ())
1656
self.extra = extra or {}
1657
self.extra_positional = extra_positional or []
1658
ValueError.__init__(self, 'function arguments invalid. ('
1659
'%d missing, %d additional)' % (
1661
len(self.extra) + len(self.extra_positional)
1665
# circular dependency fun
1666
from werkzeug.http import parse_multipart, parse_options_header, \
1667
is_resource_modified
1668
from werkzeug.exceptions import BadRequest, RequestEntityTooLarge
1669
from werkzeug.datastructures import MultiDict, TypeConversionDict
1673
# these objects were previously in this module as well. we import
1674
# them here for backwards compatibility. Will go away in 0.6
1675
from werkzeug.datastructures import MultiDict, CombinedMultiDict, \
1676
Headers, EnvironHeaders
1678
def create_environ(*args, **kwargs):
1679
"""backward compatibility."""
1680
from werkzeug.test import create_environ
1681
return create_environ(*args, **kwargs)
1683
def run_wsgi_app(*args, **kwargs):
1684
"""backwards compatibility."""
1685
from werkzeug.test import run_wsgi_app
1686
return run_wsgi_app(*args, **kwargs)