1
# -*- coding: utf-8 -*-
6
The wrappers are simple request and response objects which you can
7
subclass to do whatever you want them to do. The request object contains
8
the information transmitted by the client (webbrowser) and the response
9
object contains all the information sent back to the browser.
11
An important detail is that the request object is created with the WSGI
12
environ and will act as high-level proxy whereas the response object is an
13
actual WSGI application.
15
Like everything else in Werkzeug these objects will work correctly with
16
unicode data. Incoming form data parsed by the response object will be
17
decoded into an unicode object if possible and if it makes sense.
20
:copyright: (c) 2009 by the Werkzeug Team, see AUTHORS for more details.
21
:license: BSD, see LICENSE for more details.
25
from datetime import datetime, timedelta
26
from werkzeug.http import HTTP_STATUS_CODES, \
27
parse_accept_header, parse_cache_control_header, parse_etags, \
28
parse_date, generate_etag, is_resource_modified, unquote_etag, \
29
quote_etag, parse_set_header, parse_authorization_header, \
30
parse_www_authenticate_header, remove_entity_headers, \
31
default_stream_factory, parse_options_header, \
33
from werkzeug.utils import cached_property, environ_property, \
34
get_current_url, url_encode, run_wsgi_app, get_host, \
35
cookie_date, parse_cookie, dump_cookie, http_date, escape, \
36
header_property, parse_form_data, get_content_type, url_decode
37
from werkzeug.datastructures import MultiDict, CombinedMultiDict, Headers, \
38
EnvironHeaders, ImmutableMultiDict, ImmutableTypeConversionDict, \
39
ImmutableList, MIMEAccept, CharsetAccept, LanguageAccept, \
40
ResponseCacheControl, RequestCacheControl, CallbackDict
41
from werkzeug._internal import _empty_stream, _decode_unicode, \
45
class BaseRequest(object):
46
"""Very basic request object. This does not implement advanced stuff like
47
entity tag parsing or cache controls. The request object is created with
48
the WSGI environment as first argument and will add itself to the WSGI
49
environment as ``'werkzeug.request'`` unless it's created with
50
`populate_request` set to False.
52
There are a couple of mixins available that add additional functionality
53
to the request object, there is also a class called `Request` which
54
subclasses `BaseRequest` and all the important mixins.
56
It's a good idea to create a custom subclass of the :class:`BaseRequest`
57
and add missing functionality either via mixins or direct implementation.
58
Here an example for such subclasses::
60
from werkzeug import BaseRequest, ETagRequestMixin
62
class Request(BaseRequest, ETagRequestMixin):
65
Request objects are **read only**. As of 0.5 modifications are not
66
allowed in any place. Unlike the lower level parsing functions the
67
request object will use immutable objects everywhere possible.
69
Per default the request object will assume all the text data is `utf-8`
70
encoded. Please refer to `the unicode chapter <unicode.txt>`_ for more
71
details about customizing the behavior.
73
Per default the request object will be added to the WSGI
74
environment as `werkzeug.request` to support the debugging system.
75
If you don't want that, set `populate_request` to `False`.
77
If `shallow` is `True` the environment is initialized as shallow
78
object around the environ. Every operation that would modify the
79
environ in any way (such as consuming form data) raises an exception
80
unless the `shallow` attribute is explicitly set to `False`. This
81
is useful for middlewares where you don't want to consume the form
82
data by accident. A shallow request is not populated to the WSGI
85
.. versionchanged:: 0.5
86
read-only mode was enforced by using immutables classes for all
90
#: the charset for the request, defaults to utf-8
93
#: the error handling procedure for errors, defaults to 'ignore'
94
encoding_errors = 'ignore'
96
#: set to True if the application runs behind an HTTP proxy
97
is_behind_proxy = False
99
#: the maximum content length. This is forwarded to the form data
100
#: parsing function (:func:`parse_form_data`). When set and the
101
#: :attr:`form` or :attr:`files` attribute is accessed and the
102
#: parsing fails because more than the specified value is transmitted
103
#: a :exc:`~exceptions.RequestEntityTooLarge` exception is raised.
105
#: Have a look at :ref:`dealing-with-request-data` for more details.
107
#: .. versionadded:: 0.5
108
max_content_length = None
110
#: the maximum form field size. This is forwarded to the form data
111
#: parsing function (:func:`parse_form_data`). When set and the
112
#: :attr:`form` or :attr:`files` attribute is accessed and the
113
#: data in memory for post data is longer than the specified value a
114
#: :exc:`~exceptions.RequestEntityTooLarge` exception is raised.
116
#: Have a look at :ref:`dealing-with-request-data` for more details.
118
#: .. versionadded:: 0.5
119
max_form_memory_size = None
121
def __init__(self, environ, populate_request=True, shallow=False):
122
self.environ = environ
123
if populate_request and not shallow:
124
self.environ['werkzeug.request'] = self
125
self.shallow = shallow
126
self._data_stream = None
129
def from_values(cls, *args, **kwargs):
130
"""Create a new request object based on the values provided. If
131
environ is given missing values are filled from there. This method is
132
useful for small scripts when you need to simulate a request from an URL.
133
Do not use this method for unittesting, there is a full featured client
134
object (:class:`Client`) that allows to create multipart requests,
135
support for cookies etc.
137
This accepts the same options as the :class:`EnvironBuilder`.
139
.. versionchanged:: 0.5
140
This method now accepts the same arguments as
141
:class:`EnvironBuilder`. Because of this the `environ` parameter
142
is now called `environ_overrides`.
144
:return: request object
146
from werkzeug.test import EnvironBuilder
147
charset = kwargs.pop('charset', cls.charset)
148
environ = kwargs.pop('environ', None)
149
if environ is not None:
150
from warnings import warn
151
warn(DeprecationWarning('The environ parameter to from_values'
152
' is now called environ_overrides for'
153
' consistency with EnvironBuilder'),
155
kwargs['environ_overrides'] = environ
156
builder = EnvironBuilder(*args, **kwargs)
158
return builder.get_request(cls)
163
def application(cls, f):
164
"""Decorate a function as responder that accepts the request as first
165
argument. This works like the :func:`responder` decorator but the
166
function is passed the request object as first argument::
169
def my_wsgi_app(request):
170
return Response('Hello World!')
172
:param f: the WSGI callable to decorate
173
:return: a new WSGI callable
175
#: return a callable that wraps the -2nd argument with the request
176
#: and calls the function with all the arguments up to that one and
177
#: the request. The return value is then called with the latest
178
#: two arguments. This makes it possible to use this decorator for
179
#: both methods and standalone WSGI functions.
180
return _patch_wrapper(f, lambda *a: f(*a[:-2]+(cls(a[-2]),))(*a[-2:]))
182
def _get_file_stream(self, total_content_length, content_type, filename=None,
183
content_length=None):
184
"""Called to get a stream for the file upload.
186
This must provide a file-like class with `read()`, `readline()`
187
and `seek()` methods that is both writeable and readable.
189
The default implementation returns a temporary file if the total
190
content length is higher than 500KB. Because many browsers do not
191
provide a content length for the files only the total content
194
.. versionchanged:: 0.5
195
Previously this function was not passed any arguments. In 0.5 older
196
functions not accepting any arguments are still supported for
197
backwards compatibility.
199
:param total_content_length: the total content length of all the
200
data in the request combined. This value
201
is guaranteed to be there.
202
:param content_type: the mimetype of the uploaded file.
203
:param filename: the filename of the uploaded file. May be `None`.
204
:param content_length: the length of this file. This value is usually
205
not provided because webbrowsers do not provide
208
return default_stream_factory(total_content_length, content_type,
209
filename, content_length)
211
def _load_form_data(self):
212
"""Method used internally to retrieve submitted data. After calling
213
this sets `_form` and `_files` on the request object to multi dicts
214
filled with the incoming form data. As a matter of fact the input
215
stream will be empty afterwards.
219
if self._data_stream is None:
221
raise RuntimeError('A shallow request tried to consume '
222
'form data. If you really want to do '
223
'that, set `shallow` to False.')
225
if self.environ['REQUEST_METHOD'] in ('POST', 'PUT'):
227
data = parse_form_data(self.environ, self._get_file_stream,
228
self.charset, self.encoding_errors,
229
self.max_form_memory_size,
230
self.max_content_length,
231
cls=ImmutableMultiDict,
233
except ValueError, e:
234
self._form_parsing_failed(e)
236
data = (_empty_stream, ImmutableMultiDict(),
237
ImmutableMultiDict())
238
self._data_stream, self._form, self._files = data
240
def _form_parsing_failed(self, error):
241
"""Called if parsing of form data failed. This is currently only
242
invoked for failed multipart uploads. By default this method does
245
:param error: a `ValueError` object with a message why the
248
.. versionadded:: 0.5.1
253
"""The parsed stream if the submitted data was not multipart or
254
urlencoded form data. This stream is the stream left by the form data
255
parser module after parsing. This is *not* the WSGI input stream but
256
a wrapper around it that ensures the caller does not accidentally
257
read past `Content-Length`.
259
self._load_form_data()
260
return self._data_stream
262
input_stream = environ_property('wsgi.input', 'The WSGI input stream.\n'
263
'In general it\'s a bad idea to use this one because you can easily '
264
'read past the boundary. Use the :attr:`stream` instead.')
268
"""The parsed URL parameters as :class:`ImmutableMultiDict`."""
269
return url_decode(self.environ.get('QUERY_STRING', ''), self.charset,
270
errors=self.encoding_errors,
271
cls=ImmutableMultiDict)
275
"""This reads the buffered incoming data from the client into the
276
string. Usually it's a bad idea to access :attr:`data` because a client
277
could send dozens of megabytes or more to cause memory problems on the
280
To circumvent that make sure to check the content length first.
282
return self.stream.read()
286
"""Form parameters. Currently it's not guaranteed that the
287
:class:`ImmutableMultiDict` returned by this function is ordered in
288
the same way as the submitted form data.
290
self._load_form_data()
295
"""Combined multi dict for :attr:`args` and :attr:`form`."""
296
return CombinedMultiDict([self.args, self.form])
300
""":class:`MultiDict` object containing all uploaded files. Each key in
301
:attr:`files` is the name from the ``<input type="file" name="">``. Each
302
value in :attr:`files` is a Werkzeug :class:`FileStorage` object.
304
Note that :attr:`files` will only contain data if the request method was
305
POST or PUT and the ``<form>`` that posted to the request had
306
``enctype="multipart/form-data"``. It will be empty otherwise.
308
See the :class:`MultiDict` / :class:`FileStorage` documentation for more
309
details about the used data structure.
311
self._load_form_data()
316
"""The retrieved cookie values as regular dictionary."""
317
return parse_cookie(self.environ, self.charset,
318
cls=ImmutableTypeConversionDict)
322
"""The headers from the WSGI environ as immutable
323
:class:`EnvironHeaders`.
325
return EnvironHeaders(self.environ)
329
"""Requested path as unicode. This works a bit like the regular path
330
info in the WSGI environment but will always include a leading slash,
331
even if the URL root is accessed.
333
path = '/' + (self.environ.get('PATH_INFO') or '').lstrip('/')
334
return _decode_unicode(path, self.charset, self.encoding_errors)
337
def script_root(self):
338
"""The root path of the script without the trailing slash."""
339
path = (self.environ.get('SCRIPT_NAME') or '').rstrip('/')
340
return _decode_unicode(path, self.charset, self.encoding_errors)
344
"""The reconstructed current URL"""
345
return get_current_url(self.environ)
349
"""Like :attr:`url` but without the querystring"""
350
return get_current_url(self.environ, strip_querystring=True)
354
"""The full URL root (with hostname), this is the application root."""
355
return get_current_url(self.environ, True)
359
"""Just the host with scheme."""
360
return get_current_url(self.environ, host_only=True)
364
"""Just the host including the port if available."""
365
return get_host(self.environ)
367
query_string = environ_property('QUERY_STRING', '', read_only=True, doc=
368
'''The URL parameters as raw bytestring.''')
369
method = environ_property('REQUEST_METHOD', 'GET', read_only=True, doc=
370
'''The transmission method. (For example ``'GET'`` or ``'POST'``).''')
373
def access_route(self):
374
"""If a forwarded header exists this is a list of all ip addresses
375
from the client ip to the last proxy server.
377
if 'HTTP_X_FORWARDED_FOR' in self.environ:
378
addr = self.environ['HTTP_X_FORWARDED_FOR'].split(',')
379
return ImmutableList([x.strip() for x in addr])
380
elif 'REMOTE_ADDR' in self.environ:
381
return ImmutableList([self.environ['REMOTE_ADDR']])
382
return ImmutableList()
385
def remote_addr(self):
386
"""The remote address of the client."""
387
if self.is_behind_proxy and self.access_route:
388
return self.access_route[0]
389
return self.environ.get('REMOTE_ADDR')
391
remote_user = environ_property('REMOTE_USER', doc='''
392
If the server supports user authentication, and the script is
393
protected, this attribute contains the username the user has
394
authenticated as.''')
396
is_xhr = property(lambda x: x.environ.get('HTTP_X_REQUESTED_WITH', '')
397
.lower() == 'xmlhttprequest', doc='''
398
True if the request was triggered via a JavaScript XMLHttpRequest.
399
This only works with libraries that support the `X-Requested-With`
400
header and set it to "XMLHttpRequest". Libraries that do that are
401
prototype, jQuery and Mochikit and probably some more.''')
402
is_secure = property(lambda x: x.environ['wsgi.url_scheme'] == 'https',
403
doc='`True` if the request is secure.')
404
is_multithread = environ_property('wsgi.multithread', doc='''
405
boolean that is `True` if the application is served by
406
a multithreaded WSGI server.''')
407
is_multiprocess = environ_property('wsgi.multiprocess', doc='''
408
boolean that is `True` if the application is served by
409
a WSGI server that spawns multiple processes.''')
410
is_run_once = environ_property('wsgi.run_once', doc='''
411
boolean that is `True` if the application will be executed only
412
once in a process lifetime. This is the case for CGI for example,
413
but it's not guaranteed that the exeuction only happens one time.''')
416
class BaseResponse(object):
417
"""Base response class. The most important fact about a response object
418
is that it's a regular WSGI application. It's initialized with a couple
419
of response parameters (headers, body, status code etc.) and will start a
420
valid WSGI response when called with the environ and start response
423
Because it's a WSGI application itself processing usually ends before the
424
actual response is sent to the server. This helps debugging systems
425
because they can catch all the exceptions before responses are started.
427
Here a small example WSGI application that takes advantage of the
430
from werkzeug import BaseResponse as Response
433
return Response('Index page')
435
def application(environ, start_response):
436
path = environ.get('PATH_INFO') or '/'
440
response = Response('Not Found', status=404)
441
return response(environ, start_response)
443
Like :class:`BaseRequest` which object is lacking a lot of functionality
444
implemented in mixins. This gives you a better control about the actual
445
API of your response objects, so you can create subclasses and add custom
446
functionality. A full featured response object is available as
447
:class:`Response` which implements a couple of useful mixins.
449
To enforce a new type of already existing responses you can use the
450
:meth:`force_type` method. This is useful if you're working with different
451
subclasses of response objects and you want to post process them with a
454
Per default the request object will assume all the text data is `utf-8`
455
encoded. Please refer to `the unicode chapter <unicode.txt>`_ for more
456
details about customizing the behavior.
458
Response can be any kind of iterable or string. If it's a string
459
it's considered being an iterable with one item which is the string
460
passed. Headers can be a list of tuples or a :class:`Headers` object.
462
Special note for `mimetype` and `content_type`: For most mime types
463
`mimetype` and `content_type` work the same, the difference affects
464
only 'text' mimetypes. If the mimetype passed with `mimetype` is a
465
mimetype starting with `text/` it becomes a charset parameter defined
466
with the charset of the response object. In contrast the
467
`content_type` parameter is always added as header unmodified.
469
.. versionchanged:: 0.5
470
the `direct_passthrough` parameter was added.
472
:param response: a string or response iterable.
473
:param status: a string with a status or an integer with the status code.
474
:param headers: a list of headers or an :class:`Headers` object.
475
:param mimetype: the mimetype for the request. See notice above.
476
:param content_type: the content type for the request. See notice above.
477
:param direct_passthrough: if set to `True` :meth:`iter_encoded` is not
478
called before iteration which makes it
479
possible to pass special iterators though
480
unchanged (see :func:`wrap_file` for more
485
default_mimetype = 'text/plain'
487
def __init__(self, response=None, status=None, headers=None,
488
mimetype=None, content_type=None, direct_passthrough=False):
491
elif isinstance(response, basestring):
492
self.response = [response]
494
self.response = iter(response)
496
self.headers = Headers()
497
elif isinstance(headers, Headers):
498
self.headers = headers
500
self.headers = Headers(headers)
501
if content_type is None:
502
if mimetype is None and 'Content-Type' not in self.headers:
503
mimetype = self.default_mimetype
504
if mimetype is not None:
505
mimetype = get_content_type(mimetype, self.charset)
506
content_type = mimetype
507
if content_type is not None:
508
self.headers['Content-Type'] = content_type
510
status = self.default_status
511
if isinstance(status, (int, long)):
512
self.status_code = status
515
self.direct_passthrough = direct_passthrough
518
def force_type(cls, response, environ=None):
519
"""Enforce that the WSGI response is a response object of the current
520
type. Werkzeug will use the :class:`BaseResponse` internally in many
521
situations like the exceptions. If you call :meth:`get_response` on an
522
exception you will get back a regular :class:`BaseResponse` object, even
523
if you are using a custom subclass.
525
This method can enforce a given response type, and it will also
526
convert arbitrary WSGI callables into response objects if an environ
529
# convert a Werkzeug response object into an instance of the
530
# MyResponseClass subclass.
531
response = MyResponseClass.force_type(response)
533
# convert any WSGI application into a response object
534
response = MyResponseClass.force_type(response, environ)
536
This is especially useful if you want to post-process responses in
537
the main dispatcher and use functionality provided by your subclass.
539
Keep in mind that this will modify response objects in place if
542
:param response: a response object or wsgi application.
543
:param environ: a WSGI environment object.
544
:return: a response object.
546
if not isinstance(response, BaseResponse):
548
raise TypeError('cannot convert WSGI application into '
549
'response objects without an environ')
550
response = BaseResponse(*run_wsgi_app(response, environ))
551
response.__class__ = cls
555
def from_app(cls, app, environ, buffered=False):
556
"""Create a new response object from an application output. This
557
works best if you pass it an application that returns a generator all
558
the time. Sometimes applications may use the `write()` callable
559
returned by the `start_response` function. This tries to resolve such
560
edge cases automatically. But if you don't get the expected output
561
you should set `buffered` to `True` which enforces buffering.
563
:param app: the WSGI application to execute.
564
:param environ: the WSGI environment to execute against.
565
:param buffered: set to `True` to enforce buffering.
566
:return: a response object.
568
return cls(*run_wsgi_app(app, environ, buffered))
570
def _get_status_code(self):
572
return int(self.status.split(None, 1)[0])
575
def _set_status_code(self, code):
577
self.status = '%d %s' % (code, HTTP_STATUS_CODES[code].upper())
579
self.status = '%d UNKNOWN' % code
580
status_code = property(_get_status_code, _set_status_code,
581
'The HTTP Status code as number')
582
del _get_status_code, _set_status_code
585
"""The string representation of the request body. Whenever you access
586
this property the request iterable is encoded and flattened. This
587
can lead to unwanted behavior if you stream big data.
589
if not isinstance(self.response, list):
590
self.response = list(self.response)
591
return ''.join(self.iter_encoded())
592
def _set_data(self, value):
593
self.response = [value]
594
data = property(_get_data, _set_data, doc=_get_data.__doc__)
595
del _get_data, _set_data
597
def iter_encoded(self, charset=None):
598
"""Iter the response encoded with the encoding specified. If no
599
encoding is given the encoding from the class is used. Note that
600
this does not encode data that is already a bytestring. If the
601
response object is invoked as WSGI application the return value
602
of this method is used as application iterator except if
603
:attr:`direct_passthrough` was activated.
605
charset = charset or self.charset or 'ascii'
606
for item in self.response:
607
if isinstance(item, unicode):
608
yield item.encode(charset)
612
def set_cookie(self, key, value='', max_age=None, expires=None,
613
path='/', domain=None, secure=None, httponly=False):
614
"""Sets a cookie. The parameters are the same as in the cookie `Morsel`
615
object in the Python standard library but it accepts unicode data, too.
617
:param key: the key (name) of the cookie to be set.
618
:param value: the value of the cookie.
619
:param max_age: should be a number of seconds, or `None` (default) if
620
the cookie should last only as long as the client's
622
:param expires: should be a `datetime` object or UNIX timestamp.
623
:param domain: if you want to set a cross-domain cookie. For example,
624
``domain=".example.com"`` will set a cookie that is
625
readable by the domain ``www.example.com``,
626
``foo.example.com`` etc. Otherwise, a cookie will only
627
be readable by the domain that set it.
628
:param path: limits the cookie to a given path, per default it will
629
span the whole domain.
631
self.headers.add('Set-Cookie', dump_cookie(key, value, max_age,
632
expires, path, domain, secure, httponly,
635
def delete_cookie(self, key, path='/', domain=None):
636
"""Delete a cookie. Fails silently if key doesn't exist.
638
:param key: the key (name) of the cookie to be deleted.
639
:param path: if the cookie that should be deleted was limited to a
640
path, the path has to be defined here.
641
:param domain: if the cookie that should be deleted was limited to a
642
domain, that domain has to be defined here.
644
self.set_cookie(key, expires=0, max_age=0, path=path, domain=domain)
647
def header_list(self):
648
"""This returns the headers in the target charset as list. It's used
649
in __call__ to get the headers for the response.
651
return self.headers.to_list(self.charset)
654
def is_streamed(self):
655
"""If the response is streamed (the response is not a sequence) this
656
property is `True`. In this case streamed means that there is no
657
information about the number of iterations. This is usully `True`
658
if a generator is passed to the response object.
660
This is useful for checking before applying some sort of post
661
filtering that should not take place for streamed responses.
669
def fix_headers(self, environ):
670
"""This is automatically called right before the response is started
671
and should fix common mistakes in headers. For example location
672
headers are joined with the root URL here.
674
:param environ: the WSGI environment of the request to be used for
677
if 'Location' in self.headers:
678
self.headers['Location'] = urlparse.urljoin(
679
get_current_url(environ, root_only=True),
680
self.headers['Location']
682
if 100 <= self.status_code < 200 or self.status_code == 204:
683
self.headers['Content-Length'] = 0
684
elif self.status_code == 304:
685
remove_entity_headers(self.headers)
688
"""Close the wrapped response if possible."""
689
if hasattr(self.response, 'close'):
690
self.response.close()
693
"""Call this method if you want to make your response object ready for
694
being pickled. This buffers the generator if there is one.
696
BaseResponse.data.__get__(self)
698
def __call__(self, environ, start_response):
699
"""Process this response as WSGI application.
701
:param environ: the WSGI environment.
702
:param start_response: the response callable provided by the WSGI
705
self.fix_headers(environ)
706
if environ['REQUEST_METHOD'] == 'HEAD':
708
elif 100 <= self.status_code < 200 or self.status_code in (204, 304):
709
# no response for 204/304. the headers are adapted accordingly
712
elif self.direct_passthrough:
715
resp = self.iter_encoded()
716
start_response(self.status, self.header_list)
720
class AcceptMixin(object):
721
"""A mixin for classes with an :attr:`~BaseResponse.environ` attribute to
722
get all the HTTP accept headers as :class:`Accept` objects (or subclasses
727
def accept_mimetypes(self):
728
"""List of mimetypes this client supports as :class:`MIMEAccept`
731
return parse_accept_header(self.environ.get('HTTP_ACCEPT'), MIMEAccept)
734
def accept_charsets(self):
735
"""List of charsets this client supports as :class:`CharsetAccept`
738
return parse_accept_header(self.environ.get('HTTP_ACCEPT_CHARSET'),
742
def accept_encodings(self):
743
"""List of encodings this client accepts. Encodings in a HTTP term
744
are compression encodings such as gzip. For charsets have a look at
745
:attr:`accept_charset`.
747
return parse_accept_header(self.environ.get('HTTP_ACCEPT_ENCODING'))
750
def accept_languages(self):
751
"""List of languages this client accepts as :class:`LanguageAccept`
754
.. versionchanged 0.5
755
In previous versions this was a regualr :class:`Accept` object.
757
return parse_accept_header(self.environ.get('HTTP_ACCEPT_LANGUAGE'),
761
class ETagRequestMixin(object):
762
"""Add entity tag and cache descriptors to a request object or object with
763
a WSGI environment available as :attr:`~BaseRequest.environ`. This not
764
only provides access to etags but also to the cache control header.
768
def cache_control(self):
769
"""A :class:`RequestCacheControl` object for the incoming cache control
772
cache_control = self.environ.get('HTTP_CACHE_CONTROL')
773
return parse_cache_control_header(cache_control, None,
778
"""An object containing all the etags in the `If-Match` header."""
779
return parse_etags(self.environ.get('HTTP_IF_MATCH'))
782
def if_none_match(self):
783
"""An object containing all the etags in the `If-None-Match` header."""
784
return parse_etags(self.environ.get('HTTP_IF_NONE_MATCH'))
787
def if_modified_since(self):
788
"""The parsed `If-Modified-Since` header as datetime object."""
789
return parse_date(self.environ.get('HTTP_IF_MODIFIED_SINCE'))
792
def if_unmodified_since(self):
793
"""The parsed `If-Unmodified-Since` header as datetime object."""
794
return parse_date(self.environ.get('HTTP_IF_UNMODIFIED_SINCE'))
797
class UserAgentMixin(object):
798
"""Adds a `user_agent` attribute to the request object which contains the
799
parsed user agent of the browser that triggered the request as `UserAgent`
803
# this class actually belongs to a different module. For more details
804
# have a look at `werkzeug.useragents`. On the bottom of that module is
805
# a small comment that explains it.
806
__module__ = 'werkzeug.useragents'
809
def user_agent(self):
810
"""The current user agent."""
811
from werkzeug.useragents import UserAgent
812
return UserAgent(self.environ)
815
class AuthorizationMixin(object):
816
"""Adds an :attr:`authorization` property that represents the parsed value
817
of the `Authorization` header as :class:`Authorization` object.
821
def authorization(self):
822
"""The `Authorization` object in parsed form."""
823
header = self.environ.get('HTTP_AUTHORIZATION')
824
return parse_authorization_header(header)
827
class ETagResponseMixin(object):
828
"""Adds extra functionality to a response object for etag and cache
829
handling. This mixin requires an object with at least a `headers`
830
object that implements a dict like interface similar to :class:`Headers`.
834
def cache_control(self):
835
"""The Cache-Control general-header field is used to specify
836
directives that MUST be obeyed by all caching mechanisms along the
837
request/response chain.
839
def on_update(cache_control):
840
if not cache_control and 'cache-control' in self.headers:
841
del self.headers['cache-control']
843
self.headers['Cache-Control'] = cache_control.to_header()
844
return parse_cache_control_header(self.headers.get('cache-control'),
846
ResponseCacheControl)
848
def make_conditional(self, request_or_environ):
849
"""Make the response conditional to the request. This method works
850
best if an etag was defined for the response already. The `add_etag`
851
method can be used to do that. If called without etag just the date
854
This does nothing if the request method in the request or environ is
855
anything but GET or HEAD.
857
It does not remove the body of the response because that's something
858
the :meth:`__call__` function does for us automatically.
860
Returns self so that you can do ``return resp.make_conditional(req)``
861
but modifies the object in-place.
863
:param request_or_environ: a request object or WSGI environment to be
864
used to make the response conditional
867
environ = getattr(request_or_environ, 'environ', request_or_environ)
868
if environ['REQUEST_METHOD'] in ('GET', 'HEAD'):
869
self.headers['Date'] = http_date()
870
if 'content-length' in self.headers:
871
self.headers['Content-Length'] = len(self.data)
872
if not is_resource_modified(environ, self.headers.get('etag'), None,
873
self.headers.get('last-modified')):
874
self.status_code = 304
877
def add_etag(self, overwrite=False, weak=False):
878
"""Add an etag for the current response if there is none yet."""
879
if overwrite or 'etag' not in self.headers:
880
self.set_etag(generate_etag(self.data), weak)
882
def set_etag(self, etag, weak=False):
883
"""Set the etag, and override the old one if there was one."""
884
self.headers['ETag'] = quote_etag(etag, weak)
887
"""Return a tuple in the form ``(etag, is_weak)``. If there is no
888
ETag the return value is ``(None, None)``.
890
return unquote_etag(self.headers.get('ETag'))
892
def freeze(self, no_etag=False):
893
"""Call this method if you want to make your response object ready for
894
pickeling. This buffers the generator if there is one. This also
895
sets the etag unless `no_etag` is set to `True`.
899
super(ETagResponseMixin, self).freeze()
902
class ResponseStream(object):
903
"""A file descriptor like object used by the :class:`ResponseStreamMixin` to
904
represent the body of the stream. It directly pushes into the response
905
iterable of the response object.
910
def __init__(self, response):
911
self.response = response
914
def write(self, value):
916
raise ValueError('I/O operation on closed file')
917
buf = self.response.response
918
if not isinstance(buf, list):
919
self.response.response = buf = list(buf)
922
def writelines(self, seq):
931
raise ValueError('I/O operation on closed file')
935
raise ValueError('I/O operation on closed file')
940
return self.response.charset
943
class ResponseStreamMixin(object):
944
"""Mixin for :class:`BaseRequest` subclasses. Classes that inherit from
945
this mixin will automatically get a :attr:`stream` property that provides
946
a write-only interface to the response iterable.
951
"""The response iterable as write-only stream."""
952
return ResponseStream(self)
955
class CommonRequestDescriptorsMixin(object):
956
"""A mixin for :class:`BaseRequest` subclasses. Request objects that
957
mix this class in will automatically get descriptors for a coupl eof
958
HTTP headers with automatic type conversion.
960
.. versionadded:: 0.5
963
content_type = environ_property('CONTENT_TYPE', doc='''
964
The Content-Type entity-header field indicates the media type of
965
the entity-body sent to the recipient or, in the case of the HEAD
966
method, the media type that would have been sent had the request
968
content_length = environ_property('CONTENT_LENGTH', None, int, str, doc='''
969
The Content-Length entity-header field indicates the size of the
970
entity-body in bytes or, in the case of the HEAD method, the size of
971
the entity-body that would have been sent had the request been a
973
referrer = environ_property('HTTP_REFERER', doc='''
974
The Referer[sic] request-header field allows the client to specify,
975
for the server's benefit, the address (URI) of the resource from which
976
the Request-URI was obtained (the "referrer", although the header
977
field is misspelled).''')
978
date = environ_property('HTTP_DATE', None, parse_date, doc='''
979
The Date general-header field represents the date and time at which
980
the message was originated, having the same semantics as orig-date
982
max_forwards = environ_property('HTTP_MAX_FORWARDS', None, int, doc='''
983
The Max-Forwards request-header field provides a mechanism with the
984
TRACE and OPTIONS methods to limit the number of proxies or gateways
985
that can forward the request to the next inbound server.''')
987
def _parse_content_type(self):
988
if not hasattr(self, '_parsed_content_type'):
989
self._parsed_content_type = \
990
parse_options_header(self.environ.get('CONTENT_TYPE', ''))
994
"""Like :attr:`content_type` but without parameters (eg, without
995
charset, type etc.). For example if the content
996
type is ``text/html; charset=utf-8`` the mimetype would be
999
self._parse_content_type()
1000
return self._parsed_content_type[0]
1003
def mimetype_params(self):
1004
"""The mimetype parameters as dict. For example if the content
1005
type is ``text/html; charset=utf-8`` the params would be
1006
``{'charset': 'utf-8'}``.
1008
self._parse_content_type()
1009
return self._parsed_content_type[1]
1013
"""The Pragma general-header field is used to include
1014
implementation-specific directives that might apply to any recipient
1015
along the request/response chain. All pragma directives specify
1016
optional behavior from the viewpoint of the protocol; however, some
1017
systems MAY require that behavior be consistent with the directives.
1019
return parse_set_header(self.environ.get('HTTP_PRAGMA', ''))
1022
class CommonResponseDescriptorsMixin(object):
1023
"""A mixin for :class:`BaseResponse` subclasses. Response objects that
1024
mix this class in will automatically get descriptors for a couple of
1025
HTTP headers with automatic type conversion.
1028
def _get_mimetype(self):
1029
ct = self.headers.get('content-type')
1031
return ct.split(';')[0].strip()
1033
def _set_mimetype(self, value):
1034
self.headers['Content-Type'] = get_content_type(value, self.charset)
1036
def _get_mimetype_params(self):
1038
self.headers['Content-Type'] = \
1039
dump_options_header(self.mimetype, d)
1040
d = parse_options_header(self.headers.get('content-type', ''))[1]
1041
return CallbackDict(d, on_update)
1043
mimetype = property(_get_mimetype, _set_mimetype, doc='''
1044
The mimetype (content type without charset etc.)''')
1045
mimetype_params = property(_get_mimetype_params, doc='''
1046
The mimetype parameters as dict. For example if the content
1047
type is ``text/html; charset=utf-8`` the params would be
1048
``{'charset': 'utf-8'}``.
1050
.. versionadded:: 0.5
1052
location = header_property('Location', doc='''
1053
The Location response-header field is used to redirect the recipient
1054
to a location other than the Request-URI for completion of the request
1055
or identification of a new resource.''')
1056
age = header_property('Age', None, parse_date, http_date, doc='''
1057
The Age response-header field conveys the sender's estimate of the
1058
amount of time since the response (or its revalidation) was
1059
generated at the origin server.
1061
Age values are non-negative decimal integers, representing time in
1063
content_type = header_property('Content-Type', doc='''
1064
The Content-Type entity-header field indicates the media type of the
1065
entity-body sent to the recipient or, in the case of the HEAD method,
1066
the media type that would have been sent had the request been a GET.
1068
content_length = header_property('Content-Length', None, int, str, doc='''
1069
The Content-Length entity-header field indicates the size of the
1070
entity-body, in decimal number of OCTETs, sent to the recipient or,
1071
in the case of the HEAD method, the size of the entity-body that would
1072
have been sent had the request been a GET.''')
1073
content_location = header_property('Content-Location', doc='''
1074
The Content-Location entity-header field MAY be used to supply the
1075
resource location for the entity enclosed in the message when that
1076
entity is accessible from a location separate from the requested
1078
content_encoding = header_property('Content-Encoding', doc='''
1079
The Content-Encoding entity-header field is used as a modifier to the
1080
media-type. When present, its value indicates what additional content
1081
codings have been applied to the entity-body, and thus what decoding
1082
mechanisms must be applied in order to obtain the media-type
1083
referenced by the Content-Type header field.''')
1084
content_md5 = header_property('Content-MD5', doc='''
1085
The Content-MD5 entity-header field, as defined in RFC 1864, is an
1086
MD5 digest of the entity-body for the purpose of providing an
1087
end-to-end message integrity check (MIC) of the entity-body. (Note:
1088
a MIC is good for detecting accidental modification of the
1089
entity-body in transit, but is not proof against malicious attacks.)
1091
date = header_property('Date', None, parse_date, http_date, doc='''
1092
The Date general-header field represents the date and time at which
1093
the message was originated, having the same semantics as orig-date
1095
expires = header_property('Expires', None, parse_date, http_date, doc='''
1096
The Expires entity-header field gives the date/time after which the
1097
response is considered stale. A stale cache entry may not normally be
1098
returned by a cache.''')
1099
last_modified = header_property('Last-Modified', None, parse_date,
1101
The Last-Modified entity-header field indicates the date and time at
1102
which the origin server believes the variant was last modified.''')
1104
def _get_retry_after(self):
1105
value = self.headers.get('retry-after')
1108
elif value.isdigit():
1109
return datetime.utcnow() + timedelta(seconds=int(value))
1110
return parse_date(value)
1111
def _set_retry_after(self, value):
1113
if 'retry-after' in self.headers:
1114
del self.headers['retry-after']
1116
elif isinstance(value, datetime):
1117
value = http_date(value)
1120
self.headers['Retry-After'] = value
1122
retry_after = property(_get_retry_after, _set_retry_after, doc='''
1123
The Retry-After response-header field can be used with a 503 (Service
1124
Unavailable) response to indicate how long the service is expected
1125
to be unavailable to the requesting client.
1127
Time in seconds until expiration or date.''')
1129
def _set_property(name, doc=None):
1131
def on_update(header_set):
1132
if not header_set and name in self.headers:
1133
del self.headers[name]
1135
self.headers[name] = header_set.to_header()
1136
return parse_set_header(self.headers.get(name), on_update)
1137
return property(fget, doc=doc)
1139
vary = _set_property('Vary', doc='''
1140
The Vary field value indicates the set of request-header fields that
1141
fully determines, while the response is fresh, whether a cache is
1142
permitted to use the response to reply to a subsequent request
1143
without revalidation.''')
1144
content_language = _set_property('Content-Language', doc='''
1145
The Content-Language entity-header field describes the natural
1146
language(s) of the intended audience for the enclosed entity. Note
1147
that this might not be equivalent to all the languages used within
1148
the entity-body.''')
1149
allow = _set_property('Allow', doc='''
1150
The Allow entity-header field lists the set of methods supported
1151
by the resource identified by the Request-URI. The purpose of this
1152
field is strictly to inform the recipient of valid methods
1153
associated with the resource. An Allow header field MUST be
1154
present in a 405 (Method Not Allowed) response.''')
1156
del _set_property, _get_mimetype, _set_mimetype, _get_retry_after, \
1160
class WWWAuthenticateMixin(object):
1161
"""Adds a :attr:`www_authenticate` property to a response object."""
1164
def www_authenticate(self):
1165
"""The `WWW-Authenticate` header in a parsed form."""
1166
def on_update(www_auth):
1167
if not www_auth and 'www-authenticate' in self.headers:
1168
del self.headers['www-authenticate']
1170
self.headers['WWW-Authenticate'] = www_auth.to_header()
1171
header = self.headers.get('www-authenticate')
1172
return parse_www_authenticate_header(header, on_update)
1175
class Request(BaseRequest, AcceptMixin, ETagRequestMixin,
1176
UserAgentMixin, AuthorizationMixin,
1177
CommonRequestDescriptorsMixin):
1178
"""Full featured request object implementing the following mixins:
1180
- :class:`AcceptMixin` for accept header parsing
1181
- :class:`ETagRequestMixin` for etag and cache control handling
1182
- :class:`UserAgentMixin` for user agent introspection
1183
- :class:`AuthorizationMixin` for http auth handling
1184
- :class:`CommonRequestDescriptorsMixin` for common headers
1188
class Response(BaseResponse, ETagResponseMixin, ResponseStreamMixin,
1189
CommonResponseDescriptorsMixin,
1190
WWWAuthenticateMixin):
1191
"""Full featured response object implementing the following mixins:
1193
- :class:`ETagResponseMixin` for etag and cache control handling
1194
- :class:`ResponseStreamMixin` to add support for the `stream` property
1195
- :class:`CommonResponseDescriptorsMixin` for various HTTP descriptors
1196
- :class:`WWWAuthenticateMixin` for HTTP authentication support