Back to index

moin  1.9.0~rc2
utils.py
Go to the documentation of this file.
00001 # -*- coding: utf-8 -*-
00002 """
00003     werkzeug.utils
00004     ~~~~~~~~~~~~~~
00005 
00006     This module implements various utilities for WSGI applications.  Most of
00007     them are used by the request and response wrappers but especially for
00008     middleware development it makes sense to use them without the wrappers.
00009 
00010     :copyright: (c) 2009 by the Werkzeug Team, see AUTHORS for more details.
00011     :license: BSD, see LICENSE for more details.
00012 """
00013 import re
00014 import os
00015 import sys
00016 import urllib
00017 import urlparse
00018 import posixpath
00019 import mimetypes
00020 from zlib import adler32
00021 from time import time, mktime
00022 from datetime import datetime, timedelta
00023 
00024 from werkzeug._internal import _patch_wrapper, _decode_unicode, \
00025      _empty_stream, _iter_modules, _ExtendedCookie, _ExtendedMorsel, \
00026      _DictAccessorProperty, _dump_date, _parse_signature, _missing
00027 
00028 
00029 _format_re = re.compile(r'\$(?:(%s)|\{(%s)\})' % (('[a-zA-Z_][a-zA-Z0-9_]*',) * 2))
00030 _entity_re = re.compile(r'&([^;]+);')
00031 _filename_ascii_strip_re = re.compile(r'[^A-Za-z0-9_.-]')
00032 _windows_device_files = ('CON', 'AUX', 'COM1', 'COM2', 'COM3', 'COM4', 'LPT1',
00033                          'LPT2', 'LPT3', 'PRN', 'NUL')
00034 
00035 
00036 class FileStorage(object):
00037     """The :class:`FileStorage` class is a thin wrapper over incoming files.
00038     It is used by the request object to represent uploaded files.  All the
00039     attributes of the wrapper stream are proxied by the file storage so
00040     it's possible to do ``storage.read()`` instead of the long form
00041     ``storage.stream.read()``.
00042     """
00043 
00044     def __init__(self, stream=None, filename=None, name=None,
00045                  content_type='application/octet-stream', content_length=-1):
00046         self.name = name
00047         self.stream = stream or _empty_stream
00048         self.filename = filename or getattr(stream, 'name', None)
00049         self.content_type = content_type
00050         self.content_length = content_length
00051 
00052     def save(self, dst, buffer_size=16384):
00053         """Save the file to a destination path or file object.  If the
00054         destination is a file object you have to close it yourself after the
00055         call.  The buffer size is the number of bytes held in memory during
00056         the copy process.  It defaults to 16KB.
00057 
00058         For secure file saving also have a look at :func:`secure_filename`.
00059 
00060         :param dst: a filename or open file object the uploaded file
00061                     is saved to.
00062         :param buffer_size: the size of the buffer.  This works the same as
00063                             the `length` parameter of
00064                             :func:`shutil.copyfileobj`.
00065         """
00066         from shutil import copyfileobj
00067         close_dst = False
00068         if isinstance(dst, basestring):
00069             dst = file(dst, 'wb')
00070             close_dst = True
00071         try:
00072             copyfileobj(self.stream, dst, buffer_size)
00073         finally:
00074             if close_dst:
00075                 dst.close()
00076 
00077     def close(self):
00078         """Close the underlaying file if possible."""
00079         try:
00080             self.stream.close()
00081         except:
00082             pass
00083 
00084     def __nonzero__(self):
00085         return bool(self.filename)
00086 
00087     def __getattr__(self, name):
00088         return getattr(self.stream, name)
00089 
00090     def __iter__(self):
00091         return iter(self.readline, '')
00092 
00093     def __repr__(self):
00094         return '<%s: %r (%r)>' % (
00095             self.__class__.__name__,
00096             self.filename,
00097             self.content_type
00098         )
00099 
00100 
00101 class SharedDataMiddleware(object):
00102     """A WSGI middleware that provides static content for development
00103     environments or simple server setups. Usage is quite simple::
00104 
00105         import os
00106         from werkzeug import SharedDataMiddleware
00107 
00108         app = SharedDataMiddleware(app, {
00109             '/shared': os.path.join(os.path.dirname(__file__), 'shared')
00110         })
00111 
00112     The contents of the folder ``./shared`` will now be available on
00113     ``http://example.com/shared/``.  This is pretty useful during development
00114     because a standalone media server is not required.  One can also mount
00115     files on the root folder and still continue to use the application because
00116     the shared data middleware forwards all unhandled requests to the
00117     application, even if the requests are below one of the shared folders.
00118 
00119     If `pkg_resources` is available you can also tell the middleware to serve
00120     files from package data::
00121 
00122         app = SharedDataMiddleware(app, {
00123             '/shared': ('myapplication', 'shared_files')
00124         })
00125 
00126     This will then serve the ``shared_files`` folder in the `myapplication`
00127     Python package.
00128 
00129     The optional `disallow` parameter can be a list of :func:`~fnmatch.fnmatch`
00130     rules for files that are not accessible from the web.  If `cache` is set to
00131     `False` no caching headers are sent.
00132 
00133     Currently the middleware does not support non ASCII filenames.  If the
00134     encoding on the file system happens to be the encoding of the URI it may
00135     work but this could also be by accident.  We strongly suggest using ASCII
00136     only file names for static files.
00137 
00138     .. versionchanged:: 0.5
00139        The cache timeout is configurable now.
00140 
00141     :param app: the application to wrap.  If you don't want to wrap an
00142                 application you can pass it :exc:`NotFound`.
00143     :param exports: a dict of exported files and folders.
00144     :param diallow: a list of :func:`~fnmatch.fnmatch` rules.
00145     :param cache: enable or disable caching headers.
00146     :Param cache_timeout: the cache timeout in seconds for the headers.
00147     """
00148 
00149     def __init__(self, app, exports, disallow=None, cache=True,
00150                  cache_timeout=60 * 60 * 12):
00151         self.app = app
00152         self.exports = {}
00153         self.cache = cache
00154         self.cache_timeout = cache_timeout
00155         for key, value in exports.iteritems():
00156             if isinstance(value, tuple):
00157                 loader = self.get_package_loader(*value)
00158             elif isinstance(value, basestring):
00159                 if os.path.isfile(value):
00160                     loader = self.get_file_loader(value)
00161                 else:
00162                     loader = self.get_directory_loader(value)
00163             else:
00164                 raise TypeError('unknown def %r' % value)
00165             self.exports[key] = loader
00166         if disallow is not None:
00167             from fnmatch import fnmatch
00168             self.is_allowed = lambda x: not fnmatch(x, disallow)
00169 
00170     def is_allowed(self, filename):
00171         """Subclasses can override this method to disallow the access to
00172         certain files.  However by providing `disallow` in the constructor
00173         this method is overwritten.
00174         """
00175         return True
00176 
00177     def _opener(self, filename):
00178         return lambda: (
00179             open(filename, 'rb'),
00180             datetime.utcfromtimestamp(os.path.getmtime(filename)),
00181             int(os.path.getsize(filename))
00182         )
00183 
00184     def get_file_loader(self, filename):
00185         return lambda x: (os.path.basename(filename), self._opener(filename))
00186 
00187     def get_package_loader(self, package, package_path):
00188         from pkg_resources import DefaultProvider, ResourceManager, \
00189              get_provider
00190         loadtime = datetime.utcnow()
00191         provider = get_provider(package)
00192         manager = ResourceManager()
00193         filesystem_bound = isinstance(provider, DefaultProvider)
00194         def loader(path):
00195             path = posixpath.join(package_path, path)
00196             if path is None or not provider.has_resource(path):
00197                 return None, None
00198             basename = posixpath.basename(path)
00199             if filesystem_bound:
00200                 return basename, self._opener(
00201                     provider.get_resource_filename(manager, path))
00202             return basename, lambda: (
00203                 provider.get_resource_stream(manager, path),
00204                 loadtime,
00205                 0
00206             )
00207         return loader
00208 
00209     def get_directory_loader(self, directory):
00210         def loader(path):
00211             if path is not None:
00212                 path = os.path.join(directory, path)
00213             else:
00214                 path = directory
00215             if os.path.isfile(path):
00216                 return os.path.basename(path), self._opener(path)
00217             return None, None
00218         return loader
00219 
00220     def generate_etag(self, mtime, file_size, real_filename):
00221         return 'wzsdm-%d-%s-%s' % (
00222             mktime(mtime.timetuple()),
00223             file_size,
00224             adler32(real_filename) & 0xffffffff
00225         )
00226 
00227     def __call__(self, environ, start_response):
00228         # sanitize the path for non unix systems
00229         cleaned_path = environ.get('PATH_INFO', '').strip('/')
00230         for sep in os.sep, os.altsep:
00231             if sep and sep != '/':
00232                 cleaned_path = cleaned_path.replace(sep, '/')
00233         path = '/'.join([''] + [x for x in cleaned_path.split('/')
00234                                 if x and x != '..'])
00235         file_loader = None
00236         for search_path, loader in self.exports.iteritems():
00237             if search_path == path:
00238                 real_filename, file_loader = loader(None)
00239                 if file_loader is not None:
00240                     break
00241             if not search_path.endswith('/'):
00242                 search_path += '/'
00243             if path.startswith(search_path):
00244                 real_filename, file_loader = loader(path[len(search_path):])
00245                 if file_loader is not None:
00246                     break
00247         if file_loader is None or not self.is_allowed(real_filename):
00248             return self.app(environ, start_response)
00249 
00250         guessed_type = mimetypes.guess_type(real_filename)
00251         mime_type = guessed_type[0] or 'text/plain'
00252         f, mtime, file_size = file_loader()
00253 
00254         headers = [('Date', http_date())]
00255         if self.cache:
00256             timeout = self.cache_timeout
00257             etag = self.generate_etag(mtime, file_size, real_filename)
00258             headers += [
00259                 ('Etag', '"%s"' % etag),
00260                 ('Cache-Control', 'max-age=%d, public' % timeout)
00261             ]
00262             if not is_resource_modified(environ, etag, last_modified=mtime):
00263                 f.close()
00264                 start_response('304 Not Modified', headers)
00265                 return []
00266             headers.append(('Expires', http_date(time() + timeout)))
00267         else:
00268             headers.append(('Cache-Control', 'public'))
00269 
00270         headers.extend((
00271             ('Content-Type', mime_type),
00272             ('Content-Length', str(file_size)),
00273             ('Last-Modified', http_date(mtime))
00274         ))
00275         start_response('200 OK', headers)
00276         return wrap_file(environ, f)
00277 
00278 
00279 class DispatcherMiddleware(object):
00280     """Allows one to mount middlewares or application in a WSGI application.
00281     This is useful if you want to combine multiple WSGI applications::
00282 
00283         app = DispatcherMiddleware(app, {
00284             '/app2':        app2,
00285             '/app3':        app3
00286         })
00287     """
00288 
00289     def __init__(self, app, mounts=None):
00290         self.app = app
00291         self.mounts = mounts or {}
00292 
00293     def __call__(self, environ, start_response):
00294         script = environ.get('PATH_INFO', '')
00295         path_info = ''
00296         while '/' in script:
00297             if script in self.mounts:
00298                 app = self.mounts[script]
00299                 break
00300             items = script.split('/')
00301             script = '/'.join(items[:-1])
00302             path_info = '/%s%s' % (items[-1], path_info)
00303         else:
00304             app = self.mounts.get(script, self.app)
00305         original_script_name = environ.get('SCRIPT_NAME', '')
00306         environ['SCRIPT_NAME'] = original_script_name + script
00307         environ['PATH_INFO'] = path_info
00308         return app(environ, start_response)
00309 
00310 
00311 class ClosingIterator(object):
00312     """The WSGI specification requires that all middlewares and gateways
00313     respect the `close` callback of an iterator.  Because it is useful to add
00314     another close action to a returned iterator and adding a custom iterator
00315     is a boring task this class can be used for that::
00316 
00317         return ClosingIterator(app(environ, start_response), [cleanup_session,
00318                                                               cleanup_locals])
00319 
00320     If there is just one close function it can be passed instead of the list.
00321 
00322     A closing iterator is not needed if the application uses response objects
00323     and finishes the processing if the response is started::
00324 
00325         try:
00326             return response(environ, start_response)
00327         finally:
00328             cleanup_session()
00329             cleanup_locals()
00330     """
00331 
00332     def __init__(self, iterable, callbacks=None):
00333         iterator = iter(iterable)
00334         self._next = iterator.next
00335         if callbacks is None:
00336             callbacks = []
00337         elif callable(callbacks):
00338             callbacks = [callbacks]
00339         else:
00340             callbacks = list(callbacks)
00341         iterable_close = getattr(iterator, 'close', None)
00342         if iterable_close:
00343             callbacks.insert(0, iterable_close)
00344         self._callbacks = callbacks
00345 
00346     def __iter__(self):
00347         return self
00348 
00349     def next(self):
00350         return self._next()
00351 
00352     def close(self):
00353         for callback in self._callbacks:
00354             callback()
00355 
00356 
00357 class FileWrapper(object):
00358     """This class can be used to convert a :class:`file`-like object into
00359     an iterable.  It yields `buffer_size` blocks until the file is fully
00360     read.
00361 
00362     You should not use this class directly but rather use the
00363     :func:`wrap_file` function that uses the WSGI server's file wrapper
00364     support if it's available.
00365 
00366     .. versionadded:: 0.5
00367 
00368     :param file: a :class:`file`-like object with a :meth:`~file.read` method.
00369     :param buffer_size: number of bytes for one iteration.
00370     """
00371 
00372     def __init__(self, file, buffer_size=8192):
00373         self.file = file
00374         self.buffer_size = buffer_size
00375 
00376     def close(self):
00377         if hasattr(self.file, 'close'):
00378             self.file.close()
00379 
00380     def __iter__(self):
00381         return self
00382 
00383     def next(self):
00384         data = self.file.read(self.buffer_size)
00385         if data:
00386             return data
00387         raise StopIteration()
00388 
00389 
00390 
00391 def make_line_iter(stream, limit=None, buffer_size=10 * 1024):
00392     """Savely iterates line-based over an input stream.  If the input stream
00393     is not a :class:`LimitedStream` the `limit` parameter is mandatory.
00394 
00395     This uses the stream's :meth:`~file.read` method internally as opposite
00396     to the :meth:`~file.readline` method that is unsafe and can only be used
00397     in violation of the WSGI specification.  The same problem applies to the
00398     `__iter__` function of the input stream which calls :meth:`~file.readline`
00399     without arguments.
00400 
00401     If you need line-by-line processing it's strongly recommended to iterate
00402     over the input stream using this helper function.
00403 
00404     :param stream: the stream to iterate over.
00405     :param limit: the limit in bytes for the stream.  (Usually
00406                   content length.  Not necessary if the `stream`
00407                   is a :class:`LimitedStream`.
00408     :param buffer_size: The optional buffer size.
00409     """
00410     if not isinstance(stream, LimitedStream):
00411         if limit is None:
00412             raise TypeError('stream not limited and no limit provided.')
00413         stream = LimitedStream(stream, limit)
00414     buffer = []
00415     while 1:
00416         if len(buffer) > 1:
00417             yield buffer.pop(0)
00418             continue
00419         chunks = stream.read(buffer_size).splitlines(True)
00420         first_chunk = buffer and buffer[0] or ''
00421         if chunks:
00422             first_chunk += chunks.pop(0)
00423         buffer = chunks
00424         if not first_chunk:
00425             return
00426         yield first_chunk
00427 
00428 
00429 class LimitedStream(object):
00430     """Wraps a stream so that it doesn't read more than n bytes.  If the
00431     stream is exhausted and the caller tries to get more bytes from it
00432     :func:`on_exhausted` is called which by default returns an empty
00433     string or raises :exc:`~werkzeug.exceptions.BadRequest` if silent
00434     is set to `False`.  The return value of that function is forwarded
00435     to the reader function.  So if it returns an empty string
00436     :meth:`read` will return an empty string as well.
00437 
00438     The limit however must never be higher than what the stream can
00439     output.  Otherwise :meth:`readlines` will try to read past the
00440     limit.
00441 
00442     The `silent` parameter has no effect if :meth:`is_exhausted` is
00443     overriden by a subclass.
00444 
00445     .. admonition:: Note on WSGI compliance
00446 
00447        calls to :meth:`readline` and :meth:`readlines` are not
00448        WSGI compliant because it passes a size argument to the
00449        readline methods.  Unfortunately the WSGI PEP is not safely
00450        implementable without a size argument to :meth:`readline`
00451        because there is no EOF marker in the stream.  As a result
00452        of that the use of :meth:`readline` is discouraged.
00453 
00454        For the same reason iterating over the :class:`LimitedStream`
00455        is not portable.  It internally calls :meth:`readline`.
00456 
00457        We strongly suggest using :meth:`read` only or using the
00458        :func:`make_line_iter` which savely iterates line-based
00459        over a WSGI input stream.
00460 
00461     :param stream: the stream to wrap.
00462     :param limit: the limit for the stream, must not be longer than
00463                   what the string can provide if the stream does not
00464                   end with `EOF` (like `wsgi.input`)
00465     :param silent: If set to `True` the stream will allow reading
00466                    past the limit and will return an empty string.
00467     """
00468 
00469     def __init__(self, stream, limit, silent=True):
00470         self._stream = stream
00471         self._pos = 0
00472         self.limit = limit
00473         self.silent = silent
00474 
00475     def __iter__(self):
00476         return self
00477 
00478     @property
00479     def is_exhausted(self):
00480         """If the stream is exhausted this attribute is `True`."""
00481         return self._pos >= self.limit
00482 
00483     def on_exhausted(self):
00484         """This is called when the stream tries to read past the limit.
00485         The return value of this function is returned from the reading
00486         function.
00487 
00488         Per default this raises a :exc:`~werkzeug.exceptions.BadRequest`.
00489         """
00490         if self.silent:
00491             return ''
00492         raise BadRequest('input stream exhausted')
00493 
00494     def exhaust(self, chunk_size=1024 * 16):
00495         """Exhaust the stream.  This consumes all the data left until the
00496         limit is reached.
00497 
00498         :param chunk_size: the size for a chunk.  It will read the chunk
00499                            until the stream is exhausted and throw away
00500                            the results.
00501         """
00502         to_read = self.limit - self._pos
00503         chunk = chunk_size
00504         while to_read > 0:
00505             chunk = min(to_read, chunk)
00506             self.read(chunk)
00507             to_read -= chunk
00508 
00509     def read(self, size=None):
00510         """Read `size` bytes or if size is not provided everything is read.
00511 
00512         :param size: the number of bytes read.
00513         """
00514         if self._pos >= self.limit:
00515             return self.on_exhausted()
00516         if size is None:
00517             size = self.limit
00518         read = self._stream.read(min(self.limit - self._pos, size))
00519         self._pos += len(read)
00520         return read
00521 
00522     def readline(self, size=None):
00523         """Reads one line from the stream."""
00524         if self._pos >= self.limit:
00525             return self.on_exhausted()
00526         if size is None:
00527             size = self.limit - self._pos
00528         else:
00529             size = min(size, self.limit - self._pos)
00530         line = self._stream.readline(size)
00531         self._pos += len(line)
00532         return line
00533 
00534     def readlines(self, size=None):
00535         """Reads a file into a list of strings.  It calls :meth:`readline`
00536         until the file is read to the end.  It does support the optional
00537         `size` argument if the underlaying stream supports it for
00538         `readline`.
00539         """
00540         last_pos = self._pos
00541         result = []
00542         if size is not None:
00543             end = min(self.limit, last_pos + size)
00544         else:
00545             end = self.limit
00546         while 1:
00547             if size is not None:
00548                 size -= last_pos - self._pos
00549             if self._pos >= end:
00550                 break
00551             result.append(self.readline(size))
00552             if size is not None:
00553                 last_pos = self._pos
00554         return result
00555 
00556     def next(self):
00557         line = self.readline()
00558         if line is None:
00559             raise StopIteration()
00560         return line
00561 
00562 
00563 class Href(object):
00564     """Implements a callable that constructs URLs with the given base. The
00565     function can be called with any number of positional and keyword
00566     arguments which than are used to assemble the URL.  Works with URLs
00567     and posix paths.
00568 
00569     Positional arguments are appended as individual segments to
00570     the path of the URL:
00571 
00572     >>> href = Href('/foo')
00573     >>> href('bar', 23)
00574     '/foo/bar/23'
00575     >>> href('foo', bar=23)
00576     '/foo/foo?bar=23'
00577 
00578     If any of the arguments (positional or keyword) evaluates to `None` it
00579     will be skipped.  If no keyword arguments are given the last argument
00580     can be a :class:`dict` or :class:`MultiDict` (or any other dict subclass),
00581     otherwise the keyword arguments are used for the query parameters, cutting
00582     off the first trailing underscore of the parameter name:
00583 
00584     >>> href(is_=42)
00585     '/foo?is=42'
00586     >>> href({'foo': 'bar'})
00587     '/foo?foo=bar'
00588 
00589     Combining of both methods is not allowed:
00590 
00591     >>> href({'foo': 'bar'}, bar=42)
00592     Traceback (most recent call last):
00593       ...
00594     TypeError: keyword arguments and query-dicts can't be combined
00595 
00596     Accessing attributes on the href object creates a new href object with
00597     the attribute name as prefix:
00598 
00599     >>> bar_href = href.bar
00600     >>> bar_href("blub")
00601     '/foo/bar/blub'
00602 
00603     If `sort` is set to `True` the items are sorted by `key` or the default
00604     sorting algorithm:
00605 
00606     >>> href = Href("/", sort=True)
00607     >>> href(a=1, b=2, c=3)
00608     '/?a=1&b=2&c=3'
00609 
00610     .. versionadded:: 0.5
00611         `sort` and `key` were added.
00612     """
00613 
00614     def __init__(self, base='./', charset='utf-8', sort=False, key=None):
00615         if not base:
00616             base = './'
00617         self.base = base
00618         self.charset = charset
00619         self.sort = sort
00620         self.key = key
00621 
00622     def __getattr__(self, name):
00623         if name[:2] == '__':
00624             raise AttributeError(name)
00625         base = self.base
00626         if base[-1:] != '/':
00627             base += '/'
00628         return Href(urlparse.urljoin(base, name), self.charset, self.sort,
00629                     self.key)
00630 
00631     def __call__(self, *path, **query):
00632         if path and isinstance(path[-1], dict):
00633             if query:
00634                 raise TypeError('keyword arguments and query-dicts '
00635                                 'can\'t be combined')
00636             query, path = path[-1], path[:-1]
00637         elif query:
00638             query = dict([(k.endswith('_') and k[:-1] or k, v)
00639                           for k, v in query.items()])
00640         path = '/'.join([url_quote(x, self.charset) for x in path
00641                          if x is not None]).lstrip('/')
00642         rv = self.base
00643         if path:
00644             if not rv.endswith('/'):
00645                 rv += '/'
00646             rv = urlparse.urljoin(rv, path)
00647         if query:
00648             rv += '?' + url_encode(query, self.charset, sort=self.sort,
00649                                    key=self.key)
00650         return str(rv)
00651 
00652 
00653 class cached_property(object):
00654     """A decorator that converts a function into a lazy property.  The
00655     function wrapped is called the first time to retrieve the result
00656     and than that calculated result is used the next time you access
00657     the value::
00658 
00659         class Foo(object):
00660 
00661             @cached_property
00662             def foo(self):
00663                 # calculate something important here
00664                 return 42
00665 
00666     .. versionchanged:: 0.5
00667        cached properties are now optionally writeable.
00668     """
00669 
00670     def __init__(self, func, name=None, doc=None, writeable=False):
00671         self.func = func
00672         self.writeable = writeable
00673         self.__name__ = name or func.__name__
00674         self.__doc__ = doc or func.__doc__
00675 
00676     def __get__(self, obj, type=None):
00677         if obj is None:
00678             return self
00679         value = obj.__dict__.get(self.__name__, _missing)
00680         if value is _missing:
00681             value = self.func(obj)
00682             obj.__dict__[self.__name__] = value
00683         return value
00684 
00685     def __set__(self, obj, value):
00686         if not self.writeable:
00687             raise TypeError('read only attribute')
00688         obj.__dict__[self.__name__] = value
00689 
00690 
00691 class environ_property(_DictAccessorProperty):
00692     """Maps request attributes to environment variables. This works not only
00693     for the Werzeug request object, but also any other class with an
00694     environ attribute:
00695 
00696     >>> class Test(object):
00697     ...     environ = {'key': 'value'}
00698     ...     test = environ_property('key')
00699     >>> var = Test()
00700     >>> var.test
00701     'value'
00702 
00703     If you pass it a second value it's used as default if the key does not
00704     exist, the third one can be a converter that takes a value and converts
00705     it.  If it raises :exc:`ValueError` or :exc:`TypeError` the default value
00706     is used. If no default value is provided `None` is used.
00707 
00708     Per default the property is read only.  You have to explicitly enable it
00709     by passing ``read_only=False`` to the constructor.
00710     """
00711 
00712     read_only = True
00713 
00714     def lookup(self, obj):
00715         return obj.environ
00716 
00717 
00718 class header_property(_DictAccessorProperty):
00719     """Like `environ_property` but for headers."""
00720 
00721     def lookup(self, obj):
00722         return obj.headers
00723 
00724 
00725 class HTMLBuilder(object):
00726     """Helper object for HTML generation.
00727 
00728     Per default there are two instances of that class.  The `html` one, and
00729     the `xhtml` one for those two dialects.  The class uses keyword parameters
00730     and positional parameters to generate small snippets of HTML.
00731 
00732     Keyword parameters are converted to XML/SGML attributes, positional
00733     arguments are used as children.  Because Python accepts positional
00734     arguments before keyword arguments it's a good idea to use a list with the
00735     star-syntax for some children:
00736 
00737     >>> html.p(class_='foo', *[html.a('foo', href='foo.html'), ' ',
00738     ...                        html.a('bar', href='bar.html')])
00739     u'<p class="foo"><a href="foo.html">foo</a> <a href="bar.html">bar</a></p>'
00740 
00741     This class works around some browser limitations and can not be used for
00742     arbitrary SGML/XML generation.  For that purpose lxml and similar
00743     libraries exist.
00744 
00745     Calling the builder escapes the string passed:
00746 
00747     >>> html.p(html("<foo>"))
00748     u'<p>&lt;foo&gt;</p>'
00749     """
00750 
00751     from htmlentitydefs import name2codepoint
00752     _entity_re = re.compile(r'&([^;]+);')
00753     _entities = name2codepoint.copy()
00754     _entities['apos'] = 39
00755     _empty_elements = set([
00756         'area', 'base', 'basefont', 'br', 'col', 'frame', 'hr', 'img',
00757         'input', 'isindex', 'link', 'meta', 'param'
00758     ])
00759     _boolean_attributes = set([
00760         'selected', 'checked', 'compact', 'declare', 'defer', 'disabled',
00761         'ismap', 'multiple', 'nohref', 'noresize', 'noshade', 'nowrap'
00762     ])
00763     _plaintext_elements = set(['textarea'])
00764     _c_like_cdata = set(['script', 'style'])
00765     del name2codepoint
00766 
00767     def __init__(self, dialect):
00768         self._dialect = dialect
00769 
00770     def __call__(self, s):
00771         return escape(s)
00772 
00773     def __getattr__(self, tag):
00774         if tag[:2] == '__':
00775             raise AttributeError(tag)
00776         def proxy(*children, **arguments):
00777             buffer = ['<' + tag]
00778             write = buffer.append
00779             for key, value in arguments.iteritems():
00780                 if value is None:
00781                     continue
00782                 if key.endswith('_'):
00783                     key = key[:-1]
00784                 if key in self._boolean_attributes:
00785                     if not value:
00786                         continue
00787                     value = self._dialect == 'xhtml' and '="%s"' % key or ''
00788                 else:
00789                     value = '="%s"' % escape(value, True)
00790                 write(' ' + key + value)
00791             if not children and tag in self._empty_elements:
00792                 write(self._dialect == 'xhtml' and ' />' or '>')
00793                 return ''.join(buffer)
00794             write('>')
00795             children_as_string = ''.join(unicode(x) for x in children
00796                                          if x is not None)
00797             if children_as_string:
00798                 if tag in self._plaintext_elements:
00799                     children_as_string = escape(children_as_string)
00800                 elif tag in self._c_like_cdata and self._dialect == 'xhtml':
00801                     children_as_string = '/*<![CDATA[*/%s/*]]>*/' % \
00802                                          children_as_string
00803             buffer.extend((children_as_string, '</%s>' % tag))
00804             return ''.join(buffer)
00805         return proxy
00806 
00807     def __repr__(self):
00808         return '<%s for %r>' % (
00809             self.__class__.__name__,
00810             self._dialect
00811         )
00812 
00813 
00814 html = HTMLBuilder('html')
00815 xhtml = HTMLBuilder('xhtml')
00816 
00817 
00818 def parse_form_data(environ, stream_factory=None, charset='utf-8',
00819                     errors='ignore', max_form_memory_size=None,
00820                     max_content_length=None, cls=None,
00821                     silent=True):
00822     """Parse the form data in the environ and return it as tuple in the form
00823     ``(stream, form, files)``.  You should only call this method if the
00824     transport method is `POST` or `PUT`.
00825 
00826     If the mimetype of the data transmitted is `multipart/form-data` the
00827     files multidict will be filled with `FileStorage` objects.  If the
00828     mimetype is unknown the input stream is wrapped and returned as first
00829     argument, else the stream is empty.
00830 
00831     This function does not raise exceptions, even if the input data is
00832     malformed.
00833 
00834     Have a look at :ref:`dealing-with-request-data` for more details.
00835 
00836     .. versionadded:: 0.5
00837        The `max_form_memory_size`, `max_content_length` and
00838        `cls` parameters were added.
00839 
00840     .. versionadded:: 0.5.1
00841        The optional `silent` flag was added.
00842 
00843     :param environ: the WSGI environment to be used for parsing.
00844     :param stream_factory: An optional callable that returns a new read and
00845                            writeable file descriptor.  This callable works
00846                            the same as :meth:`~BaseResponse._get_file_stream`.
00847     :param charset: The character set for URL and url encoded form data.
00848     :param errors: The encoding error behavior.
00849     :param max_form_memory_size: the maximum number of bytes to be accepted for
00850                            in-memory stored form data.  If the data
00851                            exceeds the value specified an
00852                            :exc:`~exceptions.RequestURITooLarge`
00853                            exception is raised.
00854     :param max_content_length: If this is provided and the transmitted data
00855                                is longer than this value an
00856                                :exc:`~exceptions.RequestEntityTooLarge`
00857                                exception is raised.
00858     :param cls: an optional dict class to use.  If this is not specified
00859                        or `None` the default :class:`MultiDict` is used.
00860     :param silent: If set to False parsing errors will not be catched.
00861     :return: A tuple in the form ``(stream, form, files)``.
00862     """
00863     content_type, extra = parse_options_header(environ.get('CONTENT_TYPE', ''))
00864     try:
00865         content_length = int(environ['CONTENT_LENGTH'])
00866     except (KeyError, ValueError):
00867         content_length = 0
00868 
00869     if cls is None:
00870         cls = MultiDict
00871 
00872     if max_content_length is not None and content_length > max_content_length:
00873         raise RequestEntityTooLarge()
00874 
00875     stream = _empty_stream
00876     files = ()
00877 
00878     if content_type == 'multipart/form-data':
00879         try:
00880             form, files = parse_multipart(environ['wsgi.input'],
00881                                           extra.get('boundary'),
00882                                           content_length, stream_factory,
00883                                           charset, errors,
00884                                           max_form_memory_size=max_form_memory_size)
00885         except ValueError, e:
00886             if not silent:
00887                 raise
00888             form = cls()
00889         else:
00890             form = cls(form)
00891     elif content_type == 'application/x-www-form-urlencoded' or \
00892          content_type == 'application/x-url-encoded':
00893         if max_form_memory_size is not None and \
00894            content_length > max_form_memory_size:
00895             raise RequestEntityTooLarge()
00896         form = url_decode(environ['wsgi.input'].read(content_length),
00897                           charset, errors=errors, cls=cls)
00898     else:
00899         form = cls()
00900         stream = LimitedStream(environ['wsgi.input'], content_length)
00901 
00902     return stream, form, cls(files)
00903 
00904 
00905 def get_content_type(mimetype, charset):
00906     """Return the full content type string with charset for a mimetype.
00907 
00908     If the mimetype represents text the charset will be appended as charset
00909     parameter, otherwise the mimetype is returned unchanged.
00910 
00911     :param mimetype: the mimetype to be used as content type.
00912     :param charset: the charset to be appended in case it was a text mimetype.
00913     :return: the content type.
00914     """
00915     if mimetype.startswith('text/') or \
00916        mimetype == 'application/xml' or \
00917        (mimetype.startswith('application/') and
00918         mimetype.endswith('+xml')):
00919         mimetype += '; charset=' + charset
00920     return mimetype
00921 
00922 
00923 def format_string(string, context):
00924     """String-template format a string:
00925 
00926     >>> format_string('$foo and ${foo}s', dict(foo=42))
00927     '42 and 42s'
00928 
00929     This does not do any attribute lookup etc.  For more advanced string
00930     formattings have a look at the `werkzeug.template` module.
00931 
00932     :param string: the format string.
00933     :param context: a dict with the variables to insert.
00934     """
00935     def lookup_arg(match):
00936         x = context[match.group(1) or match.group(2)]
00937         if not isinstance(x, basestring):
00938             x = type(string)(x)
00939         return x
00940     return _format_re.sub(lookup_arg, string)
00941 
00942 
00943 def url_decode(s, charset='utf-8', decode_keys=False, include_empty=True,
00944                errors='ignore', separator='&', cls=None):
00945     """Parse a querystring and return it as :class:`MultiDict`.  Per default
00946     only values are decoded into unicode strings.  If `decode_keys` is set to
00947     `True` the same will happen for keys.
00948 
00949     Per default a missing value for a key will default to an empty key.  If
00950     you don't want that behavior you can set `include_empty` to `False`.
00951 
00952     Per default encoding errors are ignored.  If you want a different behavior
00953     you can set `errors` to ``'replace'`` or ``'strict'``.  In strict mode a
00954     `HTTPUnicodeError` is raised.
00955 
00956     .. versionchanged:: 0.5
00957        In previous versions ";" and "&" could be used for url decoding.
00958        This changed in 0.5 where only "&" is supported.  If you want to
00959        use ";" instead a different `separator` can be provided.
00960 
00961        The `cls` parameter was added.
00962 
00963     :param s: a string with the query string to decode.
00964     :param charset: the charset of the query string.
00965     :param decode_keys: set to `True` if you want the keys to be decoded
00966                         as well.
00967     :param include_empty: Set to `False` if you don't want empty values to
00968                           appear in the dict.
00969     :param errors: the decoding error behavior.
00970     :param separator: the pair separator to be used, defaults to ``&``
00971     :param cls: an optional dict class to use.  If this is not specified
00972                        or `None` the default :class:`MultiDict` is used.
00973     """
00974     if cls is None:
00975         cls = MultiDict
00976     result = []
00977     for pair in str(s).split(separator):
00978         if not pair:
00979             continue
00980         if '=' in pair:
00981             key, value = pair.split('=', 1)
00982         else:
00983             key = pair
00984             value = ''
00985         key = urllib.unquote_plus(key)
00986         if decode_keys:
00987             key = _decode_unicode(key, charset, errors)
00988         result.append((key, url_unquote_plus(value, charset, errors)))
00989     return cls(result)
00990 
00991 
00992 def url_encode(obj, charset='utf-8', encode_keys=False, sort=False, key=None,
00993                separator='&'):
00994     """URL encode a dict/`MultiDict`.  If a value is `None` it will not appear
00995     in the result string.  Per default only values are encoded into the target
00996     charset strings.  If `encode_keys` is set to ``True`` unicode keys are
00997     supported too.
00998 
00999     If `sort` is set to `True` the items are sorted by `key` or the default
01000     sorting algorithm.
01001 
01002     .. versionadded:: 0.5
01003         `sort`, `key`, and `separator` were added.
01004 
01005     :param obj: the object to encode into a query string.
01006     :param charset: the charset of the query string.
01007     :param encode_keys: set to `True` if you have unicode keys.
01008     :param sort: set to `True` if you want parameters to be sorted by `key`.
01009     :param separator: the separator to be used for the pairs.
01010     :param key: an optional function to be used for sorting.  For more details
01011                 check out the :func:`sorted` documentation.
01012     """
01013     if isinstance(obj, MultiDict):
01014         items = obj.lists()
01015     elif isinstance(obj, dict):
01016         items = []
01017         for k, v in obj.iteritems():
01018             if not isinstance(v, (tuple, list)):
01019                 v = [v]
01020             items.append((k, v))
01021     else:
01022         items = obj or ()
01023     if sort:
01024         items.sort(key=key)
01025     tmp = []
01026     for key, values in items:
01027         if encode_keys and isinstance(key, unicode):
01028             key = key.encode(charset)
01029         else:
01030             key = str(key)
01031         for value in values:
01032             if value is None:
01033                 continue
01034             elif isinstance(value, unicode):
01035                 value = value.encode(charset)
01036             else:
01037                 value = str(value)
01038             tmp.append('%s=%s' % (urllib.quote(key),
01039                                   urllib.quote_plus(value)))
01040     return separator.join(tmp)
01041 
01042 
01043 def url_quote(s, charset='utf-8', safe='/:'):
01044     """URL encode a single string with a given encoding.
01045 
01046     :param s: the string to quote.
01047     :param charset: the charset to be used.
01048     :param safe: an optional sequence of safe characters.
01049     """
01050     if isinstance(s, unicode):
01051         s = s.encode(charset)
01052     elif not isinstance(s, str):
01053         s = str(s)
01054     return urllib.quote(s, safe=safe)
01055 
01056 
01057 def url_quote_plus(s, charset='utf-8', safe=''):
01058     """URL encode a single string with the given encoding and convert
01059     whitespace to "+".
01060 
01061     :param s: the string to quote.
01062     :param charset: the charset to be used.
01063     :param safe: an optional sequence of safe characters.
01064     """
01065     if isinstance(s, unicode):
01066         s = s.encode(charset)
01067     elif not isinstance(s, str):
01068         s = str(s)
01069     return urllib.quote_plus(s, safe=safe)
01070 
01071 
01072 def url_unquote(s, charset='utf-8', errors='ignore'):
01073     """URL decode a single string with a given decoding.
01074 
01075     Per default encoding errors are ignored.  If you want a different behavior
01076     you can set `errors` to ``'replace'`` or ``'strict'``.  In strict mode a
01077     `HTTPUnicodeError` is raised.
01078 
01079     :param s: the string to unquote.
01080     :param charset: the charset to be used.
01081     :param errors: the error handling for the charset decoding.
01082     """
01083     return _decode_unicode(urllib.unquote(s), charset, errors)
01084 
01085 
01086 def url_unquote_plus(s, charset='utf-8', errors='ignore'):
01087     """URL decode a single string with the given decoding and decode
01088     a "+" to whitespace.
01089 
01090     Per default encoding errors are ignored.  If you want a different behavior
01091     you can set `errors` to ``'replace'`` or ``'strict'``.  In strict mode a
01092     `HTTPUnicodeError` is raised.
01093 
01094     :param s: the string to unquote.
01095     :param charset: the charset to be used.
01096     :param errors: the error handling for the charset decoding.
01097     """
01098     return _decode_unicode(urllib.unquote_plus(s), charset, errors)
01099 
01100 
01101 def url_fix(s, charset='utf-8'):
01102     r"""Sometimes you get an URL by a user that just isn't a real URL because
01103     it contains unsafe characters like ' ' and so on.  This function can fix
01104     some of the problems in a similar way browsers handle data entered by the
01105     user:
01106 
01107     >>> url_fix(u'http://de.wikipedia.org/wiki/Elf (Begriffskl\xe4rung)')
01108     'http://de.wikipedia.org/wiki/Elf%20%28Begriffskl%C3%A4rung%29'
01109 
01110     :param s: the string with the URL to fix.
01111     :param charset: The target charset for the URL if the url was given as
01112                     unicode string.
01113     """
01114     if isinstance(s, unicode):
01115         s = s.encode(charset, 'ignore')
01116     scheme, netloc, path, qs, anchor = urlparse.urlsplit(s)
01117     path = urllib.quote(path, '/%')
01118     qs = urllib.quote_plus(qs, ':&=')
01119     return urlparse.urlunsplit((scheme, netloc, path, qs, anchor))
01120 
01121 
01122 def secure_filename(filename):
01123     r"""Pass it a filename and it will return a secure version of it.  This
01124     filename can then savely be stored on a regular file system and passed
01125     to :func:`os.path.join`.  The filename returned is an ASCII only string
01126     for maximum portability.
01127 
01128     On windows system the function also makes sure that the file is not
01129     named after one of the special device files.
01130 
01131     >>> secure_filename("My cool movie.mov")
01132     'My_cool_movie.mov'
01133     >>> secure_filename("../../../etc/passwd")
01134     'etc_passwd'
01135     >>> secure_filename(u'i contain cool \xfcml\xe4uts.txt')
01136     'i_contain_cool_umlauts.txt'
01137 
01138     .. versionadded:: 0.5
01139 
01140     :param filename: the filename to secure
01141     """
01142     if isinstance(filename, unicode):
01143         from unicodedata import normalize
01144         filename = normalize('NFKD', filename).encode('ascii', 'ignore')
01145     for sep in os.path.sep, os.path.altsep:
01146         if sep:
01147             filename = filename.replace(sep, ' ')
01148     filename = str(_filename_ascii_strip_re.sub('', '_'.join(
01149                    filename.split()))).strip('._')
01150 
01151     # on nt a couple of special files are present in each folder.  We
01152     # have to ensure that the target file is not such a filename.  In
01153     # this case we prepend an underline
01154     if os.name == 'nt':
01155         if filename.split('.')[0].upper() in _windows_device_files:
01156             filename = '_' + filename
01157 
01158     return filename
01159 
01160 
01161 def escape(s, quote=False):
01162     """Replace special characters "&", "<" and ">" to HTML-safe sequences.  If
01163     the optional flag `quote` is `True`, the quotation mark character (") is
01164     also translated.
01165 
01166     There is a special handling for `None` which escapes to an empty string.
01167 
01168     :param s: the string to escape.
01169     :param quote: set to true to also escape double quotes.
01170     """
01171     if s is None:
01172         return ''
01173     elif hasattr(s, '__html__'):
01174         return s.__html__()
01175     elif not isinstance(s, basestring):
01176         s = unicode(s)
01177     s = s.replace('&', '&amp;').replace('<', '&lt;').replace('>', '&gt;')
01178     if quote:
01179         s = s.replace('"', "&quot;")
01180     return s
01181 
01182 
01183 def unescape(s):
01184     """The reverse function of `escape`.  This unescapes all the HTML
01185     entities, not only the XML entities inserted by `escape`.
01186 
01187     :param s: the string to unescape.
01188     """
01189     def handle_match(m):
01190         name = m.group(1)
01191         if name in HTMLBuilder._entities:
01192             return unichr(HTMLBuilder._entities[name])
01193         try:
01194             if name[:2] in ('#x', '#X'):
01195                 return unichr(int(name[2:], 16))
01196             elif name.startswith('#'):
01197                 return unichr(int(name[1:]))
01198         except ValueError:
01199             pass
01200         return u''
01201     return _entity_re.sub(handle_match, s)
01202 
01203 
01204 def get_host(environ):
01205     """Return the real host for the given WSGI environment.  This takes care
01206     of the `X-Forwarded-Host` header.
01207 
01208     :param environ: the WSGI environment to get the host of.
01209     """
01210     if 'HTTP_X_FORWARDED_HOST' in environ:
01211         return environ['HTTP_X_FORWARDED_HOST']
01212     elif 'HTTP_HOST' in environ:
01213         return environ['HTTP_HOST']
01214     result = environ['SERVER_NAME']
01215     if (environ['wsgi.url_scheme'], environ['SERVER_PORT']) not \
01216        in (('https', '443'), ('http', '80')):
01217         result += ':' + environ['SERVER_PORT']
01218     return result
01219 
01220 
01221 def get_current_url(environ, root_only=False, strip_querystring=False,
01222                     host_only=False):
01223     """A handy helper function that recreates the full URL for the current
01224     request or parts of it.  Here an example:
01225 
01226     >>> env = create_environ("/?param=foo", "http://localhost/script")
01227     >>> get_current_url(env)
01228     'http://localhost/script/?param=foo'
01229     >>> get_current_url(env, root_only=True)
01230     'http://localhost/script/'
01231     >>> get_current_url(env, host_only=True)
01232     'http://localhost/'
01233     >>> get_current_url(env, strip_querystring=True)
01234     'http://localhost/script/'
01235 
01236     :param environ: the WSGI environment to get the current URL from.
01237     :param root_only: set `True` if you only want the root URL.
01238     :param strip_querystring: set to `True` if you don't want the querystring.
01239     :param host_only: set to `True` if the host URL should be returned.
01240     """
01241     tmp = [environ['wsgi.url_scheme'], '://', get_host(environ)]
01242     cat = tmp.append
01243     if host_only:
01244         return ''.join(tmp) + '/'
01245     cat(urllib.quote(environ.get('SCRIPT_NAME', '').rstrip('/')))
01246     if root_only:
01247         cat('/')
01248     else:
01249         cat(urllib.quote('/' + environ.get('PATH_INFO', '').lstrip('/')))
01250         if not strip_querystring:
01251             qs = environ.get('QUERY_STRING')
01252             if qs:
01253                 cat('?' + qs)
01254     return ''.join(tmp)
01255 
01256 
01257 def pop_path_info(environ):
01258     """Removes and returns the next segment of `PATH_INFO`, pushing it onto
01259     `SCRIPT_NAME`.  Returns `None` if there is nothing left on `PATH_INFO`.
01260 
01261     If there are empty segments (``'/foo//bar``) these are ignored but
01262     properly pushed to the `SCRIPT_NAME`:
01263 
01264     >>> env = {'SCRIPT_NAME': '/foo', 'PATH_INFO': '/a/b'}
01265     >>> pop_path_info(env)
01266     'a'
01267     >>> env['SCRIPT_NAME']
01268     '/foo/a'
01269     >>> pop_path_info(env)
01270     'b'
01271     >>> env['SCRIPT_NAME']
01272     '/foo/a/b'
01273 
01274     .. versionadded:: 0.5
01275 
01276     :param environ: the WSGI environment that is modified.
01277     """
01278     path = environ.get('PATH_INFO')
01279     if not path:
01280         return None
01281 
01282     script_name = environ.get('SCRIPT_NAME', '')
01283 
01284     # shift multiple leading slashes over
01285     old_path = path
01286     path = path.lstrip('/')
01287     if path != old_path:
01288         script_name += '/' * (len(old_path) - len(path))
01289 
01290     if '/' not in path:
01291         environ['PATH_INFO'] = ''
01292         environ['SCRIPT_NAME'] = script_name + path
01293         return path
01294 
01295     segment, path = path.split('/', 1)
01296     environ['PATH_INFO'] = '/' + path
01297     environ['SCRIPT_NAME'] = script_name + segment
01298     return segment
01299 
01300 
01301 def peek_path_info(environ):
01302     """Returns the next segment on the `PATH_INFO` or `None` if there
01303     is none.  Works like :func:`pop_path_info` without modifying the
01304     environment:
01305 
01306     >>> env = {'SCRIPT_NAME': '/foo', 'PATH_INFO': '/a/b'}
01307     >>> peek_path_info(env)
01308     'a'
01309     >>> peek_path_info(env)
01310     'a'
01311 
01312     .. versionadded:: 0.5
01313 
01314     :param environ: the WSGI environment that is checked.
01315     """
01316     segments = environ.get('PATH_INFO', '').lstrip('/').split('/', 1)
01317     if segments:
01318         return segments[0]
01319 
01320 
01321 def cookie_date(expires=None):
01322     """Formats the time to ensure compatibility with Netscape's cookie
01323     standard.
01324 
01325     Accepts a floating point number expressed in seconds since the epoc in, a
01326     datetime object or a timetuple.  All times in UTC.  The :func:`parse_date`
01327     function can be used to parse such a date.
01328 
01329     Outputs a string in the format ``Wdy, DD-Mon-YYYY HH:MM:SS GMT``.
01330 
01331     :param expires: If provided that date is used, otherwise the current.
01332     """
01333     return _dump_date(expires, '-')
01334 
01335 
01336 def parse_cookie(header, charset='utf-8', errors='ignore',
01337                  cls=None):
01338     """Parse a cookie.  Either from a string or WSGI environ.
01339 
01340     Per default encoding errors are ignored.  If you want a different behavior
01341     you can set `errors` to ``'replace'`` or ``'strict'``.  In strict mode a
01342     :exc:`HTTPUnicodeError` is raised.
01343 
01344     .. versionchanged:: 0.5
01345        This function now returns a :class:`TypeConversionDict` instead of a
01346        regular dict.  The `cls` parameter was added.
01347 
01348     :param header: the header to be used to parse the cookie.  Alternatively
01349                    this can be a WSGI environment.
01350     :param charset: the charset for the cookie values.
01351     :param errors: the error behavior for the charset decoding.
01352     :param cls: an optional dict class to use.  If this is not specified
01353                        or `None` the default :class:`TypeConversionDict` is
01354                        used.
01355     """
01356     if isinstance(header, dict):
01357         header = header.get('HTTP_COOKIE', '')
01358     if cls is None:
01359         cls = TypeConversionDict
01360     cookie = _ExtendedCookie()
01361     cookie.load(header)
01362     result = {}
01363 
01364     # decode to unicode and skip broken items.  Our extended morsel
01365     # and extended cookie will catch CookieErrors and convert them to
01366     # `None` items which we have to skip here.
01367     for key, value in cookie.iteritems():
01368         if value.value is not None:
01369             result[key] = _decode_unicode(value.value, charset, errors)
01370 
01371     return cls(result)
01372 
01373 
01374 def dump_cookie(key, value='', max_age=None, expires=None, path='/',
01375                 domain=None, secure=None, httponly=False, charset='utf-8',
01376                 sync_expires=True):
01377     """Creates a new Set-Cookie header without the ``Set-Cookie`` prefix
01378     The parameters are the same as in the cookie Morsel object in the
01379     Python standard library but it accepts unicode data, too.
01380 
01381     :param max_age: should be a number of seconds, or `None` (default) if
01382                     the cookie should last only as long as the client's
01383                     browser session.  Additionally `timedelta` objects
01384                     are accepted, too.
01385     :param expires: should be a `datetime` object or unix timestamp.
01386     :param path: limits the cookie to a given path, per default it will
01387                  span the whole domain.
01388     :param domain: Use this if you want to set a cross-domain cookie. For
01389                    example, ``domain=".example.com"`` will set a cookie
01390                    that is readable by the domain ``www.example.com``,
01391                    ``foo.example.com`` etc. Otherwise, a cookie will only
01392                    be readable by the domain that set it.
01393     :param secure: The cookie will only be available via HTTPS
01394     :param httponly: disallow JavaScript to access the cookie.  This is an
01395                      extension to the cookie standard and probably not
01396                      supported by all browsers.
01397     :param charset: the encoding for unicode values.
01398     :param sync_expires: automatically set expires if max_age is defined
01399                          but expires not.
01400     """
01401     try:
01402         key = str(key)
01403     except UnicodeError:
01404         raise TypeError('invalid key %r' % key)
01405     if isinstance(value, unicode):
01406         value = value.encode(charset)
01407     morsel = _ExtendedMorsel(key, value)
01408     if isinstance(max_age, timedelta):
01409         max_age = (max_age.days * 60 * 60 * 24) + max_age.seconds
01410     if expires is not None:
01411         if not isinstance(expires, basestring):
01412             expires = cookie_date(expires)
01413         morsel['expires'] = expires
01414     elif max_age is not None and sync_expires:
01415         morsel['expires'] = cookie_date(time() + max_age)
01416     for k, v in (('path', path), ('domain', domain), ('secure', secure),
01417                  ('max-age', max_age), ('httponly', httponly)):
01418         if v is not None and v is not False:
01419             morsel[k] = str(v)
01420     return morsel.output(header='').lstrip()
01421 
01422 
01423 def http_date(timestamp=None):
01424     """Formats the time to match the RFC1123 date format.
01425 
01426     Accepts a floating point number expressed in seconds since the epoc in, a
01427     datetime object or a timetuple.  All times in UTC.  The :func:`parse_date`
01428     function can be used to parse such a date.
01429 
01430     Outputs a string in the format ``Wdy, DD Mon YYYY HH:MM:SS GMT``.
01431 
01432     :param timestamp: If provided that date is used, otherwise the current.
01433     """
01434     return _dump_date(timestamp, ' ')
01435 
01436 
01437 def redirect(location, code=302):
01438     """Return a response object (a WSGI application) that, if called,
01439     redirects the client to the target location.  Supported codes are 301,
01440     302, 303, 305, and 307.  300 is not supported because it's not a real
01441     redirect and 304 because it's the answer for a request with a request
01442     with defined If-Modified-Since headers.
01443 
01444     :param location: the location the response should redirect to.
01445     :param code: the redirect status code.
01446     """
01447     assert code in (301, 302, 303, 305, 307), 'invalid code'
01448     from werkzeug.wrappers import BaseResponse
01449     response = BaseResponse(
01450         '<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 3.2 Final//EN">\n'
01451         '<title>Redirecting...</title>\n'
01452         '<h1>Redirecting...</h1>\n'
01453         '<p>You should be redirected automatically to target URL: '
01454         '<a href="%s">%s</a>.  If not click the link.' %
01455         ((escape(location),) * 2), code, mimetype='text/html')
01456     response.headers['Location'] = location
01457     return response
01458 
01459 
01460 def append_slash_redirect(environ, code=301):
01461     """Redirect to the same URL but with a slash appended.  The behavior
01462     of this function is undefined if the path ends with a slash already.
01463 
01464     :param environ: the WSGI environment for the request that triggers
01465                     the redirect.
01466     :param code: the status code for the redirect.
01467     """
01468     new_path = environ['PATH_INFO'].strip('/') + '/'
01469     query_string = environ['QUERY_STRING']
01470     if query_string:
01471         new_path += '?' + query_string
01472     return redirect(new_path, code)
01473 
01474 
01475 def responder(f):
01476     """Marks a function as responder.  Decorate a function with it and it
01477     will automatically call the return value as WSGI application.
01478 
01479     Example::
01480 
01481         @responder
01482         def application(environ, start_response):
01483             return Response('Hello World!')
01484     """
01485     return _patch_wrapper(f, lambda *a: f(*a)(*a[-2:]))
01486 
01487 
01488 def wrap_file(environ, file, buffer_size=8192):
01489     """Wraps a file.  This uses the WSGI server's file wrapper if available
01490     or otherwise the generic :class:`FileWrapper`.
01491 
01492     .. versionadded:: 0.5
01493 
01494     If the file wrapper from the WSGI server is used it's important to not
01495     iterate over it from inside the application but to pass it through
01496     unchanged.  If you want to pass out a file wrapper inside a response
01497     object you have to set :attr:`~BaseResponse.direct_passthrough` to `True`.
01498 
01499     More information about file wrappers are available in :pep:`333`.
01500 
01501     :param file: a :class:`file`-like object with a :meth:`~file.read` method.
01502     :param buffer_size: number of bytes for one iteration.
01503     """
01504     return environ.get('wsgi.file_wrapper', FileWrapper)(file, buffer_size)
01505 
01506 
01507 def import_string(import_name, silent=False):
01508     """Imports an object based on a string.  This is useful if you want to
01509     use import paths as endpoints or something similar.  An import path can
01510     be specified either in dotted notation (``xml.sax.saxutils.escape``)
01511     or with a colon as object delimiter (``xml.sax.saxutils:escape``).
01512 
01513     If `silent` is True the return value will be `None` if the import fails.
01514 
01515     :param import_name: the dotted name for the object to import.
01516     :param silent: if set to `True` import errors are ignored and
01517                    `None` is returned instead.
01518     :return: imported object
01519     """
01520     try:
01521         if ':' in import_name:
01522             module, obj = import_name.split(':', 1)
01523         elif '.' in import_name:
01524             module, obj = import_name.rsplit('.', 1)
01525         else:
01526             return __import__(import_name)
01527         return getattr(__import__(module, None, None, [obj]), obj)
01528     except (ImportError, AttributeError):
01529         if not silent:
01530             raise
01531 
01532 
01533 def find_modules(import_path, include_packages=False, recursive=False):
01534     """Find all the modules below a package.  This can be useful to
01535     automatically import all views / controllers so that their metaclasses /
01536     function decorators have a chance to register themselves on the
01537     application.
01538 
01539     Packages are not returned unless `include_packages` is `True`.  This can
01540     also recursively list modules but in that case it will import all the
01541     packages to get the correct load path of that module.
01542 
01543     :param import_name: the dotted name for the package to find child modules.
01544     :param include_packages: set to `True` if packages should be returned, too.
01545     :param recursive: set to `True` if recursion should happen.
01546     :return: generator
01547     """
01548     module = import_string(import_path)
01549     path = getattr(module, '__path__', None)
01550     if path is None:
01551         raise ValueError('%r is not a package' % import_path)
01552     basename = module.__name__ + '.'
01553     for modname, ispkg in _iter_modules(path):
01554         modname = basename + modname
01555         if ispkg:
01556             if include_packages:
01557                 yield modname
01558             if recursive:
01559                 for item in find_modules(modname, include_packages, True):
01560                     yield item
01561         else:
01562             yield modname
01563 
01564 
01565 def validate_arguments(func, args, kwargs, drop_extra=True):
01566     """Check if the function accepts the arguments and keyword arguments.
01567     Returns a new ``(args, kwargs)`` tuple that can savely be passed to
01568     the function without causing a `TypeError` because the function signature
01569     is incompatible.  If `drop_extra` is set to `True` (which is the default)
01570     any extra positional or keyword arguments are dropped automatically.
01571 
01572     The exception raised provides three attributes:
01573 
01574     `missing`
01575         A set of argument names that the function expected but where
01576         missing.
01577 
01578     `extra`
01579         A dict of keyword arguments that the function can not handle but
01580         where provided.
01581 
01582     `extra_positional`
01583         A list of values that where given by positional argument but the
01584         function cannot accept.
01585 
01586     This can be useful for decorators that forward user submitted data to
01587     a view function::
01588 
01589         from werkzeug import ArgumentValidationError, validate_arguments
01590 
01591         def sanitize(f):
01592             def proxy(request):
01593                 data = request.values.to_dict()
01594                 try:
01595                     args, kwargs = validate_arguments(f, (request,), data)
01596                 except ArgumentValidationError:
01597                     raise BadRequest('The browser failed to transmit all '
01598                                      'the data expected.')
01599                 return f(*args, **kwargs)
01600             return proxy
01601 
01602     :param func: the function the validation is performed against.
01603     :param args: a tuple of positional arguments.
01604     :param kwargs: a dict of keyword arguments.
01605     :param drop_extra: set to `False` if you don't want extra arguments
01606                        to be silently dropped.
01607     :return: tuple in the form ``(args, kwargs)``.
01608     """
01609     parser = _parse_signature(func)
01610     args, kwargs, missing, extra, extra_positional = parser(args, kwargs)[:5]
01611     if missing:
01612         raise ArgumentValidationError(tuple(missing))
01613     elif (extra or extra_positional) and not drop_extra:
01614         raise ArgumentValidationError(None, extra, extra_positional)
01615     return tuple(args), kwargs
01616 
01617 
01618 def bind_arguments(func, args, kwargs):
01619     """Bind the arguments provided into a dict.  When passed a function,
01620     a tuple of arguments and a dict of keyword arguments `bind_arguments`
01621     returns a dict of names as the function would see it.  This can be useful
01622     to implement a cache decorator that uses the function arguments to build
01623     the cache key based on the values of the arguments.
01624 
01625     :param func: the function the arguments should be bound for.
01626     :param args: tuple of positional arguments.
01627     :param kwargs: a dict of keyword arguments.
01628     :return: a :class:`dict` of bound keyword arguments.
01629     """
01630     args, kwargs, missing, extra, extra_positional, \
01631         arg_spec, vararg_var, kwarg_var = _parse_signature(func)(args, kwargs)
01632     values = {}
01633     for (name, has_default, default), value in zip(arg_spec, args):
01634         values[name] = value
01635     if vararg_var is not None:
01636         values[vararg_var] = tuple(extra_positional)
01637     elif extra_positional:
01638         raise TypeError('too many positional arguments')
01639     if kwarg_var is not None:
01640         multikw = set(extra) & set([x[0] for x in arg_spec])
01641         if multikw:
01642             raise TypeError('got multiple values for keyword argument ' +
01643                             repr(iter(multikw).next()))
01644         values[kwarg_var] = extra
01645     elif extra:
01646         raise TypeError('got unexpected keyword argument ' +
01647                         repr(iter(extra).next()))
01648     return values
01649 
01650 
01651 class ArgumentValidationError(ValueError):
01652     """Raised if :func:`validate_arguments` fails to validate"""
01653 
01654     def __init__(self, missing=None, extra=None, extra_positional=None):
01655         self.missing = set(missing or ())
01656         self.extra = extra or {}
01657         self.extra_positional = extra_positional or []
01658         ValueError.__init__(self, 'function arguments invalid.  ('
01659                             '%d missing, %d additional)' % (
01660             len(self.missing),
01661             len(self.extra) + len(self.extra_positional)
01662         ))
01663 
01664 
01665 # circular dependency fun
01666 from werkzeug.http import parse_multipart, parse_options_header, \
01667      is_resource_modified
01668 from werkzeug.exceptions import BadRequest, RequestEntityTooLarge
01669 from werkzeug.datastructures import MultiDict, TypeConversionDict
01670 
01671 
01672 # DEPRECATED
01673 # these objects were previously in this module as well.  we import
01674 # them here for backwards compatibility.  Will go away in 0.6
01675 from werkzeug.datastructures import MultiDict, CombinedMultiDict, \
01676      Headers, EnvironHeaders
01677 
01678 def create_environ(*args, **kwargs):
01679     """backward compatibility."""
01680     from werkzeug.test import create_environ
01681     return create_environ(*args, **kwargs)
01682 
01683 def run_wsgi_app(*args, **kwargs):
01684     """backwards compatibility."""
01685     from werkzeug.test import run_wsgi_app
01686     return run_wsgi_app(*args, **kwargs)