Back to index

moin  1.9.0~rc2
wrappers.py
Go to the documentation of this file.
00001 # -*- coding: utf-8 -*-
00002 """
00003     werkzeug.wrappers
00004     ~~~~~~~~~~~~~~~~~
00005 
00006     The wrappers are simple request and response objects which you can
00007     subclass to do whatever you want them to do.  The request object contains
00008     the information transmitted by the client (webbrowser) and the response
00009     object contains all the information sent back to the browser.
00010 
00011     An important detail is that the request object is created with the WSGI
00012     environ and will act as high-level proxy whereas the response object is an
00013     actual WSGI application.
00014 
00015     Like everything else in Werkzeug these objects will work correctly with
00016     unicode data.  Incoming form data parsed by the response object will be
00017     decoded into an unicode object if possible and if it makes sense.
00018 
00019 
00020     :copyright: (c) 2009 by the Werkzeug Team, see AUTHORS for more details.
00021     :license: BSD, see LICENSE for more details.
00022 """
00023 import tempfile
00024 import urlparse
00025 from datetime import datetime, timedelta
00026 from werkzeug.http import HTTP_STATUS_CODES, \
00027      parse_accept_header, parse_cache_control_header, parse_etags, \
00028      parse_date, generate_etag, is_resource_modified, unquote_etag, \
00029      quote_etag, parse_set_header, parse_authorization_header, \
00030      parse_www_authenticate_header, remove_entity_headers, \
00031      default_stream_factory, parse_options_header, \
00032      dump_options_header
00033 from werkzeug.utils import cached_property, environ_property, \
00034      get_current_url, url_encode, run_wsgi_app, get_host, \
00035      cookie_date, parse_cookie, dump_cookie, http_date, escape, \
00036      header_property, parse_form_data, get_content_type, url_decode
00037 from werkzeug.datastructures import MultiDict, CombinedMultiDict, Headers, \
00038      EnvironHeaders, ImmutableMultiDict, ImmutableTypeConversionDict, \
00039      ImmutableList, MIMEAccept, CharsetAccept, LanguageAccept, \
00040      ResponseCacheControl, RequestCacheControl, CallbackDict
00041 from werkzeug._internal import _empty_stream, _decode_unicode, \
00042      _patch_wrapper
00043 
00044 
00045 class BaseRequest(object):
00046     """Very basic request object.  This does not implement advanced stuff like
00047     entity tag parsing or cache controls.  The request object is created with
00048     the WSGI environment as first argument and will add itself to the WSGI
00049     environment as ``'werkzeug.request'`` unless it's created with
00050     `populate_request` set to False.
00051 
00052     There are a couple of mixins available that add additional functionality
00053     to the request object, there is also a class called `Request` which
00054     subclasses `BaseRequest` and all the important mixins.
00055 
00056     It's a good idea to create a custom subclass of the :class:`BaseRequest`
00057     and add missing functionality either via mixins or direct implementation.
00058     Here an example for such subclasses::
00059 
00060         from werkzeug import BaseRequest, ETagRequestMixin
00061 
00062         class Request(BaseRequest, ETagRequestMixin):
00063             pass
00064 
00065     Request objects are **read only**.  As of 0.5 modifications are not
00066     allowed in any place.  Unlike the lower level parsing functions the
00067     request object will use immutable objects everywhere possible.
00068 
00069     Per default the request object will assume all the text data is `utf-8`
00070     encoded.  Please refer to `the unicode chapter <unicode.txt>`_ for more
00071     details about customizing the behavior.
00072 
00073     Per default the request object will be added to the WSGI
00074     environment as `werkzeug.request` to support the debugging system.
00075     If you don't want that, set `populate_request` to `False`.
00076 
00077     If `shallow` is `True` the environment is initialized as shallow
00078     object around the environ.  Every operation that would modify the
00079     environ in any way (such as consuming form data) raises an exception
00080     unless the `shallow` attribute is explicitly set to `False`.  This
00081     is useful for middlewares where you don't want to consume the form
00082     data by accident.  A shallow request is not populated to the WSGI
00083     environment.
00084 
00085     .. versionchanged:: 0.5
00086        read-only mode was enforced by using immutables classes for all
00087        data.
00088     """
00089 
00090     #: the charset for the request, defaults to utf-8
00091     charset = 'utf-8'
00092 
00093     #: the error handling procedure for errors, defaults to 'ignore'
00094     encoding_errors = 'ignore'
00095 
00096     #: set to True if the application runs behind an HTTP proxy
00097     is_behind_proxy = False
00098 
00099     #: the maximum content length.  This is forwarded to the form data
00100     #: parsing function (:func:`parse_form_data`).  When set and the
00101     #: :attr:`form` or :attr:`files` attribute is accessed and the
00102     #: parsing fails because more than the specified value is transmitted
00103     #: a :exc:`~exceptions.RequestEntityTooLarge` exception is raised.
00104     #:
00105     #: Have a look at :ref:`dealing-with-request-data` for more details.
00106     #:
00107     #: .. versionadded:: 0.5
00108     max_content_length = None
00109 
00110     #: the maximum form field size.  This is forwarded to the form data
00111     #: parsing function (:func:`parse_form_data`).  When set and the
00112     #: :attr:`form` or :attr:`files` attribute is accessed and the
00113     #: data in memory for post data is longer than the specified value a
00114     #: :exc:`~exceptions.RequestEntityTooLarge` exception is raised.
00115     #:
00116     #: Have a look at :ref:`dealing-with-request-data` for more details.
00117     #:
00118     #: .. versionadded:: 0.5
00119     max_form_memory_size = None
00120 
00121     def __init__(self, environ, populate_request=True, shallow=False):
00122         self.environ = environ
00123         if populate_request and not shallow:
00124             self.environ['werkzeug.request'] = self
00125         self.shallow = shallow
00126         self._data_stream = None
00127 
00128     @classmethod
00129     def from_values(cls, *args, **kwargs):
00130         """Create a new request object based on the values provided.  If
00131         environ is given missing values are filled from there.  This method is
00132         useful for small scripts when you need to simulate a request from an URL.
00133         Do not use this method for unittesting, there is a full featured client
00134         object (:class:`Client`) that allows to create multipart requests,
00135         support for cookies etc.
00136 
00137         This accepts the same options as the :class:`EnvironBuilder`.
00138 
00139         .. versionchanged:: 0.5
00140            This method now accepts the same arguments as
00141            :class:`EnvironBuilder`.  Because of this the `environ` parameter
00142            is now called `environ_overrides`.
00143 
00144         :return: request object
00145         """
00146         from werkzeug.test import EnvironBuilder
00147         charset = kwargs.pop('charset', cls.charset)
00148         environ = kwargs.pop('environ', None)
00149         if environ is not None:
00150             from warnings import warn
00151             warn(DeprecationWarning('The environ parameter to from_values'
00152                                     ' is now called environ_overrides for'
00153                                     ' consistency with EnvironBuilder'),
00154                  stacklevel=2)
00155             kwargs['environ_overrides'] = environ
00156         builder = EnvironBuilder(*args, **kwargs)
00157         try:
00158             return builder.get_request(cls)
00159         finally:
00160             builder.close()
00161 
00162     @classmethod
00163     def application(cls, f):
00164         """Decorate a function as responder that accepts the request as first
00165         argument.  This works like the :func:`responder` decorator but the
00166         function is passed the request object as first argument::
00167 
00168             @Request.application
00169             def my_wsgi_app(request):
00170                 return Response('Hello World!')
00171 
00172         :param f: the WSGI callable to decorate
00173         :return: a new WSGI callable
00174         """
00175         #: return a callable that wraps the -2nd argument with the request
00176         #: and calls the function with all the arguments up to that one and
00177         #: the request.  The return value is then called with the latest
00178         #: two arguments.  This makes it possible to use this decorator for
00179         #: both methods and standalone WSGI functions.
00180         return _patch_wrapper(f, lambda *a: f(*a[:-2]+(cls(a[-2]),))(*a[-2:]))
00181 
00182     def _get_file_stream(self, total_content_length, content_type, filename=None,
00183                          content_length=None):
00184         """Called to get a stream for the file upload.
00185 
00186         This must provide a file-like class with `read()`, `readline()`
00187         and `seek()` methods that is both writeable and readable.
00188 
00189         The default implementation returns a temporary file if the total
00190         content length is higher than 500KB.  Because many browsers do not
00191         provide a content length for the files only the total content
00192         length matters.
00193 
00194         .. versionchanged:: 0.5
00195            Previously this function was not passed any arguments.  In 0.5 older
00196            functions not accepting any arguments are still supported for
00197            backwards compatibility.
00198 
00199         :param total_content_length: the total content length of all the
00200                                      data in the request combined.  This value
00201                                      is guaranteed to be there.
00202         :param content_type: the mimetype of the uploaded file.
00203         :param filename: the filename of the uploaded file.  May be `None`.
00204         :param content_length: the length of this file.  This value is usually
00205                                not provided because webbrowsers do not provide
00206                                this value.
00207         """
00208         return default_stream_factory(total_content_length, content_type,
00209                                       filename, content_length)
00210 
00211     def _load_form_data(self):
00212         """Method used internally to retrieve submitted data.  After calling
00213         this sets `_form` and `_files` on the request object to multi dicts
00214         filled with the incoming form data.  As a matter of fact the input
00215         stream will be empty afterwards.
00216 
00217         :internal:
00218         """
00219         if self._data_stream is None:
00220             if self.shallow:
00221                 raise RuntimeError('A shallow request tried to consume '
00222                                    'form data.  If you really want to do '
00223                                    'that, set `shallow` to False.')
00224             data = None
00225             if self.environ['REQUEST_METHOD'] in ('POST', 'PUT'):
00226                 try:
00227                     data = parse_form_data(self.environ, self._get_file_stream,
00228                                            self.charset, self.encoding_errors,
00229                                            self.max_form_memory_size,
00230                                            self.max_content_length,
00231                                            cls=ImmutableMultiDict,
00232                                            silent=False)
00233                 except ValueError, e:
00234                     self._form_parsing_failed(e)
00235             if data is None:
00236                 data = (_empty_stream, ImmutableMultiDict(),
00237                         ImmutableMultiDict())
00238             self._data_stream, self._form, self._files = data
00239 
00240     def _form_parsing_failed(self, error):
00241         """Called if parsing of form data failed.  This is currently only
00242         invoked for failed multipart uploads.  By default this method does
00243         nothing.
00244 
00245         :param error: a `ValueError` object with a message why the
00246                       parsing failed.
00247 
00248         .. versionadded:: 0.5.1
00249         """
00250 
00251     @property
00252     def stream(self):
00253         """The parsed stream if the submitted data was not multipart or
00254         urlencoded form data.  This stream is the stream left by the form data
00255         parser module after parsing.  This is *not* the WSGI input stream but
00256         a wrapper around it that ensures the caller does not accidentally
00257         read past `Content-Length`.
00258         """
00259         self._load_form_data()
00260         return self._data_stream
00261 
00262     input_stream = environ_property('wsgi.input', 'The WSGI input stream.\n'
00263         'In general it\'s a bad idea to use this one because you can easily '
00264         'read past the boundary.  Use the :attr:`stream` instead.')
00265 
00266     @cached_property
00267     def args(self):
00268         """The parsed URL parameters as :class:`ImmutableMultiDict`."""
00269         return url_decode(self.environ.get('QUERY_STRING', ''), self.charset,
00270                           errors=self.encoding_errors,
00271                           cls=ImmutableMultiDict)
00272 
00273     @cached_property
00274     def data(self):
00275         """This reads the buffered incoming data from the client into the
00276         string.  Usually it's a bad idea to access :attr:`data` because a client
00277         could send dozens of megabytes or more to cause memory problems on the
00278         server.
00279 
00280         To circumvent that make sure to check the content length first.
00281         """
00282         return self.stream.read()
00283 
00284     @property
00285     def form(self):
00286         """Form parameters.  Currently it's not guaranteed that the
00287         :class:`ImmutableMultiDict` returned by this function is ordered in
00288         the same way as the submitted form data.
00289         """
00290         self._load_form_data()
00291         return self._form
00292 
00293     @cached_property
00294     def values(self):
00295         """Combined multi dict for :attr:`args` and :attr:`form`."""
00296         return CombinedMultiDict([self.args, self.form])
00297 
00298     @property
00299     def files(self):
00300         """:class:`MultiDict` object containing all uploaded files.  Each key in
00301         :attr:`files` is the name from the ``<input type="file" name="">``.  Each
00302         value in :attr:`files` is a Werkzeug :class:`FileStorage` object.
00303 
00304         Note that :attr:`files` will only contain data if the request method was
00305         POST or PUT and the ``<form>`` that posted to the request had
00306         ``enctype="multipart/form-data"``.  It will be empty otherwise.
00307 
00308         See the :class:`MultiDict` / :class:`FileStorage` documentation for more
00309         details about the used data structure.
00310         """
00311         self._load_form_data()
00312         return self._files
00313 
00314     @cached_property
00315     def cookies(self):
00316         """The retrieved cookie values as regular dictionary."""
00317         return parse_cookie(self.environ, self.charset,
00318                             cls=ImmutableTypeConversionDict)
00319 
00320     @cached_property
00321     def headers(self):
00322         """The headers from the WSGI environ as immutable
00323         :class:`EnvironHeaders`.
00324         """
00325         return EnvironHeaders(self.environ)
00326 
00327     @cached_property
00328     def path(self):
00329         """Requested path as unicode.  This works a bit like the regular path
00330         info in the WSGI environment but will always include a leading slash,
00331         even if the URL root is accessed.
00332         """
00333         path = '/' + (self.environ.get('PATH_INFO') or '').lstrip('/')
00334         return _decode_unicode(path, self.charset, self.encoding_errors)
00335 
00336     @cached_property
00337     def script_root(self):
00338         """The root path of the script without the trailing slash."""
00339         path = (self.environ.get('SCRIPT_NAME') or '').rstrip('/')
00340         return _decode_unicode(path, self.charset, self.encoding_errors)
00341 
00342     @cached_property
00343     def url(self):
00344         """The reconstructed current URL"""
00345         return get_current_url(self.environ)
00346 
00347     @cached_property
00348     def base_url(self):
00349         """Like :attr:`url` but without the querystring"""
00350         return get_current_url(self.environ, strip_querystring=True)
00351 
00352     @cached_property
00353     def url_root(self):
00354         """The full URL root (with hostname), this is the application root."""
00355         return get_current_url(self.environ, True)
00356 
00357     @cached_property
00358     def host_url(self):
00359         """Just the host with scheme."""
00360         return get_current_url(self.environ, host_only=True)
00361 
00362     @cached_property
00363     def host(self):
00364         """Just the host including the port if available."""
00365         return get_host(self.environ)
00366 
00367     query_string = environ_property('QUERY_STRING', '', read_only=True, doc=
00368         '''The URL parameters as raw bytestring.''')
00369     method = environ_property('REQUEST_METHOD', 'GET', read_only=True, doc=
00370         '''The transmission method. (For example ``'GET'`` or ``'POST'``).''')
00371 
00372     @cached_property
00373     def access_route(self):
00374         """If a forwarded header exists this is a list of all ip addresses
00375         from the client ip to the last proxy server.
00376         """
00377         if 'HTTP_X_FORWARDED_FOR' in self.environ:
00378             addr = self.environ['HTTP_X_FORWARDED_FOR'].split(',')
00379             return ImmutableList([x.strip() for x in addr])
00380         elif 'REMOTE_ADDR' in self.environ:
00381             return ImmutableList([self.environ['REMOTE_ADDR']])
00382         return ImmutableList()
00383 
00384     @property
00385     def remote_addr(self):
00386         """The remote address of the client."""
00387         if self.is_behind_proxy and self.access_route:
00388             return self.access_route[0]
00389         return self.environ.get('REMOTE_ADDR')
00390 
00391     remote_user = environ_property('REMOTE_USER', doc='''
00392         If the server supports user authentication, and the script is
00393         protected, this attribute contains the username the user has
00394         authenticated as.''')
00395 
00396     is_xhr = property(lambda x: x.environ.get('HTTP_X_REQUESTED_WITH', '')
00397                       .lower() == 'xmlhttprequest', doc='''
00398         True if the request was triggered via a JavaScript XMLHttpRequest.
00399         This only works with libraries that support the `X-Requested-With`
00400         header and set it to "XMLHttpRequest".  Libraries that do that are
00401         prototype, jQuery and Mochikit and probably some more.''')
00402     is_secure = property(lambda x: x.environ['wsgi.url_scheme'] == 'https',
00403                          doc='`True` if the request is secure.')
00404     is_multithread = environ_property('wsgi.multithread', doc='''
00405         boolean that is `True` if the application is served by
00406         a multithreaded WSGI server.''')
00407     is_multiprocess = environ_property('wsgi.multiprocess', doc='''
00408         boolean that is `True` if the application is served by
00409         a WSGI server that spawns multiple processes.''')
00410     is_run_once = environ_property('wsgi.run_once', doc='''
00411         boolean that is `True` if the application will be executed only
00412         once in a process lifetime.  This is the case for CGI for example,
00413         but it's not guaranteed that the exeuction only happens one time.''')
00414 
00415 
00416 class BaseResponse(object):
00417     """Base response class.  The most important fact about a response object
00418     is that it's a regular WSGI application.  It's initialized with a couple
00419     of response parameters (headers, body, status code etc.) and will start a
00420     valid WSGI response when called with the environ and start response
00421     callable.
00422 
00423     Because it's a WSGI application itself processing usually ends before the
00424     actual response is sent to the server.  This helps debugging systems
00425     because they can catch all the exceptions before responses are started.
00426 
00427     Here a small example WSGI application that takes advantage of the
00428     response objects::
00429 
00430         from werkzeug import BaseResponse as Response
00431 
00432         def index():
00433             return Response('Index page')
00434 
00435         def application(environ, start_response):
00436             path = environ.get('PATH_INFO') or '/'
00437             if path == '/':
00438                 response = index()
00439             else:
00440                 response = Response('Not Found', status=404)
00441             return response(environ, start_response)
00442 
00443     Like :class:`BaseRequest` which object is lacking a lot of functionality
00444     implemented in mixins.  This gives you a better control about the actual
00445     API of your response objects, so you can create subclasses and add custom
00446     functionality.  A full featured response object is available as
00447     :class:`Response` which implements a couple of useful mixins.
00448 
00449     To enforce a new type of already existing responses you can use the
00450     :meth:`force_type` method.  This is useful if you're working with different
00451     subclasses of response objects and you want to post process them with a
00452     know interface.
00453 
00454     Per default the request object will assume all the text data is `utf-8`
00455     encoded.  Please refer to `the unicode chapter <unicode.txt>`_ for more
00456     details about customizing the behavior.
00457 
00458     Response can be any kind of iterable or string.  If it's a string
00459     it's considered being an iterable with one item which is the string
00460     passed.  Headers can be a list of tuples or a :class:`Headers` object.
00461 
00462     Special note for `mimetype` and `content_type`:  For most mime types
00463     `mimetype` and `content_type` work the same, the difference affects
00464     only 'text' mimetypes.  If the mimetype passed with `mimetype` is a
00465     mimetype starting with `text/` it becomes a charset parameter defined
00466     with the charset of the response object.  In contrast the
00467     `content_type` parameter is always added as header unmodified.
00468 
00469     .. versionchanged:: 0.5
00470        the `direct_passthrough` parameter was added.
00471 
00472     :param response: a string or response iterable.
00473     :param status: a string with a status or an integer with the status code.
00474     :param headers: a list of headers or an :class:`Headers` object.
00475     :param mimetype: the mimetype for the request.  See notice above.
00476     :param content_type: the content type for the request.  See notice above.
00477     :param direct_passthrough: if set to `True` :meth:`iter_encoded` is not
00478                                called before iteration which makes it
00479                                possible to pass special iterators though
00480                                unchanged (see :func:`wrap_file` for more
00481                                details.)
00482     """
00483     charset = 'utf-8'
00484     default_status = 200
00485     default_mimetype = 'text/plain'
00486 
00487     def __init__(self, response=None, status=None, headers=None,
00488                  mimetype=None, content_type=None, direct_passthrough=False):
00489         if response is None:
00490             self.response = []
00491         elif isinstance(response, basestring):
00492             self.response = [response]
00493         else:
00494             self.response = iter(response)
00495         if not headers:
00496             self.headers = Headers()
00497         elif isinstance(headers, Headers):
00498             self.headers = headers
00499         else:
00500             self.headers = Headers(headers)
00501         if content_type is None:
00502             if mimetype is None and 'Content-Type' not in self.headers:
00503                 mimetype = self.default_mimetype
00504             if mimetype is not None:
00505                 mimetype = get_content_type(mimetype, self.charset)
00506             content_type = mimetype
00507         if content_type is not None:
00508             self.headers['Content-Type'] = content_type
00509         if status is None:
00510             status = self.default_status
00511         if isinstance(status, (int, long)):
00512             self.status_code = status
00513         else:
00514             self.status = status
00515         self.direct_passthrough = direct_passthrough
00516 
00517     @classmethod
00518     def force_type(cls, response, environ=None):
00519         """Enforce that the WSGI response is a response object of the current
00520         type.  Werkzeug will use the :class:`BaseResponse` internally in many
00521         situations like the exceptions.  If you call :meth:`get_response` on an
00522         exception you will get back a regular :class:`BaseResponse` object, even
00523         if you are using a custom subclass.
00524 
00525         This method can enforce a given response type, and it will also
00526         convert arbitrary WSGI callables into response objects if an environ
00527         is provided::
00528 
00529             # convert a Werkzeug response object into an instance of the
00530             # MyResponseClass subclass.
00531             response = MyResponseClass.force_type(response)
00532 
00533             # convert any WSGI application into a response object
00534             response = MyResponseClass.force_type(response, environ)
00535 
00536         This is especially useful if you want to post-process responses in
00537         the main dispatcher and use functionality provided by your subclass.
00538 
00539         Keep in mind that this will modify response objects in place if
00540         possible!
00541 
00542         :param response: a response object or wsgi application.
00543         :param environ: a WSGI environment object.
00544         :return: a response object.
00545         """
00546         if not isinstance(response, BaseResponse):
00547             if environ is None:
00548                 raise TypeError('cannot convert WSGI application into '
00549                                 'response objects without an environ')
00550             response = BaseResponse(*run_wsgi_app(response, environ))
00551         response.__class__ = cls
00552         return response
00553 
00554     @classmethod
00555     def from_app(cls, app, environ, buffered=False):
00556         """Create a new response object from an application output.  This
00557         works best if you pass it an application that returns a generator all
00558         the time.  Sometimes applications may use the `write()` callable
00559         returned by the `start_response` function.  This tries to resolve such
00560         edge cases automatically.  But if you don't get the expected output
00561         you should set `buffered` to `True` which enforces buffering.
00562 
00563         :param app: the WSGI application to execute.
00564         :param environ: the WSGI environment to execute against.
00565         :param buffered: set to `True` to enforce buffering.
00566         :return: a response object.
00567         """
00568         return cls(*run_wsgi_app(app, environ, buffered))
00569 
00570     def _get_status_code(self):
00571         try:
00572             return int(self.status.split(None, 1)[0])
00573         except ValueError:
00574             return 0
00575     def _set_status_code(self, code):
00576         try:
00577             self.status = '%d %s' % (code, HTTP_STATUS_CODES[code].upper())
00578         except KeyError:
00579             self.status = '%d UNKNOWN' % code
00580     status_code = property(_get_status_code, _set_status_code,
00581                            'The HTTP Status code as number')
00582     del _get_status_code, _set_status_code
00583 
00584     def _get_data(self):
00585         """The string representation of the request body.  Whenever you access
00586         this property the request iterable is encoded and flattened.  This
00587         can lead to unwanted behavior if you stream big data.
00588         """
00589         if not isinstance(self.response, list):
00590             self.response = list(self.response)
00591         return ''.join(self.iter_encoded())
00592     def _set_data(self, value):
00593         self.response = [value]
00594     data = property(_get_data, _set_data, doc=_get_data.__doc__)
00595     del _get_data, _set_data
00596 
00597     def iter_encoded(self, charset=None):
00598         """Iter the response encoded with the encoding specified.  If no
00599         encoding is given the encoding from the class is used.  Note that
00600         this does not encode data that is already a bytestring.  If the
00601         response object is invoked as WSGI application the return value
00602         of this method is used as application iterator except if
00603         :attr:`direct_passthrough` was activated.
00604         """
00605         charset = charset or self.charset or 'ascii'
00606         for item in self.response:
00607             if isinstance(item, unicode):
00608                 yield item.encode(charset)
00609             else:
00610                 yield str(item)
00611 
00612     def set_cookie(self, key, value='', max_age=None, expires=None,
00613                    path='/', domain=None, secure=None, httponly=False):
00614         """Sets a cookie. The parameters are the same as in the cookie `Morsel`
00615         object in the Python standard library but it accepts unicode data, too.
00616 
00617         :param key: the key (name) of the cookie to be set.
00618         :param value: the value of the cookie.
00619         :param max_age: should be a number of seconds, or `None` (default) if
00620                         the cookie should last only as long as the client's
00621                         browser session.
00622         :param expires: should be a `datetime` object or UNIX timestamp.
00623         :param domain: if you want to set a cross-domain cookie.  For example,
00624                        ``domain=".example.com"`` will set a cookie that is
00625                        readable by the domain ``www.example.com``,
00626                        ``foo.example.com`` etc.  Otherwise, a cookie will only
00627                        be readable by the domain that set it.
00628         :param path: limits the cookie to a given path, per default it will
00629                      span the whole domain.
00630         """
00631         self.headers.add('Set-Cookie', dump_cookie(key, value, max_age,
00632                          expires, path, domain, secure, httponly,
00633                          self.charset))
00634 
00635     def delete_cookie(self, key, path='/', domain=None):
00636         """Delete a cookie.  Fails silently if key doesn't exist.
00637 
00638         :param key: the key (name) of the cookie to be deleted.
00639         :param path: if the cookie that should be deleted was limited to a
00640                      path, the path has to be defined here.
00641         :param domain: if the cookie that should be deleted was limited to a
00642                        domain, that domain has to be defined here.
00643         """
00644         self.set_cookie(key, expires=0, max_age=0, path=path, domain=domain)
00645 
00646     @property
00647     def header_list(self):
00648         """This returns the headers in the target charset as list.  It's used
00649         in __call__ to get the headers for the response.
00650         """
00651         return self.headers.to_list(self.charset)
00652 
00653     @property
00654     def is_streamed(self):
00655         """If the response is streamed (the response is not a sequence) this
00656         property is `True`.  In this case streamed means that there is no
00657         information about the number of iterations.  This is usully `True`
00658         if a generator is passed to the response object.
00659 
00660         This is useful for checking before applying some sort of post
00661         filtering that should not take place for streamed responses.
00662         """
00663         try:
00664             len(self.response)
00665         except TypeError:
00666             return False
00667         return True
00668 
00669     def fix_headers(self, environ):
00670         """This is automatically called right before the response is started
00671         and should fix common mistakes in headers.  For example location
00672         headers are joined with the root URL here.
00673 
00674         :param environ: the WSGI environment of the request to be used for
00675                         the applied fixes.
00676         """
00677         if 'Location' in self.headers:
00678             self.headers['Location'] = urlparse.urljoin(
00679                 get_current_url(environ, root_only=True),
00680                 self.headers['Location']
00681             )
00682         if 100 <= self.status_code < 200 or self.status_code == 204:
00683             self.headers['Content-Length'] = 0
00684         elif self.status_code == 304:
00685             remove_entity_headers(self.headers)
00686 
00687     def close(self):
00688         """Close the wrapped response if possible."""
00689         if hasattr(self.response, 'close'):
00690             self.response.close()
00691 
00692     def freeze(self):
00693         """Call this method if you want to make your response object ready for
00694         being pickled.  This buffers the generator if there is one.
00695         """
00696         BaseResponse.data.__get__(self)
00697 
00698     def __call__(self, environ, start_response):
00699         """Process this response as WSGI application.
00700 
00701         :param environ: the WSGI environment.
00702         :param start_response: the response callable provided by the WSGI
00703                                server.
00704         """
00705         self.fix_headers(environ)
00706         if environ['REQUEST_METHOD'] == 'HEAD':
00707             resp = ()
00708         elif 100 <= self.status_code < 200 or self.status_code in (204, 304):
00709             # no response for 204/304.  the headers are adapted accordingly
00710             # by fix_headers()
00711             resp = ()
00712         elif self.direct_passthrough:
00713             resp = self.response
00714         else:
00715             resp = self.iter_encoded()
00716         start_response(self.status, self.header_list)
00717         return resp
00718 
00719 
00720 class AcceptMixin(object):
00721     """A mixin for classes with an :attr:`~BaseResponse.environ` attribute to
00722     get all the HTTP accept headers as :class:`Accept` objects (or subclasses
00723     thereof).
00724     """
00725 
00726     @cached_property
00727     def accept_mimetypes(self):
00728         """List of mimetypes this client supports as :class:`MIMEAccept`
00729         object.
00730         """
00731         return parse_accept_header(self.environ.get('HTTP_ACCEPT'), MIMEAccept)
00732 
00733     @cached_property
00734     def accept_charsets(self):
00735         """List of charsets this client supports as :class:`CharsetAccept`
00736         object.
00737         """
00738         return parse_accept_header(self.environ.get('HTTP_ACCEPT_CHARSET'),
00739                                    CharsetAccept)
00740 
00741     @cached_property
00742     def accept_encodings(self):
00743         """List of encodings this client accepts.  Encodings in a HTTP term
00744         are compression encodings such as gzip.  For charsets have a look at
00745         :attr:`accept_charset`.
00746         """
00747         return parse_accept_header(self.environ.get('HTTP_ACCEPT_ENCODING'))
00748 
00749     @cached_property
00750     def accept_languages(self):
00751         """List of languages this client accepts as :class:`LanguageAccept`
00752         object.
00753 
00754         .. versionchanged 0.5
00755            In previous versions this was a regualr :class:`Accept` object.
00756         """
00757         return parse_accept_header(self.environ.get('HTTP_ACCEPT_LANGUAGE'),
00758                                    LanguageAccept)
00759 
00760 
00761 class ETagRequestMixin(object):
00762     """Add entity tag and cache descriptors to a request object or object with
00763     a WSGI environment available as :attr:`~BaseRequest.environ`.  This not
00764     only provides access to etags but also to the cache control header.
00765     """
00766 
00767     @cached_property
00768     def cache_control(self):
00769         """A :class:`RequestCacheControl` object for the incoming cache control
00770         headers.
00771         """
00772         cache_control = self.environ.get('HTTP_CACHE_CONTROL')
00773         return parse_cache_control_header(cache_control, None,
00774                                           RequestCacheControl)
00775 
00776     @cached_property
00777     def if_match(self):
00778         """An object containing all the etags in the `If-Match` header."""
00779         return parse_etags(self.environ.get('HTTP_IF_MATCH'))
00780 
00781     @cached_property
00782     def if_none_match(self):
00783         """An object containing all the etags in the `If-None-Match` header."""
00784         return parse_etags(self.environ.get('HTTP_IF_NONE_MATCH'))
00785 
00786     @cached_property
00787     def if_modified_since(self):
00788         """The parsed `If-Modified-Since` header as datetime object."""
00789         return parse_date(self.environ.get('HTTP_IF_MODIFIED_SINCE'))
00790 
00791     @cached_property
00792     def if_unmodified_since(self):
00793         """The parsed `If-Unmodified-Since` header as datetime object."""
00794         return parse_date(self.environ.get('HTTP_IF_UNMODIFIED_SINCE'))
00795 
00796 
00797 class UserAgentMixin(object):
00798     """Adds a `user_agent` attribute to the request object which contains the
00799     parsed user agent of the browser that triggered the request as `UserAgent`
00800     object.
00801     """
00802 
00803     # this class actually belongs to a different module.  For more details
00804     # have a look at `werkzeug.useragents`.  On the bottom of that module is
00805     # a small comment that explains it.
00806     __module__ = 'werkzeug.useragents'
00807 
00808     @cached_property
00809     def user_agent(self):
00810         """The current user agent."""
00811         from werkzeug.useragents import UserAgent
00812         return UserAgent(self.environ)
00813 
00814 
00815 class AuthorizationMixin(object):
00816     """Adds an :attr:`authorization` property that represents the parsed value
00817     of the `Authorization` header as :class:`Authorization` object.
00818     """
00819 
00820     @cached_property
00821     def authorization(self):
00822         """The `Authorization` object in parsed form."""
00823         header = self.environ.get('HTTP_AUTHORIZATION')
00824         return parse_authorization_header(header)
00825 
00826 
00827 class ETagResponseMixin(object):
00828     """Adds extra functionality to a response object for etag and cache
00829     handling.  This mixin requires an object with at least a `headers`
00830     object that implements a dict like interface similar to :class:`Headers`.
00831     """
00832 
00833     @property
00834     def cache_control(self):
00835         """The Cache-Control general-header field is used to specify
00836         directives that MUST be obeyed by all caching mechanisms along the
00837         request/response chain.
00838         """
00839         def on_update(cache_control):
00840             if not cache_control and 'cache-control' in self.headers:
00841                 del self.headers['cache-control']
00842             elif cache_control:
00843                 self.headers['Cache-Control'] = cache_control.to_header()
00844         return parse_cache_control_header(self.headers.get('cache-control'),
00845                                           on_update,
00846                                           ResponseCacheControl)
00847 
00848     def make_conditional(self, request_or_environ):
00849         """Make the response conditional to the request.  This method works
00850         best if an etag was defined for the response already.  The `add_etag`
00851         method can be used to do that.  If called without etag just the date
00852         header is set.
00853 
00854         This does nothing if the request method in the request or environ is
00855         anything but GET or HEAD.
00856 
00857         It does not remove the body of the response because that's something
00858         the :meth:`__call__` function does for us automatically.
00859 
00860         Returns self so that you can do ``return resp.make_conditional(req)``
00861         but modifies the object in-place.
00862 
00863         :param request_or_environ: a request object or WSGI environment to be
00864                                    used to make the response conditional
00865                                    against.
00866         """
00867         environ = getattr(request_or_environ, 'environ', request_or_environ)
00868         if environ['REQUEST_METHOD'] in ('GET', 'HEAD'):
00869             self.headers['Date'] = http_date()
00870             if 'content-length' in self.headers:
00871                 self.headers['Content-Length'] = len(self.data)
00872             if not is_resource_modified(environ, self.headers.get('etag'), None,
00873                                         self.headers.get('last-modified')):
00874                 self.status_code = 304
00875         return self
00876 
00877     def add_etag(self, overwrite=False, weak=False):
00878         """Add an etag for the current response if there is none yet."""
00879         if overwrite or 'etag' not in self.headers:
00880             self.set_etag(generate_etag(self.data), weak)
00881 
00882     def set_etag(self, etag, weak=False):
00883         """Set the etag, and override the old one if there was one."""
00884         self.headers['ETag'] = quote_etag(etag, weak)
00885 
00886     def get_etag(self):
00887         """Return a tuple in the form ``(etag, is_weak)``.  If there is no
00888         ETag the return value is ``(None, None)``.
00889         """
00890         return unquote_etag(self.headers.get('ETag'))
00891 
00892     def freeze(self, no_etag=False):
00893         """Call this method if you want to make your response object ready for
00894         pickeling.  This buffers the generator if there is one.  This also
00895         sets the etag unless `no_etag` is set to `True`.
00896         """
00897         if not no_etag:
00898             self.add_etag()
00899         super(ETagResponseMixin, self).freeze()
00900 
00901 
00902 class ResponseStream(object):
00903     """A file descriptor like object used by the :class:`ResponseStreamMixin` to
00904     represent the body of the stream.  It directly pushes into the response
00905     iterable of the response object.
00906     """
00907 
00908     mode = 'wb+'
00909 
00910     def __init__(self, response):
00911         self.response = response
00912         self.closed = False
00913 
00914     def write(self, value):
00915         if self.closed:
00916             raise ValueError('I/O operation on closed file')
00917         buf = self.response.response
00918         if not isinstance(buf, list):
00919             self.response.response = buf = list(buf)
00920         buf.append(value)
00921 
00922     def writelines(self, seq):
00923         for item in seq:
00924             self.write(item)
00925 
00926     def close(self):
00927         self.closed = True
00928 
00929     def flush(self):
00930         if self.closed:
00931             raise ValueError('I/O operation on closed file')
00932 
00933     def isatty(self):
00934         if self.closed:
00935             raise ValueError('I/O operation on closed file')
00936         return False
00937 
00938     @property
00939     def encoding(self):
00940         return self.response.charset
00941 
00942 
00943 class ResponseStreamMixin(object):
00944     """Mixin for :class:`BaseRequest` subclasses.  Classes that inherit from
00945     this mixin will automatically get a :attr:`stream` property that provides
00946     a write-only interface to the response iterable.
00947     """
00948 
00949     @cached_property
00950     def stream(self):
00951         """The response iterable as write-only stream."""
00952         return ResponseStream(self)
00953 
00954 
00955 class CommonRequestDescriptorsMixin(object):
00956     """A mixin for :class:`BaseRequest` subclasses.  Request objects that
00957     mix this class in will automatically get descriptors for a coupl eof
00958     HTTP headers with automatic type conversion.
00959 
00960     .. versionadded:: 0.5
00961     """
00962 
00963     content_type = environ_property('CONTENT_TYPE', doc='''
00964          The Content-Type entity-header field indicates the media type of
00965          the entity-body sent to the recipient or, in the case of the HEAD
00966          method, the media type that would have been sent had the request
00967          been a GET.''')
00968     content_length = environ_property('CONTENT_LENGTH', None, int, str, doc='''
00969          The Content-Length entity-header field indicates the size of the
00970          entity-body in bytes or, in the case of the HEAD method, the size of
00971          the entity-body that would have been sent had the request been a
00972          GET.''')
00973     referrer = environ_property('HTTP_REFERER', doc='''
00974         The Referer[sic] request-header field allows the client to specify,
00975         for the server's benefit, the address (URI) of the resource from which
00976         the Request-URI was obtained (the "referrer", although the header
00977         field is misspelled).''')
00978     date = environ_property('HTTP_DATE', None, parse_date, doc='''
00979         The Date general-header field represents the date and time at which
00980         the message was originated, having the same semantics as orig-date
00981         in RFC 822.''')
00982     max_forwards = environ_property('HTTP_MAX_FORWARDS', None, int, doc='''
00983          The Max-Forwards request-header field provides a mechanism with the
00984          TRACE and OPTIONS methods to limit the number of proxies or gateways
00985          that can forward the request to the next inbound server.''')
00986 
00987     def _parse_content_type(self):
00988         if not hasattr(self, '_parsed_content_type'):
00989             self._parsed_content_type = \
00990                 parse_options_header(self.environ.get('CONTENT_TYPE', ''))
00991 
00992     @property
00993     def mimetype(self):
00994         """Like :attr:`content_type` but without parameters (eg, without
00995         charset, type etc.).  For example if the content
00996         type is ``text/html; charset=utf-8`` the mimetype would be
00997         ``'text/html'``.
00998         """
00999         self._parse_content_type()
01000         return self._parsed_content_type[0]
01001 
01002     @property
01003     def mimetype_params(self):
01004         """The mimetype parameters as dict.  For example if the content
01005         type is ``text/html; charset=utf-8`` the params would be
01006         ``{'charset': 'utf-8'}``.
01007         """
01008         self._parse_content_type()
01009         return self._parsed_content_type[1]
01010 
01011     @cached_property
01012     def pragma(self):
01013         """The Pragma general-header field is used to include
01014         implementation-specific directives that might apply to any recipient
01015         along the request/response chain.  All pragma directives specify
01016         optional behavior from the viewpoint of the protocol; however, some
01017         systems MAY require that behavior be consistent with the directives.
01018         """
01019         return parse_set_header(self.environ.get('HTTP_PRAGMA', ''))
01020 
01021 
01022 class CommonResponseDescriptorsMixin(object):
01023     """A mixin for :class:`BaseResponse` subclasses.  Response objects that
01024     mix this class in will automatically get descriptors for a couple of
01025     HTTP headers with automatic type conversion.
01026     """
01027 
01028     def _get_mimetype(self):
01029         ct = self.headers.get('content-type')
01030         if ct:
01031             return ct.split(';')[0].strip()
01032 
01033     def _set_mimetype(self, value):
01034         self.headers['Content-Type'] = get_content_type(value, self.charset)
01035 
01036     def _get_mimetype_params(self):
01037         def on_update(d):
01038             self.headers['Content-Type'] = \
01039                 dump_options_header(self.mimetype, d)
01040         d = parse_options_header(self.headers.get('content-type', ''))[1]
01041         return CallbackDict(d, on_update)
01042 
01043     mimetype = property(_get_mimetype, _set_mimetype, doc='''
01044         The mimetype (content type without charset etc.)''')
01045     mimetype_params = property(_get_mimetype_params, doc='''
01046         The mimetype parameters as dict.  For example if the content
01047         type is ``text/html; charset=utf-8`` the params would be
01048         ``{'charset': 'utf-8'}``.
01049 
01050         .. versionadded:: 0.5
01051         ''')
01052     location = header_property('Location', doc='''
01053         The Location response-header field is used to redirect the recipient
01054         to a location other than the Request-URI for completion of the request
01055         or identification of a new resource.''')
01056     age = header_property('Age', None, parse_date, http_date, doc='''
01057         The Age response-header field conveys the sender's estimate of the
01058         amount of time since the response (or its revalidation) was
01059         generated at the origin server.
01060 
01061         Age values are non-negative decimal integers, representing time in
01062         seconds.''')
01063     content_type = header_property('Content-Type', doc='''
01064         The Content-Type entity-header field indicates the media type of the
01065         entity-body sent to the recipient or, in the case of the HEAD method,
01066         the media type that would have been sent had the request been a GET.
01067     ''')
01068     content_length = header_property('Content-Length', None, int, str, doc='''
01069         The Content-Length entity-header field indicates the size of the
01070         entity-body, in decimal number of OCTETs, sent to the recipient or,
01071         in the case of the HEAD method, the size of the entity-body that would
01072         have been sent had the request been a GET.''')
01073     content_location = header_property('Content-Location', doc='''
01074         The Content-Location entity-header field MAY be used to supply the
01075         resource location for the entity enclosed in the message when that
01076         entity is accessible from a location separate from the requested
01077         resource's URI.''')
01078     content_encoding = header_property('Content-Encoding', doc='''
01079         The Content-Encoding entity-header field is used as a modifier to the
01080         media-type.  When present, its value indicates what additional content
01081         codings have been applied to the entity-body, and thus what decoding
01082         mechanisms must be applied in order to obtain the media-type
01083         referenced by the Content-Type header field.''')
01084     content_md5 = header_property('Content-MD5', doc='''
01085          The Content-MD5 entity-header field, as defined in RFC 1864, is an
01086          MD5 digest of the entity-body for the purpose of providing an
01087          end-to-end message integrity check (MIC) of the entity-body.  (Note:
01088          a MIC is good for detecting accidental modification of the
01089          entity-body in transit, but is not proof against malicious attacks.)
01090         ''')
01091     date = header_property('Date', None, parse_date, http_date, doc='''
01092         The Date general-header field represents the date and time at which
01093         the message was originated, having the same semantics as orig-date
01094         in RFC 822.''')
01095     expires = header_property('Expires', None, parse_date, http_date, doc='''
01096         The Expires entity-header field gives the date/time after which the
01097         response is considered stale. A stale cache entry may not normally be
01098         returned by a cache.''')
01099     last_modified = header_property('Last-Modified', None, parse_date,
01100                                     http_date, doc='''
01101         The Last-Modified entity-header field indicates the date and time at
01102         which the origin server believes the variant was last modified.''')
01103 
01104     def _get_retry_after(self):
01105         value = self.headers.get('retry-after')
01106         if value is None:
01107             return
01108         elif value.isdigit():
01109             return datetime.utcnow() + timedelta(seconds=int(value))
01110         return parse_date(value)
01111     def _set_retry_after(self, value):
01112         if value is None:
01113             if 'retry-after' in self.headers:
01114                 del self.headers['retry-after']
01115             return
01116         elif isinstance(value, datetime):
01117             value = http_date(value)
01118         else:
01119             value = str(value)
01120         self.headers['Retry-After'] = value
01121 
01122     retry_after = property(_get_retry_after, _set_retry_after, doc='''
01123         The Retry-After response-header field can be used with a 503 (Service
01124         Unavailable) response to indicate how long the service is expected
01125         to be unavailable to the requesting client.
01126 
01127         Time in seconds until expiration or date.''')
01128 
01129     def _set_property(name, doc=None):
01130         def fget(self):
01131             def on_update(header_set):
01132                 if not header_set and name in self.headers:
01133                     del self.headers[name]
01134                 elif header_set:
01135                     self.headers[name] = header_set.to_header()
01136             return parse_set_header(self.headers.get(name), on_update)
01137         return property(fget, doc=doc)
01138 
01139     vary = _set_property('Vary', doc='''
01140          The Vary field value indicates the set of request-header fields that
01141          fully determines, while the response is fresh, whether a cache is
01142          permitted to use the response to reply to a subsequent request
01143          without revalidation.''')
01144     content_language = _set_property('Content-Language', doc='''
01145          The Content-Language entity-header field describes the natural
01146          language(s) of the intended audience for the enclosed entity.  Note
01147          that this might not be equivalent to all the languages used within
01148          the entity-body.''')
01149     allow = _set_property('Allow', doc='''
01150         The Allow entity-header field lists the set of methods supported
01151         by the resource identified by the Request-URI. The purpose of this
01152         field is strictly to inform the recipient of valid methods
01153         associated with the resource. An Allow header field MUST be
01154         present in a 405 (Method Not Allowed) response.''')
01155 
01156     del _set_property, _get_mimetype, _set_mimetype, _get_retry_after, \
01157         _set_retry_after
01158 
01159 
01160 class WWWAuthenticateMixin(object):
01161     """Adds a :attr:`www_authenticate` property to a response object."""
01162 
01163     @property
01164     def www_authenticate(self):
01165         """The `WWW-Authenticate` header in a parsed form."""
01166         def on_update(www_auth):
01167             if not www_auth and 'www-authenticate' in self.headers:
01168                 del self.headers['www-authenticate']
01169             elif www_auth:
01170                 self.headers['WWW-Authenticate'] = www_auth.to_header()
01171         header = self.headers.get('www-authenticate')
01172         return parse_www_authenticate_header(header, on_update)
01173 
01174 
01175 class Request(BaseRequest, AcceptMixin, ETagRequestMixin,
01176               UserAgentMixin, AuthorizationMixin,
01177               CommonRequestDescriptorsMixin):
01178     """Full featured request object implementing the following mixins:
01179 
01180     - :class:`AcceptMixin` for accept header parsing
01181     - :class:`ETagRequestMixin` for etag and cache control handling
01182     - :class:`UserAgentMixin` for user agent introspection
01183     - :class:`AuthorizationMixin` for http auth handling
01184     - :class:`CommonRequestDescriptorsMixin` for common headers
01185     """
01186 
01187 
01188 class Response(BaseResponse, ETagResponseMixin, ResponseStreamMixin,
01189                CommonResponseDescriptorsMixin,
01190                WWWAuthenticateMixin):
01191     """Full featured response object implementing the following mixins:
01192 
01193     - :class:`ETagResponseMixin` for etag and cache control handling
01194     - :class:`ResponseStreamMixin` to add support for the `stream` property
01195     - :class:`CommonResponseDescriptorsMixin` for various HTTP descriptors
01196     - :class:`WWWAuthenticateMixin` for HTTP authentication support
01197     """