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
12
13from . import exceptions
14from ._internal import _missing
15
16
17def is_immutable(self):
18 raise TypeError(f"{type(self).__name__!r} objects are immutable")
19
20
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
36
37
38class ImmutableListMixin:
39 """Makes a :class:`list` immutable.
40
41 .. versionadded:: 0.5
42
43 :private:
44 """
45
46 _hash_cache = None
47
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
53
54 def __reduce_ex__(self, protocol):
55 return type(self), (list(self),)
56
57 def __delitem__(self, key):
58 is_immutable(self)
59
60 def __iadd__(self, other):
61 is_immutable(self)
62
63 def __imul__(self, other):
64 is_immutable(self)
65
66 def __setitem__(self, key, value):
67 is_immutable(self)
68
69 def append(self, item):
70 is_immutable(self)
71
72 def remove(self, item):
73 is_immutable(self)
74
75 def extend(self, iterable):
76 is_immutable(self)
77
78 def insert(self, pos, value):
79 is_immutable(self)
80
81 def pop(self, index=-1):
82 is_immutable(self)
83
84 def reverse(self):
85 is_immutable(self)
86
87 def sort(self, key=None, reverse=False):
88 is_immutable(self)
89
90
91class ImmutableList(ImmutableListMixin, list):
92 """An immutable :class:`list`.
93
94 .. versionadded:: 0.5
95
96 :private:
97 """
98
99 def __repr__(self):
100 return f"{type(self).__name__}({list.__repr__(self)})"
101
102
103class ImmutableDictMixin:
104 """Makes a :class:`dict` immutable.
105
106 .. versionadded:: 0.5
107
108 :private:
109 """
110
111 _hash_cache = None
112
113 @classmethod
114 def fromkeys(cls, keys, value=None):
115 instance = super().__new__(cls)
116 instance.__init__(zip(keys, repeat(value)))
117 return instance
118
119 def __reduce_ex__(self, protocol):
120 return type(self), (dict(self),)
121
122 def _iter_hashitems(self):
123 return self.items()
124
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
130
131 def setdefault(self, key, default=None):
132 is_immutable(self)
133
134 def update(self, *args, **kwargs):
135 is_immutable(self)
136
137 def pop(self, key, default=None):
138 is_immutable(self)
139
140 def popitem(self):
141 is_immutable(self)
142
143 def __setitem__(self, key, value):
144 is_immutable(self)
145
146 def __delitem__(self, key):
147 is_immutable(self)
148
149 def clear(self):
150 is_immutable(self)
151
152
153class ImmutableMultiDictMixin(ImmutableDictMixin):
154 """Makes a :class:`MultiDict` immutable.
155
156 .. versionadded:: 0.5
157
158 :private:
159 """
160
161 def __reduce_ex__(self, protocol):
162 return type(self), (list(self.items(multi=True)),)
163
164 def _iter_hashitems(self):
165 return self.items(multi=True)
166
167 def add(self, key, value):
168 is_immutable(self)
169
170 def popitemlist(self):
171 is_immutable(self)
172
173 def poplist(self, key):
174 is_immutable(self)
175
176 def setlist(self, key, new_list):
177 is_immutable(self)
178
179 def setlistdefault(self, key, default_list=None):
180 is_immutable(self)
181
182
183def _calls_update(name):
184 def oncall(self, *args, **kw):
185 rv = getattr(super(UpdateDictMixin, self), name)(*args, **kw)
186
187 if self.on_update is not None:
188 self.on_update(self)
189
190 return rv
191
192 oncall.__name__ = name
193 return oncall
194
195
196class UpdateDictMixin(dict):
197 """Makes dicts call `self.on_update` on modifications.
198
199 .. versionadded:: 0.5
200
201 :private:
202 """
203
204 on_update = None
205
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
212
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
222
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")
228
229
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.
234
235 .. versionadded:: 0.5
236 """
237
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:
244
245 >>> d = TypeConversionDict(foo='42', bar='blub')
246 >>> d.get('foo', type=int)
247 42
248 >>> d.get('bar', -1, type=int)
249 -1
250
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
269
270
271class ImmutableTypeConversionDict(ImmutableDictMixin, TypeConversionDict):
272 """Works like a :class:`TypeConversionDict` but does not support
273 modifications.
274
275 .. versionadded:: 0.5
276 """
277
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)
284
285 def __copy__(self):
286 return self
287
288
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.
294
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.
300
301 Basic Usage:
302
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
312
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.
315
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.
320
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.
324
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 """
329
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)
349
350 def __getstate__(self):
351 return dict(self.lists())
352
353 def __setstate__(self, value):
354 dict.clear(self)
355 dict.update(self, value)
356
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)
362
363 def __getitem__(self, key):
364 """Return the first data value for this key;
365 raises KeyError if not found.
366
367 :param key: The key to be looked up.
368 :raise KeyError: if the key does not exist.
369 """
370
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)
376
377 def __setitem__(self, key, value):
378 """Like :meth:`add` but removes an existing key first.
379
380 :param key: the key for the value.
381 :param value: the value to set.
382 """
383 dict.__setitem__(self, key, [value])
384
385 def add(self, key, value):
386 """Adds a new value for the key.
387
388 .. versionadded:: 0.6
389
390 :param key: the key for the value.
391 :param value: the value to add.
392 """
393 dict.setdefault(self, key, []).append(value)
394
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.
400
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
420
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.
425
426 >>> d = MultiDict()
427 >>> d.setlist('foo', ['1', '2'])
428 >>> d['foo']
429 '1'
430 >>> d.getlist('foo')
431 ['1', '2']
432
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))
438
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`.
442
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
452
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:
458
459 >>> d = MultiDict({"foo": 1})
460 >>> d.setlistdefault("foo").extend([2, 3])
461 >>> d.getlist("foo")
462 [1, 2, 3]
463
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
476
477 def items(self, multi=False):
478 """Return an iterator of ``(key, value)`` pairs.
479
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]
490
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)
496
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]
501
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`:
505
506 >>> d = MultiDict({"foo": [1, 2, 3]})
507 >>> zip(d.keys(), d.listvalues()) == d.lists()
508 True
509 """
510 return dict.values(self)
511
512 def copy(self):
513 """Return a shallow copy of this object."""
514 return self.__class__(self)
515
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))
519
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.
524
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())
533
534 def update(self, mapping):
535 """update() extends rather than replaces existing key lists:
536
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)])
542
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:
545
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)
554
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:
558
559 >>> d = MultiDict({"foo": [1, 2, 3]})
560 >>> d.pop("foo")
561 1
562 >>> "foo" in d
563 False
564
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)
571
572 if len(lst) == 0:
573 raise exceptions.BadRequestKeyError(key)
574
575 return lst[0]
576 except KeyError:
577 if default is not _missing:
578 return default
579
580 raise exceptions.BadRequestKeyError(key) from None
581
582 def popitem(self):
583 """Pop an item from the dict."""
584 try:
585 item = dict.popitem(self)
586
587 if len(item[1]) == 0:
588 raise exceptions.BadRequestKeyError(item[0])
589
590 return (item[0], item[1][0])
591 except KeyError as e:
592 raise exceptions.BadRequestKeyError(e.args[0]) from None
593
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.
597
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, [])
603
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
610
611 def __copy__(self):
612 return self.copy()
613
614 def __deepcopy__(self, memo):
615 return self.deepcopy(memo=memo)
616
617 def __repr__(self):
618 return f"{type(self).__name__}({list(self.items(multi=True))!r})"
619
620
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 """
627
628 __slots__ = ("prev", "key", "value", "next")
629
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
635
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
641
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
651
652
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``.
657
658 In general an :class:`OrderedMultiDict` is an order of magnitude
659 slower than a :class:`MultiDict`.
660
661 .. admonition:: note
662
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 """
668
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)
674
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
699
700 __hash__ = None
701
702 def __reduce_ex__(self, protocol):
703 return type(self), (list(self.items(multi=True)),)
704
705 def __getstate__(self):
706 return list(self.items(multi=True))
707
708 def __setstate__(self, values):
709 dict.clear(self)
710 for key, value in values:
711 self.add(key, value)
712
713 def __getitem__(self, key):
714 if key in self:
715 return dict.__getitem__(self, key)[0].value
716 raise exceptions.BadRequestKeyError(key)
717
718 def __setitem__(self, key, value):
719 self.poplist(key)
720 self.add(key, value)
721
722 def __delitem__(self, key):
723 self.pop(key)
724
725 def keys(self):
726 return (key for key, value in self.items())
727
728 def __iter__(self):
729 return iter(self.keys())
730
731 def values(self):
732 return (value for key, value in self.items())
733
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
747
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
756
757 def listvalues(self):
758 for _key, values in self.lists():
759 yield values
760
761 def add(self, key, value):
762 dict.setdefault(self, key, []).append(_omd_bucket(self, key, value))
763
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
778
779 def setlist(self, key, new_list):
780 self.poplist(key)
781 for value in new_list:
782 self.add(key, value)
783
784 def setlistdefault(self, key, default_list=None):
785 raise TypeError("setlistdefault is unsupported for ordered multi dicts")
786
787 def update(self, mapping):
788 for key, value in iter_multi_items(mapping):
789 OrderedMultiDict.add(self, key, value)
790
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]
796
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
803
804 raise exceptions.BadRequestKeyError(key) from None
805
806 for bucket in buckets:
807 bucket.unlink(self)
808
809 return buckets[0].value
810
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
816
817 for bucket in buckets:
818 bucket.unlink(self)
819
820 return key, buckets[0].value
821
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
827
828 for bucket in buckets:
829 bucket.unlink(self)
830
831 return key, [x.value for x in buckets]
832
833
834def _options_header_vkw(value, kw):
835 return http.dump_options_header(
836 value, {k.replace("_", "-"): v for k, v in kw.items()}
837 )
838
839
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
846
847
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.
852
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.
855
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.
860
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`.
865
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.
869
870 :param defaults: The list of default values for the :class:`Headers`.
871
872 .. versionchanged:: 2.1.0
873 Default values are validated the same as values added later.
874
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.
879
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 """
884
885 def __init__(self, defaults=None):
886 self._list = []
887 if defaults is not None:
888 self.extend(defaults)
889
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)
908
909 def __eq__(self, other):
910 def lowered(item):
911 return (item[0].lower(),) + item[1:]
912
913 return other.__class__ is self.__class__ and set(
914 map(lowered, other._list)
915 ) == set(map(lowered, self._list))
916
917 __hash__ = None
918
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:
925
926 >>> d = Headers([('Content-Length', '42')])
927 >>> d.get('Content-Length', type=int)
928 42
929
930 .. versionadded:: 0.9
931 Added support for `as_bytes`.
932
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
954
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.
960
961 .. versionadded:: 0.9
962 Added support for `as_bytes`.
963
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
984
985 def get_all(self, name):
986 """Return a list of all the values for the named field.
987
988 This method is compatible with the :mod:`wsgiref`
989 :meth:`~wsgiref.headers.Headers.get_all` method.
990 """
991 return self.getlist(name)
992
993 def items(self, lower=False):
994 for key, value in self:
995 if lower:
996 key = key.lower()
997 yield key, value
998
999 def keys(self, lower=False):
1000 for key, _ in self.items(lower):
1001 yield key
1002
1003 def values(self):
1004 for _, value in self.items():
1005 yield value
1006
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.
1010
1011 To replace existing keys instead of extending, use
1012 :meth:`update` instead.
1013
1014 If provided, the first argument can be another :class:`Headers`
1015 object, a :class:`MultiDict`, :class:`dict`, or iterable of
1016 pairs.
1017
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)}")
1023
1024 if args:
1025 for key, value in iter_multi_items(args[0]):
1026 self.add(key, value)
1027
1028 for key, value in iter_multi_items(kwargs):
1029 self.add(key, value)
1030
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
1041
1042 def remove(self, key):
1043 """Remove a key.
1044
1045 :param key: The key to be removed.
1046 """
1047 return self.__delitem__(key, _index_operation=False)
1048
1049 def pop(self, key=None, default=_missing):
1050 """Removes and returns a key or index.
1051
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
1070
1071 def popitem(self):
1072 """Removes a key or index and returns a (key, value) item."""
1073 return self.pop()
1074
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
1082
1083 def __iter__(self):
1084 """Yield ``(key, value)`` tuples."""
1085 return iter(self._list)
1086
1087 def __len__(self):
1088 return len(self._list)
1089
1090 def add(self, _key, _value, **kw):
1091 """Add a new header tuple to the list.
1092
1093 Keyword arguments can specify additional parameters for the header
1094 value, with underscores converted to dashes::
1095
1096 >>> d = Headers()
1097 >>> d.add('Content-Type', 'text/plain')
1098 >>> d.add('Content-Disposition', 'attachment', filename='foo.png')
1099
1100 The keyword argument dumping uses :func:`dump_options_header`
1101 behind the scenes.
1102
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))
1112
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 )
1121
1122 def add_header(self, _key, _value, **_kw):
1123 """Add a new header tuple to the list.
1124
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)
1129
1130 def clear(self):
1131 """Clears all headers."""
1132 del self._list[:]
1133
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.
1138
1139 Keyword arguments can specify additional parameters for the header
1140 value, with underscores converted to dashes. See :meth:`add` for
1141 more information.
1142
1143 .. versionchanged:: 0.6.1
1144 :meth:`set` now accepts the same arguments as :meth:`add`.
1145
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]
1168
1169 def setlist(self, key, values):
1170 """Remove any existing values for a header and add new ones.
1171
1172 :param key: The header key to set.
1173 :param values: An iterable of values to set for the key.
1174
1175 .. versionadded:: 1.0
1176 """
1177 if values:
1178 values_iter = iter(values)
1179 self.set(key, next(values_iter))
1180
1181 for value in values_iter:
1182 self.add(key, value)
1183 else:
1184 self.remove(key)
1185
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.
1190
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]
1197
1198 self.set(key, default)
1199 return default
1200
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.
1205
1206 Unlike :meth:`MultiDict.setlistdefault`, modifying the returned
1207 list will not affect the headers.
1208
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.
1212
1213 .. versionadded:: 1.0
1214 """
1215 if key not in self:
1216 self.setlist(key, default)
1217
1218 return self.getlist(key)
1219
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)
1237
1238 def update(self, *args, **kwargs):
1239 """Replace headers in this object with items from another
1240 headers object and keyword arguments.
1241
1242 To extend existing keys instead of replacing, use :meth:`extend`
1243 instead.
1244
1245 If provided, the first argument can be another :class:`Headers`
1246 object, a :class:`MultiDict`, :class:`dict`, or iterable of
1247 pairs.
1248
1249 .. versionadded:: 1.0
1250 """
1251 if len(args) > 1:
1252 raise TypeError(f"update expected at most 1 arguments, got {len(args)}")
1253
1254 if args:
1255 mapping = args[0]
1256
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)
1269
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)
1275
1276 def to_wsgi_list(self):
1277 """Convert the headers into a list suitable for WSGI.
1278
1279 :return: list
1280 """
1281 return list(self)
1282
1283 def copy(self):
1284 return self.__class__(self._list)
1285
1286 def __copy__(self):
1287 return self.copy()
1288
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)
1296
1297 def __repr__(self):
1298 return f"{type(self).__name__}({list(self)!r})"
1299
1300
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.
1305
1306 .. versionadded:: 0.5
1307
1308 :private:
1309 """
1310
1311 def __delitem__(self, key, **kwargs):
1312 is_immutable(self)
1313
1314 def __setitem__(self, key, value):
1315 is_immutable(self)
1316
1317 def set(self, _key, _value, **kw):
1318 is_immutable(self)
1319
1320 def setlist(self, key, values):
1321 is_immutable(self)
1322
1323 def add(self, _key, _value, **kw):
1324 is_immutable(self)
1325
1326 def add_header(self, _key, _value, **_kw):
1327 is_immutable(self)
1328
1329 def remove(self, key):
1330 is_immutable(self)
1331
1332 def extend(self, *args, **kwargs):
1333 is_immutable(self)
1334
1335 def update(self, *args, **kwargs):
1336 is_immutable(self)
1337
1338 def insert(self, pos, value):
1339 is_immutable(self)
1340
1341 def pop(self, key=None, default=_missing):
1342 is_immutable(self)
1343
1344 def popitem(self):
1345 is_immutable(self)
1346
1347 def setdefault(self, key, default):
1348 is_immutable(self)
1349
1350 def setlistdefault(self, key, default):
1351 is_immutable(self)
1352
1353
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.
1358
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 """
1364
1365 def __init__(self, environ):
1366 self.environ = environ
1367
1368 def __eq__(self, other):
1369 return self.environ is other.environ
1370
1371 __hash__ = None
1372
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}"])
1382
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)))
1387
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))
1400
1401 def copy(self):
1402 raise TypeError(f"cannot create {type(self).__name__!r} copies")
1403
1404
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:
1409
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'
1418
1419 This works for all read operations and will raise a `TypeError` for
1420 methods that usually change data which isn't possible.
1421
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 """
1427
1428 def __reduce_ex__(self, protocol):
1429 return type(self), (self.dicts,)
1430
1431 def __init__(self, dicts=None):
1432 self.dicts = list(dicts) or []
1433
1434 @classmethod
1435 def fromkeys(cls, keys, value=None):
1436 raise TypeError(f"cannot create {cls.__name__!r} instances by fromkeys")
1437
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)
1443
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
1454
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
1460
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
1468
1469 def keys(self):
1470 return self._keys_impl()
1471
1472 def __iter__(self):
1473 return iter(self.keys())
1474
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
1484
1485 def values(self):
1486 for _key, value in self.items():
1487 yield value
1488
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())
1495
1496 def listvalues(self):
1497 return (x[1] for x in self.lists())
1498
1499 def copy(self):
1500 """Return a shallow mutable copy of this object.
1501
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.
1505
1506 .. versionchanged:: 0.15
1507 Return a mutable :class:`MultiDict`.
1508 """
1509 return MultiDict(self)
1510
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.
1515
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())
1523
1524 return dict(self.lists())
1525
1526 def __len__(self):
1527 return len(self._keys_impl())
1528
1529 def __contains__(self, key):
1530 for d in self.dicts:
1531 if key in d:
1532 return True
1533 return False
1534
1535 def __repr__(self):
1536 return f"{type(self).__name__}({self.dicts!r})"
1537
1538
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.
1543
1544 .. versionadded:: 0.5
1545 """
1546
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.
1550
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)
1568
1569 self.add(name, value)
1570
1571
1572class ImmutableDict(ImmutableDictMixin, dict):
1573 """An immutable :class:`dict`.
1574
1575 .. versionadded:: 0.5
1576 """
1577
1578 def __repr__(self):
1579 return f"{type(self).__name__}({dict.__repr__(self)})"
1580
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)
1587
1588 def __copy__(self):
1589 return self
1590
1591
1592class ImmutableMultiDict(ImmutableMultiDictMixin, MultiDict):
1593 """An immutable :class:`MultiDict`.
1594
1595 .. versionadded:: 0.5
1596 """
1597
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)
1604
1605 def __copy__(self):
1606 return self
1607
1608
1609class ImmutableOrderedMultiDict(ImmutableMultiDictMixin, OrderedMultiDict):
1610 """An immutable :class:`OrderedMultiDict`.
1611
1612 .. versionadded:: 0.6
1613 """
1614
1615 def _iter_hashitems(self):
1616 return enumerate(self.items(multi=True))
1617
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)
1624
1625 def __copy__(self):
1626 return self
1627
1628
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.
1633
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:
1637
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
1647
1648 To get the quality for an item you can use normal item lookup:
1649
1650 >>> print a['utf-8']
1651 0.7
1652 >>> a['utf7']
1653 0
1654
1655 .. versionchanged:: 0.5
1656 :class:`Accept` objects are forced immutable now.
1657
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.
1662
1663 """
1664
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)
1678
1679 def _specificity(self, value):
1680 """Returns a tuple describing the value's specificity."""
1681 return (value != "*",)
1682
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()
1686
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)
1695
1696 def quality(self, key):
1697 """Returns the quality of the key.
1698
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
1707
1708 def __contains__(self, value):
1709 for item, _quality in self:
1710 if self._value_matches(value, item):
1711 return True
1712 return False
1713
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}])"
1717
1718 def index(self, key):
1719 """Get the position of an entry or raise :exc:`ValueError`.
1720
1721 :param key: The key to be looked up.
1722
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)
1733
1734 def find(self, key):
1735 """Get the position of an entry or return -1.
1736
1737 :param key: The key to be looked up.
1738 """
1739 try:
1740 return self.index(key)
1741 except ValueError:
1742 return -1
1743
1744 def values(self):
1745 """Iterate over all values."""
1746 for item in self:
1747 yield item[0]
1748
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)
1757
1758 def __str__(self):
1759 return self.to_header()
1760
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
1767
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.
1772
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
1793
1794 @property
1795 def best(self):
1796 """The best match as value."""
1797 if self:
1798 return self[0][0]
1799
1800
1801_mime_split_re = re.compile(r"/|(?:\s*;\s*)")
1802
1803
1804def _normalize_mime(value):
1805 return _mime_split_re.split(value.lower())
1806
1807
1808class MIMEAccept(Accept):
1809 """Like :class:`Accept` but with special methods and behavior for
1810 mimetypes.
1811 """
1812
1813 def _specificity(self, value):
1814 return tuple(x != "*" for x in _mime_split_re.split(value))
1815
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
1820
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}")
1825
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:])
1830
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}")
1834
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:])
1839
1840 # "*/not-*" from the client is invalid, can't match.
1841 if item_type == "*" and item_subtype != "*":
1842 return False
1843
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 )
1855
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 )
1862
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
1867
1868 @property
1869 def accept_json(self):
1870 """True if this object accepts JSON."""
1871 return "application/json" in self
1872
1873
1874_locale_delim_re = re.compile(r"[_-]")
1875
1876
1877def _normalize_lang(value):
1878 """Process a language tag for matching."""
1879 return _locale_delim_re.split(value.lower())
1880
1881
1882class LanguageAccept(Accept):
1883 """Like :class:`Accept` but with normalization for language tags."""
1884
1885 def _value_matches(self, value, item):
1886 return item == "*" or _normalize_lang(value) == _normalize_lang(item)
1887
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.
1891
1892 Language tags are normalized for the purpose of matching, but
1893 are returned unchanged.
1894
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.
1899
1900 The default is returned if no exact or fallback match is found.
1901
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)
1908
1909 if result is not None:
1910 return result
1911
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)
1919
1920 if result is not None:
1921 return result
1922
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)
1927
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))
1932
1933 return default
1934
1935
1936class CharsetAccept(Accept):
1937 """Like :class:`Accept` but with normalization for charsets."""
1938
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()
1945
1946 return item == "*" or _normalize(value) == _normalize(item)
1947
1948
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.
1952
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 )
1962
1963
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.
1968
1969 Because the cache-control directives in the HTTP header use dashes the
1970 python descriptors use underscores for that.
1971
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.
1976
1977 .. versionchanged:: 2.1.0
1978 Setting int properties such as ``max_age`` will convert the
1979 value to an int.
1980
1981 .. versionchanged:: 0.4
1982
1983 Setting `no_cache` or `private` to boolean `True` will set the implicit
1984 none-value which is ``*``:
1985
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 ''>
1995
1996 In versions before 0.5 the behavior documented here affected the now
1997 no longer existing `CacheControl` class.
1998 """
1999
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)
2004
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
2009
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
2025
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
2043
2044 def _del_cache_value(self, key):
2045 """Used internally by the accessor properties."""
2046 if key in self:
2047 del self[key]
2048
2049 def to_header(self):
2050 """Convert the stored values into a cache control header."""
2051 return http.dump_header(self)
2052
2053 def __str__(self):
2054 return self.to_header()
2055
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}>"
2059
2060 cache_property = staticmethod(cache_control_property)
2061
2062
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.
2066
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.
2071
2072 .. versionchanged:: 2.1.0
2073 Setting int properties such as ``max_age`` will convert the
2074 value to an int.
2075
2076 .. versionadded:: 0.5
2077 In previous versions a `CacheControl` class existed that was used
2078 both for request and response.
2079 """
2080
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)
2084
2085
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.
2090
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.
2095
2096 .. versionchanged:: 2.1.1
2097 ``s_maxage`` converts the value to an int.
2098
2099 .. versionchanged:: 2.1.0
2100 Setting int properties such as ``max_age`` will convert the
2101 value to an int.
2102
2103 .. versionadded:: 0.5
2104 In previous versions a `CacheControl` class existed that was used
2105 both for request and response.
2106 """
2107
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)
2114
2115
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 )
2127
2128
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.
2132
2133 Because the csp directives in the HTTP header use dashes the
2134 python descriptors use underscores for that.
2135
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.
2140
2141 .. versionadded:: 1.0.0
2142 Support for Content Security Policy headers was added.
2143
2144 """
2145
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")
2171
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
2176
2177 def _get_value(self, key):
2178 """Used internally by the accessor properties."""
2179 return self.get(key)
2180
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
2187
2188 def _del_value(self, key):
2189 """Used internally by the accessor properties."""
2190 if key in self:
2191 del self[key]
2192
2193 def to_header(self):
2194 """Convert the stored values into a cache control header."""
2195 return http.dump_csp_header(self)
2196
2197 def __str__(self):
2198 return self.to_header()
2199
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}>"
2203
2204
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 """
2209
2210 def __init__(self, initial=None, on_update=None):
2211 dict.__init__(self, initial or ())
2212 self.on_update = on_update
2213
2214 def __repr__(self):
2215 return f"<{type(self).__name__} {dict.__repr__(self)}>"
2216
2217
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.
2222
2223 If not constructed using the :func:`parse_set_header` function the
2224 instantiation works like this:
2225
2226 >>> hs = HeaderSet(['foo', 'bar', 'baz'])
2227 >>> hs
2228 HeaderSet(['foo', 'bar', 'baz'])
2229 """
2230
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
2235
2236 def add(self, header):
2237 """Add a new header to the set."""
2238 self.update((header,))
2239
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.
2243
2244 .. versionchanged:: 0.5
2245 In older versions a :exc:`IndexError` was raised instead of a
2246 :exc:`KeyError` if the object was missing.
2247
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)
2260
2261 def update(self, iterable):
2262 """Add all the headers from the iterable to the set.
2263
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)
2275
2276 def discard(self, header):
2277 """Like :meth:`remove` but ignores errors.
2278
2279 :param header: the header to be discarded.
2280 """
2281 try:
2282 self.remove(header)
2283 except KeyError:
2284 pass
2285
2286 def find(self, header):
2287 """Return the index of the header in the set or return -1 if not found.
2288
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
2296
2297 def index(self, header):
2298 """Return the index of the header in the set or raise an
2299 :exc:`IndexError`.
2300
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
2307
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)
2314
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.
2318
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)
2327
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))
2331
2332 def __getitem__(self, idx):
2333 return self._headers[idx]
2334
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)
2340
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)
2348
2349 def __contains__(self, header):
2350 return header.lower() in self._set
2351
2352 def __len__(self):
2353 return len(self._set)
2354
2355 def __iter__(self):
2356 return iter(self._headers)
2357
2358 def __bool__(self):
2359 return bool(self._set)
2360
2361 def __str__(self):
2362 return self.to_header()
2363
2364 def __repr__(self):
2365 return f"{type(self).__name__}({self._headers!r})"
2366
2367
2368class ETags(Collection):
2369 """A set that can be used to check if one etag is present in a collection
2370 of etags.
2371 """
2372
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()
2378
2379 self._weak = frozenset(weak_etags or ())
2380 self.star_tag = star_tag
2381
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
2389
2390 def is_weak(self, etag):
2391 """Check if an etag is weak."""
2392 return etag in self._weak
2393
2394 def is_strong(self, etag):
2395 """Check if an etag is strong."""
2396 return etag in self._strong
2397
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)
2401
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)
2409
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)
2418
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 )
2426
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
2436
2437 def __bool__(self):
2438 return bool(self.star_tag or self._strong or self._weak)
2439
2440 def __str__(self):
2441 return self.to_header()
2442
2443 def __len__(self):
2444 return len(self._strong)
2445
2446 def __iter__(self):
2447 return iter(self._strong)
2448
2449 def __contains__(self, etag):
2450 return self.contains(etag)
2451
2452 def __repr__(self):
2453 return f"<{type(self).__name__} {str(self)!r}>"
2454
2455
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.
2460
2461 .. versionadded:: 0.7
2462 """
2463
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
2470
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 ""
2478
2479 def __str__(self):
2480 return self.to_header()
2481
2482 def __repr__(self):
2483 return f"<{type(self).__name__} {str(self)!r}>"
2484
2485
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.
2490
2491 :raise ValueError: If the ranges provided are invalid.
2492
2493 .. versionchanged:: 0.15
2494 The ranges passed in are validated.
2495
2496 .. versionadded:: 0.7
2497 """
2498
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
2505
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.")
2509
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
2525
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
2534
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)}"
2544
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
2553
2554 def __str__(self):
2555 return self.to_header()
2556
2557 def __repr__(self):
2558 return f"<{type(self).__name__} {str(self)!r}>"
2559
2560
2561def _callback_property(name):
2562 def fget(self):
2563 return getattr(self, name)
2564
2565 def fset(self, value):
2566 setattr(self, name, value)
2567 if self.on_update is not None:
2568 self.on_update(self)
2569
2570 return property(fget, fset)
2571
2572
2573class ContentRange:
2574 """Represents the content range header.
2575
2576 .. versionadded:: 0.7
2577 """
2578
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)
2583
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")
2593
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)
2603
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)
2609
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}"
2620
2621 def __bool__(self):
2622 return self.units is not None
2623
2624 def __str__(self):
2625 return self.to_header()
2626
2627 def __repr__(self):
2628 return f"<{type(self).__name__} {str(self)!r}>"
2629
2630
2631class Authorization(ImmutableDictMixin, dict):
2632 """Represents an ``Authorization`` header sent by the client.
2633
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`.
2638
2639 .. versionchanged:: 0.5
2640 This object became immutable.
2641 """
2642
2643 def __init__(self, auth_type, data=None):
2644 dict.__init__(self, data or {})
2645 self.type = auth_type
2646
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")
2653
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")
2660
2661 @property
2662 def realm(self):
2663 """This is the server realm sent back for HTTP digest auth."""
2664 return self.get("realm")
2665
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")
2672
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")
2680
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")
2687
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")
2695
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")
2702
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")
2710
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")
2718
2719 def to_header(self):
2720 """Convert to a string value for an ``Authorization`` header.
2721
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}"
2730
2731 if self.type == "digest":
2732 return f"Digest {http.dump_header(self)}"
2733
2734 raise ValueError(f"Unsupported type {self.type!r}.")
2735
2736
2737def auth_property(name, doc=None):
2738 """A static helper function for Authentication subclasses to add
2739 extra authentication system properties onto a class::
2740
2741 class FooAuthenticate(WWWAuthenticate):
2742 special_realm = auth_property('special_realm')
2743
2744 For more information have a look at the sourcecode to see how the
2745 regular properties (:attr:`realm` etc.) are implemented.
2746 """
2747
2748 def _set_value(self, value):
2749 if value is None:
2750 self.pop(name, None)
2751 else:
2752 self[name] = str(value)
2753
2754 return property(lambda x: x.get(name), _set_value, doc=doc)
2755
2756
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()
2764
2765 return http.parse_set_header(self.get(name), on_update)
2766
2767 return property(fget, doc=doc)
2768
2769
2770class WWWAuthenticate(UpdateDictMixin, dict):
2771 """Provides simple access to `WWW-Authenticate` headers."""
2772
2773 #: list of keys that require quoting in the generated header
2774 _require_quoting = frozenset(["domain", "nonce", "opaque", "realm", "qop"])
2775
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
2781
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)
2788
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)
2809
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}"
2820
2821 def __str__(self):
2822 return self.to_header()
2823
2824 def __repr__(self):
2825 return f"<{type(self).__name__} {self.to_header()!r}>"
2826
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 )
2874
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"
2883
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"
2890
2891 auth_property = staticmethod(auth_property)
2892
2893
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 """
2901
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()
2913
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)
2919
2920 if filename is not None:
2921 filename = os.fsdecode(filename)
2922
2923 if filename and filename[0] == "<" and filename[-1] == ">":
2924 filename = None
2925 else:
2926 filename = os.fsdecode(filename)
2927
2928 self.filename = filename
2929
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)
2937
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)
2941
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")
2946
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
2954
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'``.
2961
2962 .. versionadded:: 0.7
2963 """
2964 self._parse_content_type()
2965 return self._parsed_content_type[0].lower()
2966
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'}``.
2972
2973 .. versionadded:: 0.7
2974 """
2975 self._parse_content_type()
2976 return self._parsed_content_type[1]
2977
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.
2983
2984 For secure file saving also have a look at :func:`secure_filename`.
2985
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`.
2990
2991 .. versionchanged:: 1.0
2992 Supports :mod:`pathlib`.
2993 """
2994 from shutil import copyfileobj
2995
2996 close_dst = False
2997
2998 if hasattr(dst, "__fspath__"):
2999 dst = fspath(dst)
3000
3001 if isinstance(dst, str):
3002 dst = open(dst, "wb")
3003 close_dst = True
3004
3005 try:
3006 copyfileobj(self.stream, dst, buffer_size)
3007 finally:
3008 if close_dst:
3009 dst.close()
3010
3011 def close(self):
3012 """Close the underlying file if possible."""
3013 try:
3014 self.stream.close()
3015 except Exception:
3016 pass
3017
3018 def __bool__(self):
3019 return bool(self.filename)
3020
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
3031
3032 def __iter__(self):
3033 return iter(self.stream)
3034
3035 def __repr__(self):
3036 return f"<{type(self).__name__}: {self.filename!r} ({self.content_type!r})>"
3037
3038
3039# circular dependencies
3040from . import http