Coverage for /pythoncovmergedfiles/medio/medio/usr/local/lib/python3.8/site-packages/werkzeug/datastructures.py: 31%
1447 statements
« prev ^ index » next coverage.py v7.2.7, created at 2023-06-07 06:35 +0000
« prev ^ index » next coverage.py v7.2.7, created at 2023-06-07 06:35 +0000
1import base64
2import codecs
3import mimetypes
4import os
5import re
6from collections.abc import Collection
7from collections.abc import MutableSet
8from copy import deepcopy
9from io import BytesIO
10from itertools import repeat
11from os import fspath
13from . import exceptions
14from ._internal import _missing
17def is_immutable(self):
18 raise TypeError(f"{type(self).__name__!r} objects are immutable")
21def iter_multi_items(mapping):
22 """Iterates over the items of a mapping yielding keys and values
23 without dropping any from more complex structures.
24 """
25 if isinstance(mapping, MultiDict):
26 yield from mapping.items(multi=True)
27 elif isinstance(mapping, dict):
28 for key, value in mapping.items():
29 if isinstance(value, (tuple, list)):
30 for v in value:
31 yield key, v
32 else:
33 yield key, value
34 else:
35 yield from mapping
38class ImmutableListMixin:
39 """Makes a :class:`list` immutable.
41 .. versionadded:: 0.5
43 :private:
44 """
46 _hash_cache = None
48 def __hash__(self):
49 if self._hash_cache is not None:
50 return self._hash_cache
51 rv = self._hash_cache = hash(tuple(self))
52 return rv
54 def __reduce_ex__(self, protocol):
55 return type(self), (list(self),)
57 def __delitem__(self, key):
58 is_immutable(self)
60 def __iadd__(self, other):
61 is_immutable(self)
63 def __imul__(self, other):
64 is_immutable(self)
66 def __setitem__(self, key, value):
67 is_immutable(self)
69 def append(self, item):
70 is_immutable(self)
72 def remove(self, item):
73 is_immutable(self)
75 def extend(self, iterable):
76 is_immutable(self)
78 def insert(self, pos, value):
79 is_immutable(self)
81 def pop(self, index=-1):
82 is_immutable(self)
84 def reverse(self):
85 is_immutable(self)
87 def sort(self, key=None, reverse=False):
88 is_immutable(self)
91class ImmutableList(ImmutableListMixin, list):
92 """An immutable :class:`list`.
94 .. versionadded:: 0.5
96 :private:
97 """
99 def __repr__(self):
100 return f"{type(self).__name__}({list.__repr__(self)})"
103class ImmutableDictMixin:
104 """Makes a :class:`dict` immutable.
106 .. versionadded:: 0.5
108 :private:
109 """
111 _hash_cache = None
113 @classmethod
114 def fromkeys(cls, keys, value=None):
115 instance = super().__new__(cls)
116 instance.__init__(zip(keys, repeat(value)))
117 return instance
119 def __reduce_ex__(self, protocol):
120 return type(self), (dict(self),)
122 def _iter_hashitems(self):
123 return self.items()
125 def __hash__(self):
126 if self._hash_cache is not None:
127 return self._hash_cache
128 rv = self._hash_cache = hash(frozenset(self._iter_hashitems()))
129 return rv
131 def setdefault(self, key, default=None):
132 is_immutable(self)
134 def update(self, *args, **kwargs):
135 is_immutable(self)
137 def pop(self, key, default=None):
138 is_immutable(self)
140 def popitem(self):
141 is_immutable(self)
143 def __setitem__(self, key, value):
144 is_immutable(self)
146 def __delitem__(self, key):
147 is_immutable(self)
149 def clear(self):
150 is_immutable(self)
153class ImmutableMultiDictMixin(ImmutableDictMixin):
154 """Makes a :class:`MultiDict` immutable.
156 .. versionadded:: 0.5
158 :private:
159 """
161 def __reduce_ex__(self, protocol):
162 return type(self), (list(self.items(multi=True)),)
164 def _iter_hashitems(self):
165 return self.items(multi=True)
167 def add(self, key, value):
168 is_immutable(self)
170 def popitemlist(self):
171 is_immutable(self)
173 def poplist(self, key):
174 is_immutable(self)
176 def setlist(self, key, new_list):
177 is_immutable(self)
179 def setlistdefault(self, key, default_list=None):
180 is_immutable(self)
183def _calls_update(name):
184 def oncall(self, *args, **kw):
185 rv = getattr(super(UpdateDictMixin, self), name)(*args, **kw)
187 if self.on_update is not None:
188 self.on_update(self)
190 return rv
192 oncall.__name__ = name
193 return oncall
196class UpdateDictMixin(dict):
197 """Makes dicts call `self.on_update` on modifications.
199 .. versionadded:: 0.5
201 :private:
202 """
204 on_update = None
206 def setdefault(self, key, default=None):
207 modified = key not in self
208 rv = super().setdefault(key, default)
209 if modified and self.on_update is not None:
210 self.on_update(self)
211 return rv
213 def pop(self, key, default=_missing):
214 modified = key in self
215 if default is _missing:
216 rv = super().pop(key)
217 else:
218 rv = super().pop(key, default)
219 if modified and self.on_update is not None:
220 self.on_update(self)
221 return rv
223 __setitem__ = _calls_update("__setitem__")
224 __delitem__ = _calls_update("__delitem__")
225 clear = _calls_update("clear")
226 popitem = _calls_update("popitem")
227 update = _calls_update("update")
230class TypeConversionDict(dict):
231 """Works like a regular dict but the :meth:`get` method can perform
232 type conversions. :class:`MultiDict` and :class:`CombinedMultiDict`
233 are subclasses of this class and provide the same feature.
235 .. versionadded:: 0.5
236 """
238 def get(self, key, default=None, type=None):
239 """Return the default value if the requested data doesn't exist.
240 If `type` is provided and is a callable it should convert the value,
241 return it or raise a :exc:`ValueError` if that is not possible. In
242 this case the function will return the default as if the value was not
243 found:
245 >>> d = TypeConversionDict(foo='42', bar='blub')
246 >>> d.get('foo', type=int)
247 42
248 >>> d.get('bar', -1, type=int)
249 -1
251 :param key: The key to be looked up.
252 :param default: The default value to be returned if the key can't
253 be looked up. If not further specified `None` is
254 returned.
255 :param type: A callable that is used to cast the value in the
256 :class:`MultiDict`. If a :exc:`ValueError` is raised
257 by this callable the default value is returned.
258 """
259 try:
260 rv = self[key]
261 except KeyError:
262 return default
263 if type is not None:
264 try:
265 rv = type(rv)
266 except ValueError:
267 rv = default
268 return rv
271class ImmutableTypeConversionDict(ImmutableDictMixin, TypeConversionDict):
272 """Works like a :class:`TypeConversionDict` but does not support
273 modifications.
275 .. versionadded:: 0.5
276 """
278 def copy(self):
279 """Return a shallow mutable copy of this object. Keep in mind that
280 the standard library's :func:`copy` function is a no-op for this class
281 like for any other python immutable type (eg: :class:`tuple`).
282 """
283 return TypeConversionDict(self)
285 def __copy__(self):
286 return self
289class MultiDict(TypeConversionDict):
290 """A :class:`MultiDict` is a dictionary subclass customized to deal with
291 multiple values for the same key which is for example used by the parsing
292 functions in the wrappers. This is necessary because some HTML form
293 elements pass multiple values for the same key.
295 :class:`MultiDict` implements all standard dictionary methods.
296 Internally, it saves all values for a key as a list, but the standard dict
297 access methods will only return the first value for a key. If you want to
298 gain access to the other values, too, you have to use the `list` methods as
299 explained below.
301 Basic Usage:
303 >>> d = MultiDict([('a', 'b'), ('a', 'c')])
304 >>> d
305 MultiDict([('a', 'b'), ('a', 'c')])
306 >>> d['a']
307 'b'
308 >>> d.getlist('a')
309 ['b', 'c']
310 >>> 'a' in d
311 True
313 It behaves like a normal dict thus all dict functions will only return the
314 first value when multiple values for one key are found.
316 From Werkzeug 0.3 onwards, the `KeyError` raised by this class is also a
317 subclass of the :exc:`~exceptions.BadRequest` HTTP exception and will
318 render a page for a ``400 BAD REQUEST`` if caught in a catch-all for HTTP
319 exceptions.
321 A :class:`MultiDict` can be constructed from an iterable of
322 ``(key, value)`` tuples, a dict, a :class:`MultiDict` or from Werkzeug 0.2
323 onwards some keyword parameters.
325 :param mapping: the initial value for the :class:`MultiDict`. Either a
326 regular dict, an iterable of ``(key, value)`` tuples
327 or `None`.
328 """
330 def __init__(self, mapping=None):
331 if isinstance(mapping, MultiDict):
332 dict.__init__(self, ((k, l[:]) for k, l in mapping.lists()))
333 elif isinstance(mapping, dict):
334 tmp = {}
335 for key, value in mapping.items():
336 if isinstance(value, (tuple, list)):
337 if len(value) == 0:
338 continue
339 value = list(value)
340 else:
341 value = [value]
342 tmp[key] = value
343 dict.__init__(self, tmp)
344 else:
345 tmp = {}
346 for key, value in mapping or ():
347 tmp.setdefault(key, []).append(value)
348 dict.__init__(self, tmp)
350 def __getstate__(self):
351 return dict(self.lists())
353 def __setstate__(self, value):
354 dict.clear(self)
355 dict.update(self, value)
357 def __iter__(self):
358 # Work around https://bugs.python.org/issue43246.
359 # (`return super().__iter__()` also works here, which makes this look
360 # even more like it should be a no-op, yet it isn't.)
361 return dict.__iter__(self)
363 def __getitem__(self, key):
364 """Return the first data value for this key;
365 raises KeyError if not found.
367 :param key: The key to be looked up.
368 :raise KeyError: if the key does not exist.
369 """
371 if key in self:
372 lst = dict.__getitem__(self, key)
373 if len(lst) > 0:
374 return lst[0]
375 raise exceptions.BadRequestKeyError(key)
377 def __setitem__(self, key, value):
378 """Like :meth:`add` but removes an existing key first.
380 :param key: the key for the value.
381 :param value: the value to set.
382 """
383 dict.__setitem__(self, key, [value])
385 def add(self, key, value):
386 """Adds a new value for the key.
388 .. versionadded:: 0.6
390 :param key: the key for the value.
391 :param value: the value to add.
392 """
393 dict.setdefault(self, key, []).append(value)
395 def getlist(self, key, type=None):
396 """Return the list of items for a given key. If that key is not in the
397 `MultiDict`, the return value will be an empty list. Just like `get`,
398 `getlist` accepts a `type` parameter. All items will be converted
399 with the callable defined there.
401 :param key: The key to be looked up.
402 :param type: A callable that is used to cast the value in the
403 :class:`MultiDict`. If a :exc:`ValueError` is raised
404 by this callable the value will be removed from the list.
405 :return: a :class:`list` of all the values for the key.
406 """
407 try:
408 rv = dict.__getitem__(self, key)
409 except KeyError:
410 return []
411 if type is None:
412 return list(rv)
413 result = []
414 for item in rv:
415 try:
416 result.append(type(item))
417 except ValueError:
418 pass
419 return result
421 def setlist(self, key, new_list):
422 """Remove the old values for a key and add new ones. Note that the list
423 you pass the values in will be shallow-copied before it is inserted in
424 the dictionary.
426 >>> d = MultiDict()
427 >>> d.setlist('foo', ['1', '2'])
428 >>> d['foo']
429 '1'
430 >>> d.getlist('foo')
431 ['1', '2']
433 :param key: The key for which the values are set.
434 :param new_list: An iterable with the new values for the key. Old values
435 are removed first.
436 """
437 dict.__setitem__(self, key, list(new_list))
439 def setdefault(self, key, default=None):
440 """Returns the value for the key if it is in the dict, otherwise it
441 returns `default` and sets that value for `key`.
443 :param key: The key to be looked up.
444 :param default: The default value to be returned if the key is not
445 in the dict. If not further specified it's `None`.
446 """
447 if key not in self:
448 self[key] = default
449 else:
450 default = self[key]
451 return default
453 def setlistdefault(self, key, default_list=None):
454 """Like `setdefault` but sets multiple values. The list returned
455 is not a copy, but the list that is actually used internally. This
456 means that you can put new values into the dict by appending items
457 to the list:
459 >>> d = MultiDict({"foo": 1})
460 >>> d.setlistdefault("foo").extend([2, 3])
461 >>> d.getlist("foo")
462 [1, 2, 3]
464 :param key: The key to be looked up.
465 :param default_list: An iterable of default values. It is either copied
466 (in case it was a list) or converted into a list
467 before returned.
468 :return: a :class:`list`
469 """
470 if key not in self:
471 default_list = list(default_list or ())
472 dict.__setitem__(self, key, default_list)
473 else:
474 default_list = dict.__getitem__(self, key)
475 return default_list
477 def items(self, multi=False):
478 """Return an iterator of ``(key, value)`` pairs.
480 :param multi: If set to `True` the iterator returned will have a pair
481 for each value of each key. Otherwise it will only
482 contain pairs for the first value of each key.
483 """
484 for key, values in dict.items(self):
485 if multi:
486 for value in values:
487 yield key, value
488 else:
489 yield key, values[0]
491 def lists(self):
492 """Return a iterator of ``(key, values)`` pairs, where values is the list
493 of all values associated with the key."""
494 for key, values in dict.items(self):
495 yield key, list(values)
497 def values(self):
498 """Returns an iterator of the first value on every key's value list."""
499 for values in dict.values(self):
500 yield values[0]
502 def listvalues(self):
503 """Return an iterator of all values associated with a key. Zipping
504 :meth:`keys` and this is the same as calling :meth:`lists`:
506 >>> d = MultiDict({"foo": [1, 2, 3]})
507 >>> zip(d.keys(), d.listvalues()) == d.lists()
508 True
509 """
510 return dict.values(self)
512 def copy(self):
513 """Return a shallow copy of this object."""
514 return self.__class__(self)
516 def deepcopy(self, memo=None):
517 """Return a deep copy of this object."""
518 return self.__class__(deepcopy(self.to_dict(flat=False), memo))
520 def to_dict(self, flat=True):
521 """Return the contents as regular dict. If `flat` is `True` the
522 returned dict will only have the first item present, if `flat` is
523 `False` all values will be returned as lists.
525 :param flat: If set to `False` the dict returned will have lists
526 with all the values in it. Otherwise it will only
527 contain the first value for each key.
528 :return: a :class:`dict`
529 """
530 if flat:
531 return dict(self.items())
532 return dict(self.lists())
534 def update(self, mapping):
535 """update() extends rather than replaces existing key lists:
537 >>> a = MultiDict({'x': 1})
538 >>> b = MultiDict({'x': 2, 'y': 3})
539 >>> a.update(b)
540 >>> a
541 MultiDict([('y', 3), ('x', 1), ('x', 2)])
543 If the value list for a key in ``other_dict`` is empty, no new values
544 will be added to the dict and the key will not be created:
546 >>> x = {'empty_list': []}
547 >>> y = MultiDict()
548 >>> y.update(x)
549 >>> y
550 MultiDict([])
551 """
552 for key, value in iter_multi_items(mapping):
553 MultiDict.add(self, key, value)
555 def pop(self, key, default=_missing):
556 """Pop the first item for a list on the dict. Afterwards the
557 key is removed from the dict, so additional values are discarded:
559 >>> d = MultiDict({"foo": [1, 2, 3]})
560 >>> d.pop("foo")
561 1
562 >>> "foo" in d
563 False
565 :param key: the key to pop.
566 :param default: if provided the value to return if the key was
567 not in the dictionary.
568 """
569 try:
570 lst = dict.pop(self, key)
572 if len(lst) == 0:
573 raise exceptions.BadRequestKeyError(key)
575 return lst[0]
576 except KeyError:
577 if default is not _missing:
578 return default
580 raise exceptions.BadRequestKeyError(key) from None
582 def popitem(self):
583 """Pop an item from the dict."""
584 try:
585 item = dict.popitem(self)
587 if len(item[1]) == 0:
588 raise exceptions.BadRequestKeyError(item[0])
590 return (item[0], item[1][0])
591 except KeyError as e:
592 raise exceptions.BadRequestKeyError(e.args[0]) from None
594 def poplist(self, key):
595 """Pop the list for a key from the dict. If the key is not in the dict
596 an empty list is returned.
598 .. versionchanged:: 0.5
599 If the key does no longer exist a list is returned instead of
600 raising an error.
601 """
602 return dict.pop(self, key, [])
604 def popitemlist(self):
605 """Pop a ``(key, list)`` tuple from the dict."""
606 try:
607 return dict.popitem(self)
608 except KeyError as e:
609 raise exceptions.BadRequestKeyError(e.args[0]) from None
611 def __copy__(self):
612 return self.copy()
614 def __deepcopy__(self, memo):
615 return self.deepcopy(memo=memo)
617 def __repr__(self):
618 return f"{type(self).__name__}({list(self.items(multi=True))!r})"
621class _omd_bucket:
622 """Wraps values in the :class:`OrderedMultiDict`. This makes it
623 possible to keep an order over multiple different keys. It requires
624 a lot of extra memory and slows down access a lot, but makes it
625 possible to access elements in O(1) and iterate in O(n).
626 """
628 __slots__ = ("prev", "key", "value", "next")
630 def __init__(self, omd, key, value):
631 self.prev = omd._last_bucket
632 self.key = key
633 self.value = value
634 self.next = None
636 if omd._first_bucket is None:
637 omd._first_bucket = self
638 if omd._last_bucket is not None:
639 omd._last_bucket.next = self
640 omd._last_bucket = self
642 def unlink(self, omd):
643 if self.prev:
644 self.prev.next = self.next
645 if self.next:
646 self.next.prev = self.prev
647 if omd._first_bucket is self:
648 omd._first_bucket = self.next
649 if omd._last_bucket is self:
650 omd._last_bucket = self.prev
653class OrderedMultiDict(MultiDict):
654 """Works like a regular :class:`MultiDict` but preserves the
655 order of the fields. To convert the ordered multi dict into a
656 list you can use the :meth:`items` method and pass it ``multi=True``.
658 In general an :class:`OrderedMultiDict` is an order of magnitude
659 slower than a :class:`MultiDict`.
661 .. admonition:: note
663 Due to a limitation in Python you cannot convert an ordered
664 multi dict into a regular dict by using ``dict(multidict)``.
665 Instead you have to use the :meth:`to_dict` method, otherwise
666 the internal bucket objects are exposed.
667 """
669 def __init__(self, mapping=None):
670 dict.__init__(self)
671 self._first_bucket = self._last_bucket = None
672 if mapping is not None:
673 OrderedMultiDict.update(self, mapping)
675 def __eq__(self, other):
676 if not isinstance(other, MultiDict):
677 return NotImplemented
678 if isinstance(other, OrderedMultiDict):
679 iter1 = iter(self.items(multi=True))
680 iter2 = iter(other.items(multi=True))
681 try:
682 for k1, v1 in iter1:
683 k2, v2 = next(iter2)
684 if k1 != k2 or v1 != v2:
685 return False
686 except StopIteration:
687 return False
688 try:
689 next(iter2)
690 except StopIteration:
691 return True
692 return False
693 if len(self) != len(other):
694 return False
695 for key, values in self.lists():
696 if other.getlist(key) != values:
697 return False
698 return True
700 __hash__ = None
702 def __reduce_ex__(self, protocol):
703 return type(self), (list(self.items(multi=True)),)
705 def __getstate__(self):
706 return list(self.items(multi=True))
708 def __setstate__(self, values):
709 dict.clear(self)
710 for key, value in values:
711 self.add(key, value)
713 def __getitem__(self, key):
714 if key in self:
715 return dict.__getitem__(self, key)[0].value
716 raise exceptions.BadRequestKeyError(key)
718 def __setitem__(self, key, value):
719 self.poplist(key)
720 self.add(key, value)
722 def __delitem__(self, key):
723 self.pop(key)
725 def keys(self):
726 return (key for key, value in self.items())
728 def __iter__(self):
729 return iter(self.keys())
731 def values(self):
732 return (value for key, value in self.items())
734 def items(self, multi=False):
735 ptr = self._first_bucket
736 if multi:
737 while ptr is not None:
738 yield ptr.key, ptr.value
739 ptr = ptr.next
740 else:
741 returned_keys = set()
742 while ptr is not None:
743 if ptr.key not in returned_keys:
744 returned_keys.add(ptr.key)
745 yield ptr.key, ptr.value
746 ptr = ptr.next
748 def lists(self):
749 returned_keys = set()
750 ptr = self._first_bucket
751 while ptr is not None:
752 if ptr.key not in returned_keys:
753 yield ptr.key, self.getlist(ptr.key)
754 returned_keys.add(ptr.key)
755 ptr = ptr.next
757 def listvalues(self):
758 for _key, values in self.lists():
759 yield values
761 def add(self, key, value):
762 dict.setdefault(self, key, []).append(_omd_bucket(self, key, value))
764 def getlist(self, key, type=None):
765 try:
766 rv = dict.__getitem__(self, key)
767 except KeyError:
768 return []
769 if type is None:
770 return [x.value for x in rv]
771 result = []
772 for item in rv:
773 try:
774 result.append(type(item.value))
775 except ValueError:
776 pass
777 return result
779 def setlist(self, key, new_list):
780 self.poplist(key)
781 for value in new_list:
782 self.add(key, value)
784 def setlistdefault(self, key, default_list=None):
785 raise TypeError("setlistdefault is unsupported for ordered multi dicts")
787 def update(self, mapping):
788 for key, value in iter_multi_items(mapping):
789 OrderedMultiDict.add(self, key, value)
791 def poplist(self, key):
792 buckets = dict.pop(self, key, ())
793 for bucket in buckets:
794 bucket.unlink(self)
795 return [x.value for x in buckets]
797 def pop(self, key, default=_missing):
798 try:
799 buckets = dict.pop(self, key)
800 except KeyError:
801 if default is not _missing:
802 return default
804 raise exceptions.BadRequestKeyError(key) from None
806 for bucket in buckets:
807 bucket.unlink(self)
809 return buckets[0].value
811 def popitem(self):
812 try:
813 key, buckets = dict.popitem(self)
814 except KeyError as e:
815 raise exceptions.BadRequestKeyError(e.args[0]) from None
817 for bucket in buckets:
818 bucket.unlink(self)
820 return key, buckets[0].value
822 def popitemlist(self):
823 try:
824 key, buckets = dict.popitem(self)
825 except KeyError as e:
826 raise exceptions.BadRequestKeyError(e.args[0]) from None
828 for bucket in buckets:
829 bucket.unlink(self)
831 return key, [x.value for x in buckets]
834def _options_header_vkw(value, kw):
835 return http.dump_options_header(
836 value, {k.replace("_", "-"): v for k, v in kw.items()}
837 )
840def _unicodify_header_value(value):
841 if isinstance(value, bytes):
842 value = value.decode("latin-1")
843 if not isinstance(value, str):
844 value = str(value)
845 return value
848class Headers:
849 """An object that stores some headers. It has a dict-like interface,
850 but is ordered, can store the same key multiple times, and iterating
851 yields ``(key, value)`` pairs instead of only keys.
853 This data structure is useful if you want a nicer way to handle WSGI
854 headers which are stored as tuples in a list.
856 From Werkzeug 0.3 onwards, the :exc:`KeyError` raised by this class is
857 also a subclass of the :class:`~exceptions.BadRequest` HTTP exception
858 and will render a page for a ``400 BAD REQUEST`` if caught in a
859 catch-all for HTTP exceptions.
861 Headers is mostly compatible with the Python :class:`wsgiref.headers.Headers`
862 class, with the exception of `__getitem__`. :mod:`wsgiref` will return
863 `None` for ``headers['missing']``, whereas :class:`Headers` will raise
864 a :class:`KeyError`.
866 To create a new ``Headers`` object, pass it a list, dict, or
867 other ``Headers`` object with default values. These values are
868 validated the same way values added later are.
870 :param defaults: The list of default values for the :class:`Headers`.
872 .. versionchanged:: 2.1.0
873 Default values are validated the same as values added later.
875 .. versionchanged:: 0.9
876 This data structure now stores unicode values similar to how the
877 multi dicts do it. The main difference is that bytes can be set as
878 well which will automatically be latin1 decoded.
880 .. versionchanged:: 0.9
881 The :meth:`linked` function was removed without replacement as it
882 was an API that does not support the changes to the encoding model.
883 """
885 def __init__(self, defaults=None):
886 self._list = []
887 if defaults is not None:
888 self.extend(defaults)
890 def __getitem__(self, key, _get_mode=False):
891 if not _get_mode:
892 if isinstance(key, int):
893 return self._list[key]
894 elif isinstance(key, slice):
895 return self.__class__(self._list[key])
896 if not isinstance(key, str):
897 raise exceptions.BadRequestKeyError(key)
898 ikey = key.lower()
899 for k, v in self._list:
900 if k.lower() == ikey:
901 return v
902 # micro optimization: if we are in get mode we will catch that
903 # exception one stack level down so we can raise a standard
904 # key error instead of our special one.
905 if _get_mode:
906 raise KeyError()
907 raise exceptions.BadRequestKeyError(key)
909 def __eq__(self, other):
910 def lowered(item):
911 return (item[0].lower(),) + item[1:]
913 return other.__class__ is self.__class__ and set(
914 map(lowered, other._list)
915 ) == set(map(lowered, self._list))
917 __hash__ = None
919 def get(self, key, default=None, type=None, as_bytes=False):
920 """Return the default value if the requested data doesn't exist.
921 If `type` is provided and is a callable it should convert the value,
922 return it or raise a :exc:`ValueError` if that is not possible. In
923 this case the function will return the default as if the value was not
924 found:
926 >>> d = Headers([('Content-Length', '42')])
927 >>> d.get('Content-Length', type=int)
928 42
930 .. versionadded:: 0.9
931 Added support for `as_bytes`.
933 :param key: The key to be looked up.
934 :param default: The default value to be returned if the key can't
935 be looked up. If not further specified `None` is
936 returned.
937 :param type: A callable that is used to cast the value in the
938 :class:`Headers`. If a :exc:`ValueError` is raised
939 by this callable the default value is returned.
940 :param as_bytes: return bytes instead of strings.
941 """
942 try:
943 rv = self.__getitem__(key, _get_mode=True)
944 except KeyError:
945 return default
946 if as_bytes:
947 rv = rv.encode("latin1")
948 if type is None:
949 return rv
950 try:
951 return type(rv)
952 except ValueError:
953 return default
955 def getlist(self, key, type=None, as_bytes=False):
956 """Return the list of items for a given key. If that key is not in the
957 :class:`Headers`, the return value will be an empty list. Just like
958 :meth:`get`, :meth:`getlist` accepts a `type` parameter. All items will
959 be converted with the callable defined there.
961 .. versionadded:: 0.9
962 Added support for `as_bytes`.
964 :param key: The key to be looked up.
965 :param type: A callable that is used to cast the value in the
966 :class:`Headers`. If a :exc:`ValueError` is raised
967 by this callable the value will be removed from the list.
968 :return: a :class:`list` of all the values for the key.
969 :param as_bytes: return bytes instead of strings.
970 """
971 ikey = key.lower()
972 result = []
973 for k, v in self:
974 if k.lower() == ikey:
975 if as_bytes:
976 v = v.encode("latin1")
977 if type is not None:
978 try:
979 v = type(v)
980 except ValueError:
981 continue
982 result.append(v)
983 return result
985 def get_all(self, name):
986 """Return a list of all the values for the named field.
988 This method is compatible with the :mod:`wsgiref`
989 :meth:`~wsgiref.headers.Headers.get_all` method.
990 """
991 return self.getlist(name)
993 def items(self, lower=False):
994 for key, value in self:
995 if lower:
996 key = key.lower()
997 yield key, value
999 def keys(self, lower=False):
1000 for key, _ in self.items(lower):
1001 yield key
1003 def values(self):
1004 for _, value in self.items():
1005 yield value
1007 def extend(self, *args, **kwargs):
1008 """Extend headers in this object with items from another object
1009 containing header items as well as keyword arguments.
1011 To replace existing keys instead of extending, use
1012 :meth:`update` instead.
1014 If provided, the first argument can be another :class:`Headers`
1015 object, a :class:`MultiDict`, :class:`dict`, or iterable of
1016 pairs.
1018 .. versionchanged:: 1.0
1019 Support :class:`MultiDict`. Allow passing ``kwargs``.
1020 """
1021 if len(args) > 1:
1022 raise TypeError(f"update expected at most 1 arguments, got {len(args)}")
1024 if args:
1025 for key, value in iter_multi_items(args[0]):
1026 self.add(key, value)
1028 for key, value in iter_multi_items(kwargs):
1029 self.add(key, value)
1031 def __delitem__(self, key, _index_operation=True):
1032 if _index_operation and isinstance(key, (int, slice)):
1033 del self._list[key]
1034 return
1035 key = key.lower()
1036 new = []
1037 for k, v in self._list:
1038 if k.lower() != key:
1039 new.append((k, v))
1040 self._list[:] = new
1042 def remove(self, key):
1043 """Remove a key.
1045 :param key: The key to be removed.
1046 """
1047 return self.__delitem__(key, _index_operation=False)
1049 def pop(self, key=None, default=_missing):
1050 """Removes and returns a key or index.
1052 :param key: The key to be popped. If this is an integer the item at
1053 that position is removed, if it's a string the value for
1054 that key is. If the key is omitted or `None` the last
1055 item is removed.
1056 :return: an item.
1057 """
1058 if key is None:
1059 return self._list.pop()
1060 if isinstance(key, int):
1061 return self._list.pop(key)
1062 try:
1063 rv = self[key]
1064 self.remove(key)
1065 except KeyError:
1066 if default is not _missing:
1067 return default
1068 raise
1069 return rv
1071 def popitem(self):
1072 """Removes a key or index and returns a (key, value) item."""
1073 return self.pop()
1075 def __contains__(self, key):
1076 """Check if a key is present."""
1077 try:
1078 self.__getitem__(key, _get_mode=True)
1079 except KeyError:
1080 return False
1081 return True
1083 def __iter__(self):
1084 """Yield ``(key, value)`` tuples."""
1085 return iter(self._list)
1087 def __len__(self):
1088 return len(self._list)
1090 def add(self, _key, _value, **kw):
1091 """Add a new header tuple to the list.
1093 Keyword arguments can specify additional parameters for the header
1094 value, with underscores converted to dashes::
1096 >>> d = Headers()
1097 >>> d.add('Content-Type', 'text/plain')
1098 >>> d.add('Content-Disposition', 'attachment', filename='foo.png')
1100 The keyword argument dumping uses :func:`dump_options_header`
1101 behind the scenes.
1103 .. versionadded:: 0.4.1
1104 keyword arguments were added for :mod:`wsgiref` compatibility.
1105 """
1106 if kw:
1107 _value = _options_header_vkw(_value, kw)
1108 _key = _unicodify_header_value(_key)
1109 _value = _unicodify_header_value(_value)
1110 self._validate_value(_value)
1111 self._list.append((_key, _value))
1113 def _validate_value(self, value):
1114 if not isinstance(value, str):
1115 raise TypeError("Value should be a string.")
1116 if "\n" in value or "\r" in value:
1117 raise ValueError(
1118 "Detected newline in header value. This is "
1119 "a potential security problem"
1120 )
1122 def add_header(self, _key, _value, **_kw):
1123 """Add a new header tuple to the list.
1125 An alias for :meth:`add` for compatibility with the :mod:`wsgiref`
1126 :meth:`~wsgiref.headers.Headers.add_header` method.
1127 """
1128 self.add(_key, _value, **_kw)
1130 def clear(self):
1131 """Clears all headers."""
1132 del self._list[:]
1134 def set(self, _key, _value, **kw):
1135 """Remove all header tuples for `key` and add a new one. The newly
1136 added key either appears at the end of the list if there was no
1137 entry or replaces the first one.
1139 Keyword arguments can specify additional parameters for the header
1140 value, with underscores converted to dashes. See :meth:`add` for
1141 more information.
1143 .. versionchanged:: 0.6.1
1144 :meth:`set` now accepts the same arguments as :meth:`add`.
1146 :param key: The key to be inserted.
1147 :param value: The value to be inserted.
1148 """
1149 if kw:
1150 _value = _options_header_vkw(_value, kw)
1151 _key = _unicodify_header_value(_key)
1152 _value = _unicodify_header_value(_value)
1153 self._validate_value(_value)
1154 if not self._list:
1155 self._list.append((_key, _value))
1156 return
1157 listiter = iter(self._list)
1158 ikey = _key.lower()
1159 for idx, (old_key, _old_value) in enumerate(listiter):
1160 if old_key.lower() == ikey:
1161 # replace first occurrence
1162 self._list[idx] = (_key, _value)
1163 break
1164 else:
1165 self._list.append((_key, _value))
1166 return
1167 self._list[idx + 1 :] = [t for t in listiter if t[0].lower() != ikey]
1169 def setlist(self, key, values):
1170 """Remove any existing values for a header and add new ones.
1172 :param key: The header key to set.
1173 :param values: An iterable of values to set for the key.
1175 .. versionadded:: 1.0
1176 """
1177 if values:
1178 values_iter = iter(values)
1179 self.set(key, next(values_iter))
1181 for value in values_iter:
1182 self.add(key, value)
1183 else:
1184 self.remove(key)
1186 def setdefault(self, key, default):
1187 """Return the first value for the key if it is in the headers,
1188 otherwise set the header to the value given by ``default`` and
1189 return that.
1191 :param key: The header key to get.
1192 :param default: The value to set for the key if it is not in the
1193 headers.
1194 """
1195 if key in self:
1196 return self[key]
1198 self.set(key, default)
1199 return default
1201 def setlistdefault(self, key, default):
1202 """Return the list of values for the key if it is in the
1203 headers, otherwise set the header to the list of values given
1204 by ``default`` and return that.
1206 Unlike :meth:`MultiDict.setlistdefault`, modifying the returned
1207 list will not affect the headers.
1209 :param key: The header key to get.
1210 :param default: An iterable of values to set for the key if it
1211 is not in the headers.
1213 .. versionadded:: 1.0
1214 """
1215 if key not in self:
1216 self.setlist(key, default)
1218 return self.getlist(key)
1220 def __setitem__(self, key, value):
1221 """Like :meth:`set` but also supports index/slice based setting."""
1222 if isinstance(key, (slice, int)):
1223 if isinstance(key, int):
1224 value = [value]
1225 value = [
1226 (_unicodify_header_value(k), _unicodify_header_value(v))
1227 for (k, v) in value
1228 ]
1229 for _, v in value:
1230 self._validate_value(v)
1231 if isinstance(key, int):
1232 self._list[key] = value[0]
1233 else:
1234 self._list[key] = value
1235 else:
1236 self.set(key, value)
1238 def update(self, *args, **kwargs):
1239 """Replace headers in this object with items from another
1240 headers object and keyword arguments.
1242 To extend existing keys instead of replacing, use :meth:`extend`
1243 instead.
1245 If provided, the first argument can be another :class:`Headers`
1246 object, a :class:`MultiDict`, :class:`dict`, or iterable of
1247 pairs.
1249 .. versionadded:: 1.0
1250 """
1251 if len(args) > 1:
1252 raise TypeError(f"update expected at most 1 arguments, got {len(args)}")
1254 if args:
1255 mapping = args[0]
1257 if isinstance(mapping, (Headers, MultiDict)):
1258 for key in mapping.keys():
1259 self.setlist(key, mapping.getlist(key))
1260 elif isinstance(mapping, dict):
1261 for key, value in mapping.items():
1262 if isinstance(value, (list, tuple)):
1263 self.setlist(key, value)
1264 else:
1265 self.set(key, value)
1266 else:
1267 for key, value in mapping:
1268 self.set(key, value)
1270 for key, value in kwargs.items():
1271 if isinstance(value, (list, tuple)):
1272 self.setlist(key, value)
1273 else:
1274 self.set(key, value)
1276 def to_wsgi_list(self):
1277 """Convert the headers into a list suitable for WSGI.
1279 :return: list
1280 """
1281 return list(self)
1283 def copy(self):
1284 return self.__class__(self._list)
1286 def __copy__(self):
1287 return self.copy()
1289 def __str__(self):
1290 """Returns formatted headers suitable for HTTP transmission."""
1291 strs = []
1292 for key, value in self.to_wsgi_list():
1293 strs.append(f"{key}: {value}")
1294 strs.append("\r\n")
1295 return "\r\n".join(strs)
1297 def __repr__(self):
1298 return f"{type(self).__name__}({list(self)!r})"
1301class ImmutableHeadersMixin:
1302 """Makes a :class:`Headers` immutable. We do not mark them as
1303 hashable though since the only usecase for this datastructure
1304 in Werkzeug is a view on a mutable structure.
1306 .. versionadded:: 0.5
1308 :private:
1309 """
1311 def __delitem__(self, key, **kwargs):
1312 is_immutable(self)
1314 def __setitem__(self, key, value):
1315 is_immutable(self)
1317 def set(self, _key, _value, **kw):
1318 is_immutable(self)
1320 def setlist(self, key, values):
1321 is_immutable(self)
1323 def add(self, _key, _value, **kw):
1324 is_immutable(self)
1326 def add_header(self, _key, _value, **_kw):
1327 is_immutable(self)
1329 def remove(self, key):
1330 is_immutable(self)
1332 def extend(self, *args, **kwargs):
1333 is_immutable(self)
1335 def update(self, *args, **kwargs):
1336 is_immutable(self)
1338 def insert(self, pos, value):
1339 is_immutable(self)
1341 def pop(self, key=None, default=_missing):
1342 is_immutable(self)
1344 def popitem(self):
1345 is_immutable(self)
1347 def setdefault(self, key, default):
1348 is_immutable(self)
1350 def setlistdefault(self, key, default):
1351 is_immutable(self)
1354class EnvironHeaders(ImmutableHeadersMixin, Headers):
1355 """Read only version of the headers from a WSGI environment. This
1356 provides the same interface as `Headers` and is constructed from
1357 a WSGI environment.
1359 From Werkzeug 0.3 onwards, the `KeyError` raised by this class is also a
1360 subclass of the :exc:`~exceptions.BadRequest` HTTP exception and will
1361 render a page for a ``400 BAD REQUEST`` if caught in a catch-all for
1362 HTTP exceptions.
1363 """
1365 def __init__(self, environ):
1366 self.environ = environ
1368 def __eq__(self, other):
1369 return self.environ is other.environ
1371 __hash__ = None
1373 def __getitem__(self, key, _get_mode=False):
1374 # _get_mode is a no-op for this class as there is no index but
1375 # used because get() calls it.
1376 if not isinstance(key, str):
1377 raise KeyError(key)
1378 key = key.upper().replace("-", "_")
1379 if key in ("CONTENT_TYPE", "CONTENT_LENGTH"):
1380 return _unicodify_header_value(self.environ[key])
1381 return _unicodify_header_value(self.environ[f"HTTP_{key}"])
1383 def __len__(self):
1384 # the iter is necessary because otherwise list calls our
1385 # len which would call list again and so forth.
1386 return len(list(iter(self)))
1388 def __iter__(self):
1389 for key, value in self.environ.items():
1390 if key.startswith("HTTP_") and key not in (
1391 "HTTP_CONTENT_TYPE",
1392 "HTTP_CONTENT_LENGTH",
1393 ):
1394 yield (
1395 key[5:].replace("_", "-").title(),
1396 _unicodify_header_value(value),
1397 )
1398 elif key in ("CONTENT_TYPE", "CONTENT_LENGTH") and value:
1399 yield (key.replace("_", "-").title(), _unicodify_header_value(value))
1401 def copy(self):
1402 raise TypeError(f"cannot create {type(self).__name__!r} copies")
1405class CombinedMultiDict(ImmutableMultiDictMixin, MultiDict):
1406 """A read only :class:`MultiDict` that you can pass multiple :class:`MultiDict`
1407 instances as sequence and it will combine the return values of all wrapped
1408 dicts:
1410 >>> from werkzeug.datastructures import CombinedMultiDict, MultiDict
1411 >>> post = MultiDict([('foo', 'bar')])
1412 >>> get = MultiDict([('blub', 'blah')])
1413 >>> combined = CombinedMultiDict([get, post])
1414 >>> combined['foo']
1415 'bar'
1416 >>> combined['blub']
1417 'blah'
1419 This works for all read operations and will raise a `TypeError` for
1420 methods that usually change data which isn't possible.
1422 From Werkzeug 0.3 onwards, the `KeyError` raised by this class is also a
1423 subclass of the :exc:`~exceptions.BadRequest` HTTP exception and will
1424 render a page for a ``400 BAD REQUEST`` if caught in a catch-all for HTTP
1425 exceptions.
1426 """
1428 def __reduce_ex__(self, protocol):
1429 return type(self), (self.dicts,)
1431 def __init__(self, dicts=None):
1432 self.dicts = list(dicts) or []
1434 @classmethod
1435 def fromkeys(cls, keys, value=None):
1436 raise TypeError(f"cannot create {cls.__name__!r} instances by fromkeys")
1438 def __getitem__(self, key):
1439 for d in self.dicts:
1440 if key in d:
1441 return d[key]
1442 raise exceptions.BadRequestKeyError(key)
1444 def get(self, key, default=None, type=None):
1445 for d in self.dicts:
1446 if key in d:
1447 if type is not None:
1448 try:
1449 return type(d[key])
1450 except ValueError:
1451 continue
1452 return d[key]
1453 return default
1455 def getlist(self, key, type=None):
1456 rv = []
1457 for d in self.dicts:
1458 rv.extend(d.getlist(key, type))
1459 return rv
1461 def _keys_impl(self):
1462 """This function exists so __len__ can be implemented more efficiently,
1463 saving one list creation from an iterator.
1464 """
1465 rv = set()
1466 rv.update(*self.dicts)
1467 return rv
1469 def keys(self):
1470 return self._keys_impl()
1472 def __iter__(self):
1473 return iter(self.keys())
1475 def items(self, multi=False):
1476 found = set()
1477 for d in self.dicts:
1478 for key, value in d.items(multi):
1479 if multi:
1480 yield key, value
1481 elif key not in found:
1482 found.add(key)
1483 yield key, value
1485 def values(self):
1486 for _key, value in self.items():
1487 yield value
1489 def lists(self):
1490 rv = {}
1491 for d in self.dicts:
1492 for key, values in d.lists():
1493 rv.setdefault(key, []).extend(values)
1494 return list(rv.items())
1496 def listvalues(self):
1497 return (x[1] for x in self.lists())
1499 def copy(self):
1500 """Return a shallow mutable copy of this object.
1502 This returns a :class:`MultiDict` representing the data at the
1503 time of copying. The copy will no longer reflect changes to the
1504 wrapped dicts.
1506 .. versionchanged:: 0.15
1507 Return a mutable :class:`MultiDict`.
1508 """
1509 return MultiDict(self)
1511 def to_dict(self, flat=True):
1512 """Return the contents as regular dict. If `flat` is `True` the
1513 returned dict will only have the first item present, if `flat` is
1514 `False` all values will be returned as lists.
1516 :param flat: If set to `False` the dict returned will have lists
1517 with all the values in it. Otherwise it will only
1518 contain the first item for each key.
1519 :return: a :class:`dict`
1520 """
1521 if flat:
1522 return dict(self.items())
1524 return dict(self.lists())
1526 def __len__(self):
1527 return len(self._keys_impl())
1529 def __contains__(self, key):
1530 for d in self.dicts:
1531 if key in d:
1532 return True
1533 return False
1535 def __repr__(self):
1536 return f"{type(self).__name__}({self.dicts!r})"
1539class FileMultiDict(MultiDict):
1540 """A special :class:`MultiDict` that has convenience methods to add
1541 files to it. This is used for :class:`EnvironBuilder` and generally
1542 useful for unittesting.
1544 .. versionadded:: 0.5
1545 """
1547 def add_file(self, name, file, filename=None, content_type=None):
1548 """Adds a new file to the dict. `file` can be a file name or
1549 a :class:`file`-like or a :class:`FileStorage` object.
1551 :param name: the name of the field.
1552 :param file: a filename or :class:`file`-like object
1553 :param filename: an optional filename
1554 :param content_type: an optional content type
1555 """
1556 if isinstance(file, FileStorage):
1557 value = file
1558 else:
1559 if isinstance(file, str):
1560 if filename is None:
1561 filename = file
1562 file = open(file, "rb")
1563 if filename and content_type is None:
1564 content_type = (
1565 mimetypes.guess_type(filename)[0] or "application/octet-stream"
1566 )
1567 value = FileStorage(file, filename, name, content_type)
1569 self.add(name, value)
1572class ImmutableDict(ImmutableDictMixin, dict):
1573 """An immutable :class:`dict`.
1575 .. versionadded:: 0.5
1576 """
1578 def __repr__(self):
1579 return f"{type(self).__name__}({dict.__repr__(self)})"
1581 def copy(self):
1582 """Return a shallow mutable copy of this object. Keep in mind that
1583 the standard library's :func:`copy` function is a no-op for this class
1584 like for any other python immutable type (eg: :class:`tuple`).
1585 """
1586 return dict(self)
1588 def __copy__(self):
1589 return self
1592class ImmutableMultiDict(ImmutableMultiDictMixin, MultiDict):
1593 """An immutable :class:`MultiDict`.
1595 .. versionadded:: 0.5
1596 """
1598 def copy(self):
1599 """Return a shallow mutable copy of this object. Keep in mind that
1600 the standard library's :func:`copy` function is a no-op for this class
1601 like for any other python immutable type (eg: :class:`tuple`).
1602 """
1603 return MultiDict(self)
1605 def __copy__(self):
1606 return self
1609class ImmutableOrderedMultiDict(ImmutableMultiDictMixin, OrderedMultiDict):
1610 """An immutable :class:`OrderedMultiDict`.
1612 .. versionadded:: 0.6
1613 """
1615 def _iter_hashitems(self):
1616 return enumerate(self.items(multi=True))
1618 def copy(self):
1619 """Return a shallow mutable copy of this object. Keep in mind that
1620 the standard library's :func:`copy` function is a no-op for this class
1621 like for any other python immutable type (eg: :class:`tuple`).
1622 """
1623 return OrderedMultiDict(self)
1625 def __copy__(self):
1626 return self
1629class Accept(ImmutableList):
1630 """An :class:`Accept` object is just a list subclass for lists of
1631 ``(value, quality)`` tuples. It is automatically sorted by specificity
1632 and quality.
1634 All :class:`Accept` objects work similar to a list but provide extra
1635 functionality for working with the data. Containment checks are
1636 normalized to the rules of that header:
1638 >>> a = CharsetAccept([('ISO-8859-1', 1), ('utf-8', 0.7)])
1639 >>> a.best
1640 'ISO-8859-1'
1641 >>> 'iso-8859-1' in a
1642 True
1643 >>> 'UTF8' in a
1644 True
1645 >>> 'utf7' in a
1646 False
1648 To get the quality for an item you can use normal item lookup:
1650 >>> print a['utf-8']
1651 0.7
1652 >>> a['utf7']
1653 0
1655 .. versionchanged:: 0.5
1656 :class:`Accept` objects are forced immutable now.
1658 .. versionchanged:: 1.0.0
1659 :class:`Accept` internal values are no longer ordered
1660 alphabetically for equal quality tags. Instead the initial
1661 order is preserved.
1663 """
1665 def __init__(self, values=()):
1666 if values is None:
1667 list.__init__(self)
1668 self.provided = False
1669 elif isinstance(values, Accept):
1670 self.provided = values.provided
1671 list.__init__(self, values)
1672 else:
1673 self.provided = True
1674 values = sorted(
1675 values, key=lambda x: (self._specificity(x[0]), x[1]), reverse=True
1676 )
1677 list.__init__(self, values)
1679 def _specificity(self, value):
1680 """Returns a tuple describing the value's specificity."""
1681 return (value != "*",)
1683 def _value_matches(self, value, item):
1684 """Check if a value matches a given accept item."""
1685 return item == "*" or item.lower() == value.lower()
1687 def __getitem__(self, key):
1688 """Besides index lookup (getting item n) you can also pass it a string
1689 to get the quality for the item. If the item is not in the list, the
1690 returned quality is ``0``.
1691 """
1692 if isinstance(key, str):
1693 return self.quality(key)
1694 return list.__getitem__(self, key)
1696 def quality(self, key):
1697 """Returns the quality of the key.
1699 .. versionadded:: 0.6
1700 In previous versions you had to use the item-lookup syntax
1701 (eg: ``obj[key]`` instead of ``obj.quality(key)``)
1702 """
1703 for item, quality in self:
1704 if self._value_matches(key, item):
1705 return quality
1706 return 0
1708 def __contains__(self, value):
1709 for item, _quality in self:
1710 if self._value_matches(value, item):
1711 return True
1712 return False
1714 def __repr__(self):
1715 pairs_str = ", ".join(f"({x!r}, {y})" for x, y in self)
1716 return f"{type(self).__name__}([{pairs_str}])"
1718 def index(self, key):
1719 """Get the position of an entry or raise :exc:`ValueError`.
1721 :param key: The key to be looked up.
1723 .. versionchanged:: 0.5
1724 This used to raise :exc:`IndexError`, which was inconsistent
1725 with the list API.
1726 """
1727 if isinstance(key, str):
1728 for idx, (item, _quality) in enumerate(self):
1729 if self._value_matches(key, item):
1730 return idx
1731 raise ValueError(key)
1732 return list.index(self, key)
1734 def find(self, key):
1735 """Get the position of an entry or return -1.
1737 :param key: The key to be looked up.
1738 """
1739 try:
1740 return self.index(key)
1741 except ValueError:
1742 return -1
1744 def values(self):
1745 """Iterate over all values."""
1746 for item in self:
1747 yield item[0]
1749 def to_header(self):
1750 """Convert the header set into an HTTP header string."""
1751 result = []
1752 for value, quality in self:
1753 if quality != 1:
1754 value = f"{value};q={quality}"
1755 result.append(value)
1756 return ",".join(result)
1758 def __str__(self):
1759 return self.to_header()
1761 def _best_single_match(self, match):
1762 for client_item, quality in self:
1763 if self._value_matches(match, client_item):
1764 # self is sorted by specificity descending, we can exit
1765 return client_item, quality
1766 return None
1768 def best_match(self, matches, default=None):
1769 """Returns the best match from a list of possible matches based
1770 on the specificity and quality of the client. If two items have the
1771 same quality and specificity, the one is returned that comes first.
1773 :param matches: a list of matches to check for
1774 :param default: the value that is returned if none match
1775 """
1776 result = default
1777 best_quality = -1
1778 best_specificity = (-1,)
1779 for server_item in matches:
1780 match = self._best_single_match(server_item)
1781 if not match:
1782 continue
1783 client_item, quality = match
1784 specificity = self._specificity(client_item)
1785 if quality <= 0 or quality < best_quality:
1786 continue
1787 # better quality or same quality but more specific => better match
1788 if quality > best_quality or specificity > best_specificity:
1789 result = server_item
1790 best_quality = quality
1791 best_specificity = specificity
1792 return result
1794 @property
1795 def best(self):
1796 """The best match as value."""
1797 if self:
1798 return self[0][0]
1801_mime_split_re = re.compile(r"/|(?:\s*;\s*)")
1804def _normalize_mime(value):
1805 return _mime_split_re.split(value.lower())
1808class MIMEAccept(Accept):
1809 """Like :class:`Accept` but with special methods and behavior for
1810 mimetypes.
1811 """
1813 def _specificity(self, value):
1814 return tuple(x != "*" for x in _mime_split_re.split(value))
1816 def _value_matches(self, value, item):
1817 # item comes from the client, can't match if it's invalid.
1818 if "/" not in item:
1819 return False
1821 # value comes from the application, tell the developer when it
1822 # doesn't look valid.
1823 if "/" not in value:
1824 raise ValueError(f"invalid mimetype {value!r}")
1826 # Split the match value into type, subtype, and a sorted list of parameters.
1827 normalized_value = _normalize_mime(value)
1828 value_type, value_subtype = normalized_value[:2]
1829 value_params = sorted(normalized_value[2:])
1831 # "*/*" is the only valid value that can start with "*".
1832 if value_type == "*" and value_subtype != "*":
1833 raise ValueError(f"invalid mimetype {value!r}")
1835 # Split the accept item into type, subtype, and parameters.
1836 normalized_item = _normalize_mime(item)
1837 item_type, item_subtype = normalized_item[:2]
1838 item_params = sorted(normalized_item[2:])
1840 # "*/not-*" from the client is invalid, can't match.
1841 if item_type == "*" and item_subtype != "*":
1842 return False
1844 return (
1845 (item_type == "*" and item_subtype == "*")
1846 or (value_type == "*" and value_subtype == "*")
1847 ) or (
1848 item_type == value_type
1849 and (
1850 item_subtype == "*"
1851 or value_subtype == "*"
1852 or (item_subtype == value_subtype and item_params == value_params)
1853 )
1854 )
1856 @property
1857 def accept_html(self):
1858 """True if this object accepts HTML."""
1859 return (
1860 "text/html" in self or "application/xhtml+xml" in self or self.accept_xhtml
1861 )
1863 @property
1864 def accept_xhtml(self):
1865 """True if this object accepts XHTML."""
1866 return "application/xhtml+xml" in self or "application/xml" in self
1868 @property
1869 def accept_json(self):
1870 """True if this object accepts JSON."""
1871 return "application/json" in self
1874_locale_delim_re = re.compile(r"[_-]")
1877def _normalize_lang(value):
1878 """Process a language tag for matching."""
1879 return _locale_delim_re.split(value.lower())
1882class LanguageAccept(Accept):
1883 """Like :class:`Accept` but with normalization for language tags."""
1885 def _value_matches(self, value, item):
1886 return item == "*" or _normalize_lang(value) == _normalize_lang(item)
1888 def best_match(self, matches, default=None):
1889 """Given a list of supported values, finds the best match from
1890 the list of accepted values.
1892 Language tags are normalized for the purpose of matching, but
1893 are returned unchanged.
1895 If no exact match is found, this will fall back to matching
1896 the first subtag (primary language only), first with the
1897 accepted values then with the match values. This partial is not
1898 applied to any other language subtags.
1900 The default is returned if no exact or fallback match is found.
1902 :param matches: A list of supported languages to find a match.
1903 :param default: The value that is returned if none match.
1904 """
1905 # Look for an exact match first. If a client accepts "en-US",
1906 # "en-US" is a valid match at this point.
1907 result = super().best_match(matches)
1909 if result is not None:
1910 return result
1912 # Fall back to accepting primary tags. If a client accepts
1913 # "en-US", "en" is a valid match at this point. Need to use
1914 # re.split to account for 2 or 3 letter codes.
1915 fallback = Accept(
1916 [(_locale_delim_re.split(item[0], 1)[0], item[1]) for item in self]
1917 )
1918 result = fallback.best_match(matches)
1920 if result is not None:
1921 return result
1923 # Fall back to matching primary tags. If the client accepts
1924 # "en", "en-US" is a valid match at this point.
1925 fallback_matches = [_locale_delim_re.split(item, 1)[0] for item in matches]
1926 result = super().best_match(fallback_matches)
1928 # Return a value from the original match list. Find the first
1929 # original value that starts with the matched primary tag.
1930 if result is not None:
1931 return next(item for item in matches if item.startswith(result))
1933 return default
1936class CharsetAccept(Accept):
1937 """Like :class:`Accept` but with normalization for charsets."""
1939 def _value_matches(self, value, item):
1940 def _normalize(name):
1941 try:
1942 return codecs.lookup(name).name
1943 except LookupError:
1944 return name.lower()
1946 return item == "*" or _normalize(value) == _normalize(item)
1949def cache_control_property(key, empty, type):
1950 """Return a new property object for a cache header. Useful if you
1951 want to add support for a cache extension in a subclass.
1953 .. versionchanged:: 2.0
1954 Renamed from ``cache_property``.
1955 """
1956 return property(
1957 lambda x: x._get_cache_value(key, empty, type),
1958 lambda x, v: x._set_cache_value(key, v, type),
1959 lambda x: x._del_cache_value(key),
1960 f"accessor for {key!r}",
1961 )
1964class _CacheControl(UpdateDictMixin, dict):
1965 """Subclass of a dict that stores values for a Cache-Control header. It
1966 has accessors for all the cache-control directives specified in RFC 2616.
1967 The class does not differentiate between request and response directives.
1969 Because the cache-control directives in the HTTP header use dashes the
1970 python descriptors use underscores for that.
1972 To get a header of the :class:`CacheControl` object again you can convert
1973 the object into a string or call the :meth:`to_header` method. If you plan
1974 to subclass it and add your own items have a look at the sourcecode for
1975 that class.
1977 .. versionchanged:: 2.1.0
1978 Setting int properties such as ``max_age`` will convert the
1979 value to an int.
1981 .. versionchanged:: 0.4
1983 Setting `no_cache` or `private` to boolean `True` will set the implicit
1984 none-value which is ``*``:
1986 >>> cc = ResponseCacheControl()
1987 >>> cc.no_cache = True
1988 >>> cc
1989 <ResponseCacheControl 'no-cache'>
1990 >>> cc.no_cache
1991 '*'
1992 >>> cc.no_cache = None
1993 >>> cc
1994 <ResponseCacheControl ''>
1996 In versions before 0.5 the behavior documented here affected the now
1997 no longer existing `CacheControl` class.
1998 """
2000 no_cache = cache_control_property("no-cache", "*", None)
2001 no_store = cache_control_property("no-store", None, bool)
2002 max_age = cache_control_property("max-age", -1, int)
2003 no_transform = cache_control_property("no-transform", None, None)
2005 def __init__(self, values=(), on_update=None):
2006 dict.__init__(self, values or ())
2007 self.on_update = on_update
2008 self.provided = values is not None
2010 def _get_cache_value(self, key, empty, type):
2011 """Used internally by the accessor properties."""
2012 if type is bool:
2013 return key in self
2014 if key in self:
2015 value = self[key]
2016 if value is None:
2017 return empty
2018 elif type is not None:
2019 try:
2020 value = type(value)
2021 except ValueError:
2022 pass
2023 return value
2024 return None
2026 def _set_cache_value(self, key, value, type):
2027 """Used internally by the accessor properties."""
2028 if type is bool:
2029 if value:
2030 self[key] = None
2031 else:
2032 self.pop(key, None)
2033 else:
2034 if value is None:
2035 self.pop(key, None)
2036 elif value is True:
2037 self[key] = None
2038 else:
2039 if type is not None:
2040 self[key] = type(value)
2041 else:
2042 self[key] = value
2044 def _del_cache_value(self, key):
2045 """Used internally by the accessor properties."""
2046 if key in self:
2047 del self[key]
2049 def to_header(self):
2050 """Convert the stored values into a cache control header."""
2051 return http.dump_header(self)
2053 def __str__(self):
2054 return self.to_header()
2056 def __repr__(self):
2057 kv_str = " ".join(f"{k}={v!r}" for k, v in sorted(self.items()))
2058 return f"<{type(self).__name__} {kv_str}>"
2060 cache_property = staticmethod(cache_control_property)
2063class RequestCacheControl(ImmutableDictMixin, _CacheControl):
2064 """A cache control for requests. This is immutable and gives access
2065 to all the request-relevant cache control headers.
2067 To get a header of the :class:`RequestCacheControl` object again you can
2068 convert the object into a string or call the :meth:`to_header` method. If
2069 you plan to subclass it and add your own items have a look at the sourcecode
2070 for that class.
2072 .. versionchanged:: 2.1.0
2073 Setting int properties such as ``max_age`` will convert the
2074 value to an int.
2076 .. versionadded:: 0.5
2077 In previous versions a `CacheControl` class existed that was used
2078 both for request and response.
2079 """
2081 max_stale = cache_control_property("max-stale", "*", int)
2082 min_fresh = cache_control_property("min-fresh", "*", int)
2083 only_if_cached = cache_control_property("only-if-cached", None, bool)
2086class ResponseCacheControl(_CacheControl):
2087 """A cache control for responses. Unlike :class:`RequestCacheControl`
2088 this is mutable and gives access to response-relevant cache control
2089 headers.
2091 To get a header of the :class:`ResponseCacheControl` object again you can
2092 convert the object into a string or call the :meth:`to_header` method. If
2093 you plan to subclass it and add your own items have a look at the sourcecode
2094 for that class.
2096 .. versionchanged:: 2.1.1
2097 ``s_maxage`` converts the value to an int.
2099 .. versionchanged:: 2.1.0
2100 Setting int properties such as ``max_age`` will convert the
2101 value to an int.
2103 .. versionadded:: 0.5
2104 In previous versions a `CacheControl` class existed that was used
2105 both for request and response.
2106 """
2108 public = cache_control_property("public", None, bool)
2109 private = cache_control_property("private", "*", None)
2110 must_revalidate = cache_control_property("must-revalidate", None, bool)
2111 proxy_revalidate = cache_control_property("proxy-revalidate", None, bool)
2112 s_maxage = cache_control_property("s-maxage", None, int)
2113 immutable = cache_control_property("immutable", None, bool)
2116def csp_property(key):
2117 """Return a new property object for a content security policy header.
2118 Useful if you want to add support for a csp extension in a
2119 subclass.
2120 """
2121 return property(
2122 lambda x: x._get_value(key),
2123 lambda x, v: x._set_value(key, v),
2124 lambda x: x._del_value(key),
2125 f"accessor for {key!r}",
2126 )
2129class ContentSecurityPolicy(UpdateDictMixin, dict):
2130 """Subclass of a dict that stores values for a Content Security Policy
2131 header. It has accessors for all the level 3 policies.
2133 Because the csp directives in the HTTP header use dashes the
2134 python descriptors use underscores for that.
2136 To get a header of the :class:`ContentSecuirtyPolicy` object again
2137 you can convert the object into a string or call the
2138 :meth:`to_header` method. If you plan to subclass it and add your
2139 own items have a look at the sourcecode for that class.
2141 .. versionadded:: 1.0.0
2142 Support for Content Security Policy headers was added.
2144 """
2146 base_uri = csp_property("base-uri")
2147 child_src = csp_property("child-src")
2148 connect_src = csp_property("connect-src")
2149 default_src = csp_property("default-src")
2150 font_src = csp_property("font-src")
2151 form_action = csp_property("form-action")
2152 frame_ancestors = csp_property("frame-ancestors")
2153 frame_src = csp_property("frame-src")
2154 img_src = csp_property("img-src")
2155 manifest_src = csp_property("manifest-src")
2156 media_src = csp_property("media-src")
2157 navigate_to = csp_property("navigate-to")
2158 object_src = csp_property("object-src")
2159 prefetch_src = csp_property("prefetch-src")
2160 plugin_types = csp_property("plugin-types")
2161 report_to = csp_property("report-to")
2162 report_uri = csp_property("report-uri")
2163 sandbox = csp_property("sandbox")
2164 script_src = csp_property("script-src")
2165 script_src_attr = csp_property("script-src-attr")
2166 script_src_elem = csp_property("script-src-elem")
2167 style_src = csp_property("style-src")
2168 style_src_attr = csp_property("style-src-attr")
2169 style_src_elem = csp_property("style-src-elem")
2170 worker_src = csp_property("worker-src")
2172 def __init__(self, values=(), on_update=None):
2173 dict.__init__(self, values or ())
2174 self.on_update = on_update
2175 self.provided = values is not None
2177 def _get_value(self, key):
2178 """Used internally by the accessor properties."""
2179 return self.get(key)
2181 def _set_value(self, key, value):
2182 """Used internally by the accessor properties."""
2183 if value is None:
2184 self.pop(key, None)
2185 else:
2186 self[key] = value
2188 def _del_value(self, key):
2189 """Used internally by the accessor properties."""
2190 if key in self:
2191 del self[key]
2193 def to_header(self):
2194 """Convert the stored values into a cache control header."""
2195 return http.dump_csp_header(self)
2197 def __str__(self):
2198 return self.to_header()
2200 def __repr__(self):
2201 kv_str = " ".join(f"{k}={v!r}" for k, v in sorted(self.items()))
2202 return f"<{type(self).__name__} {kv_str}>"
2205class CallbackDict(UpdateDictMixin, dict):
2206 """A dict that calls a function passed every time something is changed.
2207 The function is passed the dict instance.
2208 """
2210 def __init__(self, initial=None, on_update=None):
2211 dict.__init__(self, initial or ())
2212 self.on_update = on_update
2214 def __repr__(self):
2215 return f"<{type(self).__name__} {dict.__repr__(self)}>"
2218class HeaderSet(MutableSet):
2219 """Similar to the :class:`ETags` class this implements a set-like structure.
2220 Unlike :class:`ETags` this is case insensitive and used for vary, allow, and
2221 content-language headers.
2223 If not constructed using the :func:`parse_set_header` function the
2224 instantiation works like this:
2226 >>> hs = HeaderSet(['foo', 'bar', 'baz'])
2227 >>> hs
2228 HeaderSet(['foo', 'bar', 'baz'])
2229 """
2231 def __init__(self, headers=None, on_update=None):
2232 self._headers = list(headers or ())
2233 self._set = {x.lower() for x in self._headers}
2234 self.on_update = on_update
2236 def add(self, header):
2237 """Add a new header to the set."""
2238 self.update((header,))
2240 def remove(self, header):
2241 """Remove a header from the set. This raises an :exc:`KeyError` if the
2242 header is not in the set.
2244 .. versionchanged:: 0.5
2245 In older versions a :exc:`IndexError` was raised instead of a
2246 :exc:`KeyError` if the object was missing.
2248 :param header: the header to be removed.
2249 """
2250 key = header.lower()
2251 if key not in self._set:
2252 raise KeyError(header)
2253 self._set.remove(key)
2254 for idx, key in enumerate(self._headers):
2255 if key.lower() == header:
2256 del self._headers[idx]
2257 break
2258 if self.on_update is not None:
2259 self.on_update(self)
2261 def update(self, iterable):
2262 """Add all the headers from the iterable to the set.
2264 :param iterable: updates the set with the items from the iterable.
2265 """
2266 inserted_any = False
2267 for header in iterable:
2268 key = header.lower()
2269 if key not in self._set:
2270 self._headers.append(header)
2271 self._set.add(key)
2272 inserted_any = True
2273 if inserted_any and self.on_update is not None:
2274 self.on_update(self)
2276 def discard(self, header):
2277 """Like :meth:`remove` but ignores errors.
2279 :param header: the header to be discarded.
2280 """
2281 try:
2282 self.remove(header)
2283 except KeyError:
2284 pass
2286 def find(self, header):
2287 """Return the index of the header in the set or return -1 if not found.
2289 :param header: the header to be looked up.
2290 """
2291 header = header.lower()
2292 for idx, item in enumerate(self._headers):
2293 if item.lower() == header:
2294 return idx
2295 return -1
2297 def index(self, header):
2298 """Return the index of the header in the set or raise an
2299 :exc:`IndexError`.
2301 :param header: the header to be looked up.
2302 """
2303 rv = self.find(header)
2304 if rv < 0:
2305 raise IndexError(header)
2306 return rv
2308 def clear(self):
2309 """Clear the set."""
2310 self._set.clear()
2311 del self._headers[:]
2312 if self.on_update is not None:
2313 self.on_update(self)
2315 def as_set(self, preserve_casing=False):
2316 """Return the set as real python set type. When calling this, all
2317 the items are converted to lowercase and the ordering is lost.
2319 :param preserve_casing: if set to `True` the items in the set returned
2320 will have the original case like in the
2321 :class:`HeaderSet`, otherwise they will
2322 be lowercase.
2323 """
2324 if preserve_casing:
2325 return set(self._headers)
2326 return set(self._set)
2328 def to_header(self):
2329 """Convert the header set into an HTTP header string."""
2330 return ", ".join(map(http.quote_header_value, self._headers))
2332 def __getitem__(self, idx):
2333 return self._headers[idx]
2335 def __delitem__(self, idx):
2336 rv = self._headers.pop(idx)
2337 self._set.remove(rv.lower())
2338 if self.on_update is not None:
2339 self.on_update(self)
2341 def __setitem__(self, idx, value):
2342 old = self._headers[idx]
2343 self._set.remove(old.lower())
2344 self._headers[idx] = value
2345 self._set.add(value.lower())
2346 if self.on_update is not None:
2347 self.on_update(self)
2349 def __contains__(self, header):
2350 return header.lower() in self._set
2352 def __len__(self):
2353 return len(self._set)
2355 def __iter__(self):
2356 return iter(self._headers)
2358 def __bool__(self):
2359 return bool(self._set)
2361 def __str__(self):
2362 return self.to_header()
2364 def __repr__(self):
2365 return f"{type(self).__name__}({self._headers!r})"
2368class ETags(Collection):
2369 """A set that can be used to check if one etag is present in a collection
2370 of etags.
2371 """
2373 def __init__(self, strong_etags=None, weak_etags=None, star_tag=False):
2374 if not star_tag and strong_etags:
2375 self._strong = frozenset(strong_etags)
2376 else:
2377 self._strong = frozenset()
2379 self._weak = frozenset(weak_etags or ())
2380 self.star_tag = star_tag
2382 def as_set(self, include_weak=False):
2383 """Convert the `ETags` object into a python set. Per default all the
2384 weak etags are not part of this set."""
2385 rv = set(self._strong)
2386 if include_weak:
2387 rv.update(self._weak)
2388 return rv
2390 def is_weak(self, etag):
2391 """Check if an etag is weak."""
2392 return etag in self._weak
2394 def is_strong(self, etag):
2395 """Check if an etag is strong."""
2396 return etag in self._strong
2398 def contains_weak(self, etag):
2399 """Check if an etag is part of the set including weak and strong tags."""
2400 return self.is_weak(etag) or self.contains(etag)
2402 def contains(self, etag):
2403 """Check if an etag is part of the set ignoring weak tags.
2404 It is also possible to use the ``in`` operator.
2405 """
2406 if self.star_tag:
2407 return True
2408 return self.is_strong(etag)
2410 def contains_raw(self, etag):
2411 """When passed a quoted tag it will check if this tag is part of the
2412 set. If the tag is weak it is checked against weak and strong tags,
2413 otherwise strong only."""
2414 etag, weak = http.unquote_etag(etag)
2415 if weak:
2416 return self.contains_weak(etag)
2417 return self.contains(etag)
2419 def to_header(self):
2420 """Convert the etags set into a HTTP header string."""
2421 if self.star_tag:
2422 return "*"
2423 return ", ".join(
2424 [f'"{x}"' for x in self._strong] + [f'W/"{x}"' for x in self._weak]
2425 )
2427 def __call__(self, etag=None, data=None, include_weak=False):
2428 if [etag, data].count(None) != 1:
2429 raise TypeError("either tag or data required, but at least one")
2430 if etag is None:
2431 etag = http.generate_etag(data)
2432 if include_weak:
2433 if etag in self._weak:
2434 return True
2435 return etag in self._strong
2437 def __bool__(self):
2438 return bool(self.star_tag or self._strong or self._weak)
2440 def __str__(self):
2441 return self.to_header()
2443 def __len__(self):
2444 return len(self._strong)
2446 def __iter__(self):
2447 return iter(self._strong)
2449 def __contains__(self, etag):
2450 return self.contains(etag)
2452 def __repr__(self):
2453 return f"<{type(self).__name__} {str(self)!r}>"
2456class IfRange:
2457 """Very simple object that represents the `If-Range` header in parsed
2458 form. It will either have neither a etag or date or one of either but
2459 never both.
2461 .. versionadded:: 0.7
2462 """
2464 def __init__(self, etag=None, date=None):
2465 #: The etag parsed and unquoted. Ranges always operate on strong
2466 #: etags so the weakness information is not necessary.
2467 self.etag = etag
2468 #: The date in parsed format or `None`.
2469 self.date = date
2471 def to_header(self):
2472 """Converts the object back into an HTTP header."""
2473 if self.date is not None:
2474 return http.http_date(self.date)
2475 if self.etag is not None:
2476 return http.quote_etag(self.etag)
2477 return ""
2479 def __str__(self):
2480 return self.to_header()
2482 def __repr__(self):
2483 return f"<{type(self).__name__} {str(self)!r}>"
2486class Range:
2487 """Represents a ``Range`` header. All methods only support only
2488 bytes as the unit. Stores a list of ranges if given, but the methods
2489 only work if only one range is provided.
2491 :raise ValueError: If the ranges provided are invalid.
2493 .. versionchanged:: 0.15
2494 The ranges passed in are validated.
2496 .. versionadded:: 0.7
2497 """
2499 def __init__(self, units, ranges):
2500 #: The units of this range. Usually "bytes".
2501 self.units = units
2502 #: A list of ``(begin, end)`` tuples for the range header provided.
2503 #: The ranges are non-inclusive.
2504 self.ranges = ranges
2506 for start, end in ranges:
2507 if start is None or (end is not None and (start < 0 or start >= end)):
2508 raise ValueError(f"{(start, end)} is not a valid range.")
2510 def range_for_length(self, length):
2511 """If the range is for bytes, the length is not None and there is
2512 exactly one range and it is satisfiable it returns a ``(start, stop)``
2513 tuple, otherwise `None`.
2514 """
2515 if self.units != "bytes" or length is None or len(self.ranges) != 1:
2516 return None
2517 start, end = self.ranges[0]
2518 if end is None:
2519 end = length
2520 if start < 0:
2521 start += length
2522 if http.is_byte_range_valid(start, end, length):
2523 return start, min(end, length)
2524 return None
2526 def make_content_range(self, length):
2527 """Creates a :class:`~werkzeug.datastructures.ContentRange` object
2528 from the current range and given content length.
2529 """
2530 rng = self.range_for_length(length)
2531 if rng is not None:
2532 return ContentRange(self.units, rng[0], rng[1], length)
2533 return None
2535 def to_header(self):
2536 """Converts the object back into an HTTP header."""
2537 ranges = []
2538 for begin, end in self.ranges:
2539 if end is None:
2540 ranges.append(f"{begin}-" if begin >= 0 else str(begin))
2541 else:
2542 ranges.append(f"{begin}-{end - 1}")
2543 return f"{self.units}={','.join(ranges)}"
2545 def to_content_range_header(self, length):
2546 """Converts the object into `Content-Range` HTTP header,
2547 based on given length
2548 """
2549 range = self.range_for_length(length)
2550 if range is not None:
2551 return f"{self.units} {range[0]}-{range[1] - 1}/{length}"
2552 return None
2554 def __str__(self):
2555 return self.to_header()
2557 def __repr__(self):
2558 return f"<{type(self).__name__} {str(self)!r}>"
2561def _callback_property(name):
2562 def fget(self):
2563 return getattr(self, name)
2565 def fset(self, value):
2566 setattr(self, name, value)
2567 if self.on_update is not None:
2568 self.on_update(self)
2570 return property(fget, fset)
2573class ContentRange:
2574 """Represents the content range header.
2576 .. versionadded:: 0.7
2577 """
2579 def __init__(self, units, start, stop, length=None, on_update=None):
2580 assert http.is_byte_range_valid(start, stop, length), "Bad range provided"
2581 self.on_update = on_update
2582 self.set(start, stop, length, units)
2584 #: The units to use, usually "bytes"
2585 units = _callback_property("_units")
2586 #: The start point of the range or `None`.
2587 start = _callback_property("_start")
2588 #: The stop point of the range (non-inclusive) or `None`. Can only be
2589 #: `None` if also start is `None`.
2590 stop = _callback_property("_stop")
2591 #: The length of the range or `None`.
2592 length = _callback_property("_length")
2594 def set(self, start, stop, length=None, units="bytes"):
2595 """Simple method to update the ranges."""
2596 assert http.is_byte_range_valid(start, stop, length), "Bad range provided"
2597 self._units = units
2598 self._start = start
2599 self._stop = stop
2600 self._length = length
2601 if self.on_update is not None:
2602 self.on_update(self)
2604 def unset(self):
2605 """Sets the units to `None` which indicates that the header should
2606 no longer be used.
2607 """
2608 self.set(None, None, units=None)
2610 def to_header(self):
2611 if self.units is None:
2612 return ""
2613 if self.length is None:
2614 length = "*"
2615 else:
2616 length = self.length
2617 if self.start is None:
2618 return f"{self.units} */{length}"
2619 return f"{self.units} {self.start}-{self.stop - 1}/{length}"
2621 def __bool__(self):
2622 return self.units is not None
2624 def __str__(self):
2625 return self.to_header()
2627 def __repr__(self):
2628 return f"<{type(self).__name__} {str(self)!r}>"
2631class Authorization(ImmutableDictMixin, dict):
2632 """Represents an ``Authorization`` header sent by the client.
2634 This is returned by
2635 :func:`~werkzeug.http.parse_authorization_header`. It can be useful
2636 to create the object manually to pass to the test
2637 :class:`~werkzeug.test.Client`.
2639 .. versionchanged:: 0.5
2640 This object became immutable.
2641 """
2643 def __init__(self, auth_type, data=None):
2644 dict.__init__(self, data or {})
2645 self.type = auth_type
2647 @property
2648 def username(self):
2649 """The username transmitted. This is set for both basic and digest
2650 auth all the time.
2651 """
2652 return self.get("username")
2654 @property
2655 def password(self):
2656 """When the authentication type is basic this is the password
2657 transmitted by the client, else `None`.
2658 """
2659 return self.get("password")
2661 @property
2662 def realm(self):
2663 """This is the server realm sent back for HTTP digest auth."""
2664 return self.get("realm")
2666 @property
2667 def nonce(self):
2668 """The nonce the server sent for digest auth, sent back by the client.
2669 A nonce should be unique for every 401 response for HTTP digest auth.
2670 """
2671 return self.get("nonce")
2673 @property
2674 def uri(self):
2675 """The URI from Request-URI of the Request-Line; duplicated because
2676 proxies are allowed to change the Request-Line in transit. HTTP
2677 digest auth only.
2678 """
2679 return self.get("uri")
2681 @property
2682 def nc(self):
2683 """The nonce count value transmitted by clients if a qop-header is
2684 also transmitted. HTTP digest auth only.
2685 """
2686 return self.get("nc")
2688 @property
2689 def cnonce(self):
2690 """If the server sent a qop-header in the ``WWW-Authenticate``
2691 header, the client has to provide this value for HTTP digest auth.
2692 See the RFC for more details.
2693 """
2694 return self.get("cnonce")
2696 @property
2697 def response(self):
2698 """A string of 32 hex digits computed as defined in RFC 2617, which
2699 proves that the user knows a password. Digest auth only.
2700 """
2701 return self.get("response")
2703 @property
2704 def opaque(self):
2705 """The opaque header from the server returned unchanged by the client.
2706 It is recommended that this string be base64 or hexadecimal data.
2707 Digest auth only.
2708 """
2709 return self.get("opaque")
2711 @property
2712 def qop(self):
2713 """Indicates what "quality of protection" the client has applied to
2714 the message for HTTP digest auth. Note that this is a single token,
2715 not a quoted list of alternatives as in WWW-Authenticate.
2716 """
2717 return self.get("qop")
2719 def to_header(self):
2720 """Convert to a string value for an ``Authorization`` header.
2722 .. versionadded:: 2.0
2723 Added to support passing authorization to the test client.
2724 """
2725 if self.type == "basic":
2726 value = base64.b64encode(
2727 f"{self.username}:{self.password}".encode()
2728 ).decode("utf8")
2729 return f"Basic {value}"
2731 if self.type == "digest":
2732 return f"Digest {http.dump_header(self)}"
2734 raise ValueError(f"Unsupported type {self.type!r}.")
2737def auth_property(name, doc=None):
2738 """A static helper function for Authentication subclasses to add
2739 extra authentication system properties onto a class::
2741 class FooAuthenticate(WWWAuthenticate):
2742 special_realm = auth_property('special_realm')
2744 For more information have a look at the sourcecode to see how the
2745 regular properties (:attr:`realm` etc.) are implemented.
2746 """
2748 def _set_value(self, value):
2749 if value is None:
2750 self.pop(name, None)
2751 else:
2752 self[name] = str(value)
2754 return property(lambda x: x.get(name), _set_value, doc=doc)
2757def _set_property(name, doc=None):
2758 def fget(self):
2759 def on_update(header_set):
2760 if not header_set and name in self:
2761 del self[name]
2762 elif header_set:
2763 self[name] = header_set.to_header()
2765 return http.parse_set_header(self.get(name), on_update)
2767 return property(fget, doc=doc)
2770class WWWAuthenticate(UpdateDictMixin, dict):
2771 """Provides simple access to `WWW-Authenticate` headers."""
2773 #: list of keys that require quoting in the generated header
2774 _require_quoting = frozenset(["domain", "nonce", "opaque", "realm", "qop"])
2776 def __init__(self, auth_type=None, values=None, on_update=None):
2777 dict.__init__(self, values or ())
2778 if auth_type:
2779 self["__auth_type__"] = auth_type
2780 self.on_update = on_update
2782 def set_basic(self, realm="authentication required"):
2783 """Clear the auth info and enable basic auth."""
2784 dict.clear(self)
2785 dict.update(self, {"__auth_type__": "basic", "realm": realm})
2786 if self.on_update:
2787 self.on_update(self)
2789 def set_digest(
2790 self, realm, nonce, qop=("auth",), opaque=None, algorithm=None, stale=False
2791 ):
2792 """Clear the auth info and enable digest auth."""
2793 d = {
2794 "__auth_type__": "digest",
2795 "realm": realm,
2796 "nonce": nonce,
2797 "qop": http.dump_header(qop),
2798 }
2799 if stale:
2800 d["stale"] = "TRUE"
2801 if opaque is not None:
2802 d["opaque"] = opaque
2803 if algorithm is not None:
2804 d["algorithm"] = algorithm
2805 dict.clear(self)
2806 dict.update(self, d)
2807 if self.on_update:
2808 self.on_update(self)
2810 def to_header(self):
2811 """Convert the stored values into a WWW-Authenticate header."""
2812 d = dict(self)
2813 auth_type = d.pop("__auth_type__", None) or "basic"
2814 kv_items = (
2815 (k, http.quote_header_value(v, allow_token=k not in self._require_quoting))
2816 for k, v in d.items()
2817 )
2818 kv_string = ", ".join([f"{k}={v}" for k, v in kv_items])
2819 return f"{auth_type.title()} {kv_string}"
2821 def __str__(self):
2822 return self.to_header()
2824 def __repr__(self):
2825 return f"<{type(self).__name__} {self.to_header()!r}>"
2827 type = auth_property(
2828 "__auth_type__",
2829 doc="""The type of the auth mechanism. HTTP currently specifies
2830 ``Basic`` and ``Digest``.""",
2831 )
2832 realm = auth_property(
2833 "realm",
2834 doc="""A string to be displayed to users so they know which
2835 username and password to use. This string should contain at
2836 least the name of the host performing the authentication and
2837 might additionally indicate the collection of users who might
2838 have access.""",
2839 )
2840 domain = _set_property(
2841 "domain",
2842 doc="""A list of URIs that define the protection space. If a URI
2843 is an absolute path, it is relative to the canonical root URL of
2844 the server being accessed.""",
2845 )
2846 nonce = auth_property(
2847 "nonce",
2848 doc="""
2849 A server-specified data string which should be uniquely generated
2850 each time a 401 response is made. It is recommended that this
2851 string be base64 or hexadecimal data.""",
2852 )
2853 opaque = auth_property(
2854 "opaque",
2855 doc="""A string of data, specified by the server, which should
2856 be returned by the client unchanged in the Authorization header
2857 of subsequent requests with URIs in the same protection space.
2858 It is recommended that this string be base64 or hexadecimal
2859 data.""",
2860 )
2861 algorithm = auth_property(
2862 "algorithm",
2863 doc="""A string indicating a pair of algorithms used to produce
2864 the digest and a checksum. If this is not present it is assumed
2865 to be "MD5". If the algorithm is not understood, the challenge
2866 should be ignored (and a different one used, if there is more
2867 than one).""",
2868 )
2869 qop = _set_property(
2870 "qop",
2871 doc="""A set of quality-of-privacy directives such as auth and
2872 auth-int.""",
2873 )
2875 @property
2876 def stale(self):
2877 """A flag, indicating that the previous request from the client
2878 was rejected because the nonce value was stale.
2879 """
2880 val = self.get("stale")
2881 if val is not None:
2882 return val.lower() == "true"
2884 @stale.setter
2885 def stale(self, value):
2886 if value is None:
2887 self.pop("stale", None)
2888 else:
2889 self["stale"] = "TRUE" if value else "FALSE"
2891 auth_property = staticmethod(auth_property)
2894class FileStorage:
2895 """The :class:`FileStorage` class is a thin wrapper over incoming files.
2896 It is used by the request object to represent uploaded files. All the
2897 attributes of the wrapper stream are proxied by the file storage so
2898 it's possible to do ``storage.read()`` instead of the long form
2899 ``storage.stream.read()``.
2900 """
2902 def __init__(
2903 self,
2904 stream=None,
2905 filename=None,
2906 name=None,
2907 content_type=None,
2908 content_length=None,
2909 headers=None,
2910 ):
2911 self.name = name
2912 self.stream = stream or BytesIO()
2914 # If no filename is provided, attempt to get the filename from
2915 # the stream object. Python names special streams like
2916 # ``<stderr>`` with angular brackets, skip these streams.
2917 if filename is None:
2918 filename = getattr(stream, "name", None)
2920 if filename is not None:
2921 filename = os.fsdecode(filename)
2923 if filename and filename[0] == "<" and filename[-1] == ">":
2924 filename = None
2925 else:
2926 filename = os.fsdecode(filename)
2928 self.filename = filename
2930 if headers is None:
2931 headers = Headers()
2932 self.headers = headers
2933 if content_type is not None:
2934 headers["Content-Type"] = content_type
2935 if content_length is not None:
2936 headers["Content-Length"] = str(content_length)
2938 def _parse_content_type(self):
2939 if not hasattr(self, "_parsed_content_type"):
2940 self._parsed_content_type = http.parse_options_header(self.content_type)
2942 @property
2943 def content_type(self):
2944 """The content-type sent in the header. Usually not available"""
2945 return self.headers.get("content-type")
2947 @property
2948 def content_length(self):
2949 """The content-length sent in the header. Usually not available"""
2950 try:
2951 return int(self.headers.get("content-length") or 0)
2952 except ValueError:
2953 return 0
2955 @property
2956 def mimetype(self):
2957 """Like :attr:`content_type`, but without parameters (eg, without
2958 charset, type etc.) and always lowercase. For example if the content
2959 type is ``text/HTML; charset=utf-8`` the mimetype would be
2960 ``'text/html'``.
2962 .. versionadded:: 0.7
2963 """
2964 self._parse_content_type()
2965 return self._parsed_content_type[0].lower()
2967 @property
2968 def mimetype_params(self):
2969 """The mimetype parameters as dict. For example if the content
2970 type is ``text/html; charset=utf-8`` the params would be
2971 ``{'charset': 'utf-8'}``.
2973 .. versionadded:: 0.7
2974 """
2975 self._parse_content_type()
2976 return self._parsed_content_type[1]
2978 def save(self, dst, buffer_size=16384):
2979 """Save the file to a destination path or file object. If the
2980 destination is a file object you have to close it yourself after the
2981 call. The buffer size is the number of bytes held in memory during
2982 the copy process. It defaults to 16KB.
2984 For secure file saving also have a look at :func:`secure_filename`.
2986 :param dst: a filename, :class:`os.PathLike`, or open file
2987 object to write to.
2988 :param buffer_size: Passed as the ``length`` parameter of
2989 :func:`shutil.copyfileobj`.
2991 .. versionchanged:: 1.0
2992 Supports :mod:`pathlib`.
2993 """
2994 from shutil import copyfileobj
2996 close_dst = False
2998 if hasattr(dst, "__fspath__"):
2999 dst = fspath(dst)
3001 if isinstance(dst, str):
3002 dst = open(dst, "wb")
3003 close_dst = True
3005 try:
3006 copyfileobj(self.stream, dst, buffer_size)
3007 finally:
3008 if close_dst:
3009 dst.close()
3011 def close(self):
3012 """Close the underlying file if possible."""
3013 try:
3014 self.stream.close()
3015 except Exception:
3016 pass
3018 def __bool__(self):
3019 return bool(self.filename)
3021 def __getattr__(self, name):
3022 try:
3023 return getattr(self.stream, name)
3024 except AttributeError:
3025 # SpooledTemporaryFile doesn't implement IOBase, get the
3026 # attribute from its backing file instead.
3027 # https://github.com/python/cpython/pull/3249
3028 if hasattr(self.stream, "_file"):
3029 return getattr(self.stream._file, name)
3030 raise
3032 def __iter__(self):
3033 return iter(self.stream)
3035 def __repr__(self):
3036 return f"<{type(self).__name__}: {self.filename!r} ({self.content_type!r})>"
3039# circular dependencies
3040from . import http