1from __future__ import annotations
2
3import collections.abc as cabc
4import functools
5import json
6import typing as t
7import wsgiref.types as wt
8from io import BytesIO
9from types import TracebackType
10
11from .._internal import _wsgi_decoding_dance
12from ..datastructures.file_storage import FileStorage
13from ..datastructures.headers import EnvironHeaders
14from ..datastructures.structures import CombinedMultiDict
15from ..datastructures.structures import ImmutableMultiDict
16from ..datastructures.structures import iter_multi_items
17from ..datastructures.structures import MultiDict
18from ..exceptions import BadRequest
19from ..exceptions import RequestEntityTooLarge
20from ..exceptions import UnsupportedMediaType
21from ..formparser import _FormDataParser
22from ..formparser import _make_stream_factory
23from ..sansio.request import Request as _SansIORequest
24from ..utils import cached_property
25from ..wsgi import _FileWrapper
26from ..wsgi import _get_server
27from ..wsgi import _LimitedStream
28
29T = t.TypeVar("T")
30
31
32class Request(_SansIORequest):
33 """Represents an incoming WSGI HTTP request, with headers and body
34 taken from the WSGI environment. Has properties and methods for
35 using the functionality defined by various HTTP specs. The data in
36 requests object is read-only.
37
38 Text data is assumed to use UTF-8 encoding, which should be true for
39 the vast majority of modern clients. Using an encoding set by the
40 client is unsafe in Python due to extra encodings it provides, such
41 as ``zip``. To change the assumed encoding, subclass and replace
42 :attr:`charset`.
43
44 :param environ: The WSGI environ is generated by the WSGI server and
45 contains information about the server configuration and client
46 request.
47 :param shallow: Makes reading from :attr:`stream` (and any method
48 that would read from it) raise a :exc:`RuntimeError`. Useful to
49 prevent consuming the form data in middleware, which would make
50 it unavailable to the final application.
51
52 .. versionchanged:: 3.2
53 The ``populate_request`` parameter is deprecated and will be removed in
54 Werkzeug 4.0. ``environ["werkzeug.request"]`` will no longer be set.
55
56 .. versionchanged:: 3.0
57 The ``charset``, ``url_charset``, and ``encoding_errors`` parameters
58 were removed.
59
60 .. versionchanged:: 2.1
61 Old ``BaseRequest`` and mixin classes were removed.
62
63 .. versionchanged:: 2.1
64 Remove the ``disable_data_descriptor`` attribute.
65
66 .. versionchanged:: 2.0
67 Combine ``BaseRequest`` and mixins into a single ``Request``
68 class.
69
70 .. versionchanged:: 0.5
71 Read-only mode is enforced with immutable classes for all data.
72 """
73
74 max_content_length: int | None = None
75 """Stop reading data after this many bytes and raise
76 :exc:`.RequestEntityTooLarge`. This amount of memory, plus additional object
77 overhead, could be used during one request.
78
79 It's better to configure this in the WSGI server or HTTP server, rather than
80 the WSGI application, which is why it's not set by default. Not setting it
81 anywhere would be an issue with that application, not with Werkzeug.
82
83 This is applied to :attr:`stream` and anything that reads it such as
84 :attr:`data` and :meth:`parse_form_data`.
85
86 .. versionadded:: 0.5
87 """
88
89 max_form_memory_size: int | None = 500_000
90 """Stop parsing ``multipart/form-data`` if any non-file part is larger than
91 this number of bytes, and raise :exc:`.RequestEntityTooLarge`. File parts
92 can be larger, they are moved to disk at this limit. The default is 500kB.
93 This is an additional check, it does not replace :attr:`max_content_length`.
94
95 .. versionchanged:: 3.1.9
96 This is not applied to ``application/x-www-form-urlencoded``.
97
98 .. versionchanged:: 3.1
99 Defaults to 500kb instead of unlimited.
100
101 .. versionadded:: 0.5
102 """
103
104 max_form_parts = 1000
105 """Stop parsing ``multipart/form-data`` if more than this number of parts
106 are received, and raise :exc:`.RequestEntityTooLarge`. This is useful to
107 stop a very large number of very small fields, especially files. The
108 default is 1000. This is an additional check, it does not replace
109 :attr:`max_content_length`.
110
111 .. versionadded:: 2.2.3
112 """
113
114 form_data_parser_class: None = None
115 """The class to use to parse form data.
116
117 .. deprecated:: 3.2
118 Will be removed in Werkzeug 4.0. Override ``parse_form_data`` instead.
119 """
120
121 #: The WSGI environment containing HTTP headers and information from
122 #: the WSGI server.
123 environ: wt.WSGIEnvironment
124
125 #: Set when creating the request object. If ``True``, reading from
126 #: the request body will cause a ``RuntimeException``. Useful to
127 #: prevent modifying the stream from middleware.
128 shallow: bool
129
130 def __init__(
131 self,
132 environ: wt.WSGIEnvironment,
133 populate_request: None = None,
134 shallow: bool = False,
135 ) -> None:
136 super().__init__(
137 method=environ.get("REQUEST_METHOD", "GET"),
138 scheme=environ.get("wsgi.url_scheme", "http"),
139 server=_get_server(environ),
140 root_path=_wsgi_decoding_dance(environ.get("SCRIPT_NAME") or ""),
141 path=_wsgi_decoding_dance(environ.get("PATH_INFO") or ""),
142 query_string=environ.get("QUERY_STRING", "").encode("latin1"),
143 headers=EnvironHeaders(environ),
144 remote_addr=environ.get("REMOTE_ADDR"),
145 )
146 self.environ = environ
147 self.shallow = shallow
148
149 if populate_request is not None:
150 import warnings
151
152 warnings.warn(
153 "The 'populate_request' parameter is deprecated and will be"
154 " removed in Werkzeug 4.0. 'environ[\"werkzeug.request\"]' will"
155 " no longer be set.",
156 DeprecationWarning,
157 stacklevel=2,
158 )
159 else:
160 populate_request = True # type: ignore[assignment]
161
162 if populate_request and not shallow:
163 self.environ["werkzeug.request"] = self
164
165 @classmethod
166 def from_values(cls, *args: t.Any, **kwargs: t.Any) -> t.Self:
167 """Create a new request object based on the values provided. If
168 environ is given missing values are filled from there. This method is
169 useful for small scripts when you need to simulate a request from an URL.
170 Do not use this method for unittesting, there is a full featured client
171 object (:class:`Client`) that allows to create multipart requests,
172 support for cookies etc.
173
174 This accepts the same options as the
175 :class:`~werkzeug.test.EnvironBuilder`.
176
177 .. versionchanged:: 0.5
178 This method now accepts the same arguments as
179 :class:`~werkzeug.test.EnvironBuilder`. Because of this the
180 `environ` parameter is now called `environ_overrides`.
181
182 :return: request object
183 """
184 from ..test import EnvironBuilder
185
186 with EnvironBuilder(*args, **kwargs) as builder:
187 return builder.get_request(cls) # type: ignore[return-value]
188
189 @t.overload
190 @classmethod
191 def application(
192 cls, f: t.Callable[[T, t.Self], wt.WSGIApplication]
193 ) -> t.Callable[[T, wt.WSGIEnvironment, wt.StartResponse], t.Iterable[bytes]]: ...
194 @t.overload
195 @classmethod
196 def application(
197 cls, f: t.Callable[[t.Self], wt.WSGIApplication]
198 ) -> wt.WSGIApplication: ...
199 @classmethod
200 def application(
201 cls, f: t.Callable[..., wt.WSGIApplication]
202 ) -> t.Callable[..., t.Iterable[bytes]]:
203 """Create a WSGI application by decorating a function that takes a
204 :class:`Request` and returns a :class:`.Response`. If the function
205 raises an :exc:`.HTTPException`, it will be converted to an error
206 response. :meth:`Request.close` is called when returning.
207
208 .. code-block:: python
209
210 @Request.application
211 def my_wsgi_app(request: Request) -> Response:
212 return Response("Hello, World!")
213
214 If a request was already created with ``populate_request=True`` (the
215 default) it will be taken from``environ["werkzeug.request"]`` instead of
216 creating a new object.
217
218 :param f: The application callable.
219
220 .. versionchanged:: 0.14
221 ``HTTPException`` is caught and converted to a response.
222 """
223 from ..exceptions import HTTPException
224
225 @functools.wraps(f)
226 def application(*args: t.Any) -> cabc.Iterable[bytes]:
227 # Allow either a function (environ, start_response) or a
228 # bound method (self, environ, start_response).
229 *rest, environ, start_response = args
230
231 with cls(environ) as request:
232 try:
233 response = f(*rest, request)
234 except HTTPException as e:
235 response = e.get_response()
236
237 return response(request.environ, start_response)
238
239 return application
240
241 def _get_file_stream(
242 self,
243 total_content_length: int | None,
244 content_type: str | None,
245 filename: str | None = None,
246 content_length: int | None = None,
247 ) -> t.IO[bytes]:
248 """Called to get a stream for the file upload.
249
250 This must provide a file-like class with `read()`, `readline()`
251 and `seek()` methods that is both writeable and readable.
252
253 The default implementation returns a temporary file if the total
254 content length is higher than 500KB. Because many browsers do not
255 provide a content length for the files only the total content
256 length matters.
257
258 :param total_content_length: the total content length of all the
259 data in the request combined. This value
260 is guaranteed to be there.
261 :param content_type: the mimetype of the uploaded file.
262 :param filename: the filename of the uploaded file. May be `None`.
263 :param content_length: the length of this file. This value is usually
264 not provided because webbrowsers do not provide
265 this value.
266
267 .. deprecated:: 3.2
268 Will be removed in Werkzeug 4.0. Override ``_parse_form_data`` instead.
269 """
270 import warnings
271
272 warnings.warn(
273 "'_get_file_stream' is deprecated and will be removed in Werkzeug 4.0."
274 " Override '_parse_form_data` instead.",
275 DeprecationWarning,
276 stacklevel=2,
277 )
278 return _make_stream_factory(self.max_form_memory_size)(None, None, None, None)
279
280 @property
281 def want_form_data_parsed(self) -> bool:
282 """``True`` if the request method carries content. By default
283 this is true if a ``Content-Type`` is sent.
284
285 .. deprecated:: 3.2
286 Will be removed in Werkzeug 4.0. Override ``_parse_form_data`` instead.
287
288 .. versionadded:: 0.8
289 """
290 import warnings
291
292 warnings.warn(
293 "'want_form_data_parsed' is deprecated and will be removed in Werkzeug 4.0."
294 " Override '_parse_form_data' instead.",
295 DeprecationWarning,
296 stacklevel=2,
297 )
298 return self.content_type is not None
299
300 def make_form_data_parser(self) -> _FormDataParser:
301 """Creates the form data parser. Instantiates the
302 :attr:`form_data_parser_class` with some parameters.
303
304 .. deprecated:: 3.2
305 Will be removed in Werkzeug 4.0. Override ``_parse_form_data`` instead.
306
307 .. versionadded:: 0.8
308 """
309 import warnings
310
311 warnings.warn(
312 "'make_form_data_parser' is deprecated and will be removed in Werkzeug 4.0."
313 " Override '_parse_form_data' instead.",
314 DeprecationWarning,
315 stacklevel=2,
316 )
317 return self._private_make_form_data_parser()
318
319 def _private_make_form_data_parser(self) -> _FormDataParser:
320 kwargs: dict[str, t.Any] = {
321 "max_form_memory_size": self.max_form_memory_size,
322 "max_content_length": self.max_content_length,
323 "max_form_parts": self.max_form_parts,
324 }
325
326 if type(self)._get_file_stream is not Request._get_file_stream:
327 import warnings
328
329 warnings.warn(
330 "'Request._get_file_stream' is deprecated and will not be used in"
331 " Werkzeug 4.0. Override '_parse_form_data' instead.",
332 DeprecationWarning,
333 stacklevel=1,
334 )
335 kwargs["stream_factory"] = self._get_file_stream
336
337 if self.parameter_storage_class is not None:
338 import warnings
339
340 warnings.warn(
341 "Setting 'Request.parameter_storage_class' is deprecated and will be"
342 " removed in Werkzeug 4.0. It will always be 'ImmutableMultiDict'.",
343 DeprecationWarning,
344 stacklevel=1,
345 )
346 kwargs["cls"] = self.parameter_storage_class
347
348 if self.form_data_parser_class is not None:
349 import warnings
350
351 warnings.warn(
352 "Setting 'Request.form_data_parser_class' is deprecated and will be"
353 " removed in Werkzeug 4.0. Override '_parse_form_data' instead.",
354 DeprecationWarning,
355 stacklevel=1,
356 )
357 return self.form_data_parser_class(**kwargs)
358
359 return _FormDataParser(**kwargs)
360
361 def _parse_form_data(
362 self, stream: t.IO[bytes]
363 ) -> tuple[MultiDict[str, str], MultiDict[str, FileStorage]] | None:
364 """Parse the given stream as form data.
365
366 :param stream: The stream to read the data from.
367 :return: ``(form, files)``, or ``None`` if the data could not be parsed.
368
369 .. versionadded:: 3.2
370 """
371 if type(self).make_form_data_parser is not Request.make_form_data_parser:
372 import warnings
373
374 warnings.warn(
375 "'Request.make_form_data_parser' is deprecated and will not be used in"
376 " Werkzeug 4.0. Override `_parse_form_data` instead.",
377 DeprecationWarning,
378 stacklevel=1,
379 )
380 parser = self.make_form_data_parser()
381 else:
382 # TODO inline after deprecation
383 parser = self._private_make_form_data_parser()
384
385 _, form, files = parser.parse(
386 stream=stream,
387 mimetype=self.mimetype,
388 content_length=self.content_length,
389 options=self.mimetype_params,
390 )
391 return form, files
392
393 def _load_form_data(self) -> None:
394 """Internal method to parse and cache form data.
395
396 .. versionadded:: 0.8
397
398 :meta private:
399 """
400 if "form" in self.__dict__:
401 # The data has already been parsed and cached.
402 return
403
404 if type(self).want_form_data_parsed is not Request.want_form_data_parsed:
405 import warnings
406
407 warnings.warn(
408 "'Request.want_form_data_parsed' is deprecated and will be removed in"
409 " Werkzeug 4.0. Override '_parse_form_data' instead.",
410 DeprecationWarning,
411 stacklevel=1,
412 )
413
414 if not self.want_form_data_parsed:
415 if self.parameter_storage_class is not None:
416 import warnings
417
418 warnings.warn(
419 "Setting 'Request.parameter_storage_class' is deprecated and"
420 " will be removed in Werkzeug 4.0. It will always be"
421 " 'ImmutableMultiDict'.",
422 DeprecationWarning,
423 stacklevel=1,
424 )
425 self.form = self.parameter_storage_class()
426 self.files = self.parameter_storage_class()
427 else:
428 self.form = ImmutableMultiDict()
429 self.files = ImmutableMultiDict()
430 else:
431 if (
432 type(self)._get_stream_for_parsing
433 is not Request._get_stream_for_parsing
434 ):
435 import warnings
436
437 warnings.warn(
438 "'Request._get_stream_for_parsing' is deprecated and will not be"
439 " used in Werkzeug 4.0. It is handled internally.",
440 DeprecationWarning,
441 stacklevel=1,
442 )
443 stream = self._get_stream_for_parsing()
444 else:
445 # TODO inline after deprecation
446 stream = self._private_get_stream_for_parsing()
447
448 result = self._parse_form_data(stream)
449
450 if result is None:
451 self.form = ImmutableMultiDict()
452 self.files = ImmutableMultiDict()
453 else:
454 self.form, self.files = result # type: ignore[assignment]
455
456 def _get_stream_for_parsing(self) -> t.IO[bytes]:
457 """Access :attr:`stream`. If :meth:`get_data` has already read and
458 cached the data, return a stream of the cached data instead.
459
460 .. deprecated:: 3.2
461 Will be removed in Werkzeug 4.0. Override ``_parse_form_data`` instead.
462
463 .. versionadded:: 0.9.3
464 """
465 import warnings
466
467 warnings.warn(
468 "'_get_stream_for_parsing' is deprecated and will be removed in Werkzeug"
469 " 4.0. Override '_parse_form_data' instead.",
470 DeprecationWarning,
471 stacklevel=2,
472 )
473 return self._private_get_stream_for_parsing()
474
475 def _private_get_stream_for_parsing(self) -> t.IO[bytes]:
476 if self._cached_data is not None:
477 return BytesIO(self._cached_data)
478
479 return self.stream
480
481 def close(self) -> None:
482 """Closes associated resources of this request object. This
483 closes all file handles explicitly. You can also use the request
484 object in a with statement which will automatically close it.
485
486 .. versionadded:: 0.9
487 """
488 files = self.__dict__.get("files")
489 for _key, value in iter_multi_items(files or ()):
490 value.close()
491
492 def __enter__(self) -> Request:
493 return self
494
495 def __exit__(
496 self,
497 exc_type: type[BaseException] | None,
498 exc_val: BaseException | None,
499 exc_tb: TracebackType | None,
500 ) -> None:
501 self.close()
502
503 @cached_property
504 def stream(self) -> t.IO[bytes]:
505 """The WSGI input stream, wrapped so that it may be read safely and not
506 past the ``Content-Length`` header or :attr:`max_content_length`.
507
508 Use :meth:`get_data` to get the full data as bytes or text. The
509 :attr:`data` attribute will contain the full bytes only if they do not
510 represent form data. The :attr:`form` and :attr:`files` attributes will
511 contain the parsed form data in that case.
512
513 If the client sends ``Content-Length``, :attr:`max_content_length` can
514 be checked immediately, or if that's not set the stream will be limited
515 to ``Content-Length``. If the client does not send ``Content-Length``,
516 it is not safe to read and an empty stream is returned.
517
518 However, the WSGI server can set ``environ["wsgi.input_terminated"]`` to
519 indicate that it handles input without ``Content-Length``, such as by
520 using non-blocking reads, buffering, and termination. This does not mean
521 the stream might not be infinite, only that it is now safe to read.
522 Therefore, you should still set :attr:`max_content_length`.
523
524 If the limit is reached before the underlying stream is exhausted, its
525 remaining content cannot be read safely. Depending on how the server
526 handles this, clients may show a "connection reset" failure instead of
527 seeing the 413 response.
528
529 :raise .RequestEntityTooLarge: If :attr:`max_content_length` is exceeded.
530
531 .. versionchanged:: 2.3.2
532 ``max_content_length`` is only applied to requests if the server
533 sets ``wsgi.input_terminated``.
534
535 .. versionchanged:: 2.3
536 Check ``max_content_length`` preemptively and while reading.
537
538 .. versionchanged:: 0.9
539 The stream remains available (but consumed) if form parsing was
540 accessed first.
541 """
542 if self.shallow:
543 raise RuntimeError(
544 "This request was created with 'shallow=True', reading"
545 " from the input stream is disabled."
546 )
547
548 stream: t.IO[bytes] = self.environ["wsgi.input"]
549
550 if (
551 self.content_length is not None
552 and self.max_content_length is not None
553 and self.content_length > self.max_content_length
554 ):
555 raise RequestEntityTooLarge()
556
557 # A WSGI server can set this to indicate that it terminates the input
558 # stream. In that case the stream is safe without wrapping, or can
559 # enforce a max length.
560 if "wsgi.input_terminated" in self.environ:
561 if self.max_content_length is not None:
562 # If this is moved above, it can cause the stream to hang if a
563 # read attempt is made when the client sends no data. For
564 # example, the development server does not handle buffering
565 # except for chunked encoding.
566 return _LimitedStream(stream, self.max_content_length, is_max=True) # type: ignore[return-value]
567
568 return stream
569
570 # No limit given, stream can't be read safely, return empty.
571 if self.content_length is None:
572 return BytesIO()
573
574 return _LimitedStream(stream, self.content_length) # type: ignore[return-value]
575
576 @property
577 def input_stream(self) -> t.IO[bytes]:
578 """The raw WSGI input stream, without any safety checks.
579
580 This is dangerous to use. It does not guard against infinite streams or
581 reading past :attr:`content_length` or :attr:`max_content_length`.
582
583 Use :attr:`stream` instead.
584
585 .. deprecated:: 3.2
586 Will be removed in Werkzeug 4.0. Use ``environ["REMOTE_USER"]`` instead.
587 """
588 import warnings
589
590 warnings.warn(
591 "The 'input_stream' attribute is deprecated and will be removed in"
592 " Werkzeug 4.0. Use 'stream' instead.",
593 DeprecationWarning,
594 stacklevel=2,
595 )
596 return self.environ["wsgi.input"] # type: ignore[no-any-return]
597
598 @cached_property
599 def data(self) -> bytes:
600 """The raw data read from :attr:`stream`. Will be empty if the request
601 represents form data.
602
603 Typically, you'll want to access :attr:`form`, :attr:`files`, or
604 :attr:`json`. You only need this if the body is in another format.
605
606 To get the raw data even if it represents form data, use :meth:`get_data`.
607 """
608 return self.get_data(parse_form_data=True)
609
610 _cached_data: bytes | None = None
611
612 @t.overload
613 def get_data(
614 self,
615 cache: bool = True,
616 as_text: t.Literal[False] = False,
617 parse_form_data: bool = False,
618 ) -> bytes: ...
619
620 @t.overload
621 def get_data(
622 self,
623 cache: bool = True,
624 as_text: t.Literal[True] = ...,
625 parse_form_data: bool = False,
626 ) -> str: ...
627
628 def get_data(
629 self, cache: bool = True, as_text: bool = False, parse_form_data: bool = False
630 ) -> bytes | str:
631 """The raw data read from :attr:`stream`.
632
633 Typically, you'll want to access :attr:`form`, :attr:`files`, or
634 :attr:`json`. You only need this if the body is in another format.
635
636 See :attr:`stream` for how the input is read safely. In summary, either
637 the client must send the ``Content-Length`` header, or the WSGI server
638 must handle terminating input. Otherwise, an empty stream is returned.
639 Set :attr:`max_content_length` to prevent infinite streams, otherwise
640 this call may block forever.
641
642 :param cache: Cache the result. Otherwise, subsequent calls will return
643 empty. If you know you'll only access it once, disabling this is
644 more efficient.
645 :param as_text: Decode the bytes as UTF-8 and return a string.
646 :param parse_form_data: Parse the body as form data if possible. This
647 will then return empty, since the data is in :attr:`form` and
648 :attr:`files`. :attr:`data` is a shortcut for this.
649 :raise .RequestEntityTooLarge: If :attr:`max_content_length` is exceeded.
650
651 .. versionadded:: 0.9
652 """
653 if (data := self._cached_data) is None:
654 if parse_form_data:
655 self._load_form_data()
656
657 data = self.stream.read()
658
659 if cache:
660 self._cached_data = data
661
662 if as_text:
663 return data.decode(errors="replace")
664
665 return data
666
667 @cached_property
668 def form(self) -> ImmutableMultiDict[str, str]:
669 """The parsed form text fields as an :class:`.ImmutableMultiDict`. File
670 fields are in :attr:`files`, not here.
671
672 .. versionchanged:: 0.9
673 Works for any method, not only ``POST`` and ``PUT``.
674 """
675 self._load_form_data()
676 return self.form
677
678 @cached_property
679 def values(self) -> CombinedMultiDict[str, str]:
680 """A :class:`werkzeug.datastructures.CombinedMultiDict` that
681 combines :attr:`args` and :attr:`form`.
682
683 For GET requests, only ``args`` are present, not ``form``.
684
685 .. versionchanged:: 2.0
686 For GET requests, only ``args`` are present, not ``form``.
687 """
688 sources = [self.args]
689
690 if self.method != "GET":
691 # GET requests can have a body, and some caching proxies
692 # might not treat that differently than a normal GET
693 # request, allowing form data to "invisibly" affect the
694 # cache without indication in the query string / URL.
695 sources.append(self.form)
696
697 args = []
698
699 for d in sources:
700 # TODO remove with parameter_storage_class
701 if not isinstance(d, MultiDict):
702 d = MultiDict(d)
703
704 args.append(d)
705
706 return CombinedMultiDict(args)
707
708 @cached_property
709 def files(self) -> ImmutableMultiDict[str, FileStorage]:
710 """The parsed form file fields as an :class:`.ImmutableMultiDict`. Text
711 fields are in :attr:`form`, not here.
712
713 This will only be populated if the HTML form has the
714 ``enctype=multipart/form-data`` attribute.
715
716 Each value is a :class:`.FileStorage` object. ``FileStorage`` is
717 file-like, for example it has a ``read()`` method and is iterable. The
718 :meth:`~.FileStorage.save` method can be used to save the data, along
719 with the :func:`.secure_filename` function.
720 """
721 self._load_form_data()
722 return self.files
723
724 @property
725 def script_root(self) -> str:
726 """Alias for :attr:`self.root_path`. ``environ["SCRIPT_NAME"]``
727 without a trailing slash.
728 """
729 return self.root_path
730
731 @cached_property
732 def url_root(self) -> str:
733 """Alias for :attr:`root_url`. The URL with scheme, host, and
734 root path. For example, ``https://example.com/app/``.
735 """
736 return self.root_url
737
738 @property
739 def remote_user(self) -> str | None:
740 """The ``REMOTE_USER`` CGI variable from :attr:`environ`.
741
742 .. deprecated:: 3.2
743 Will be removed in Werkzeug 4.0. Use ``environ["REMOTE_USER"]`` instead.
744 """
745 import warnings
746
747 warnings.warn(
748 "The 'remote_user' attribute is deprecated and will be removed in"
749 " Werkzeug 4.0. Use 'environ[\"REMOTE_USER\"]' instead.",
750 DeprecationWarning,
751 stacklevel=2,
752 )
753 return self.environ.get("REMOTE_USER")
754
755 @property
756 def is_multithread(self) -> str | None:
757 """Indicates the WSGI server uses thread workers.
758
759 .. deprecated:: 3.2
760 Will be removed in Werkzeug 4.0. Use
761 ``environ["wsgi.multithread"]`` instead.
762 """
763 import warnings
764
765 warnings.warn(
766 "The 'is_multithread' attribute is deprecated and will be removed in"
767 " Werkzeug 4.0. Use 'environ[\"wsgi.multithread\"]' instead.",
768 DeprecationWarning,
769 stacklevel=2,
770 )
771 return self.environ["wsgi.multithread"] # type: ignore[no-any-return]
772
773 @property
774 def is_multiprocess(self) -> str | None:
775 """Indicates the WSGI server uses process workers.
776
777 .. deprecated:: 3.2
778 Will be removed in Werkzeug 4.0. Use
779 ``environ["wsgi.multiprocess"]`` instead.
780 """
781 import warnings
782
783 warnings.warn(
784 "The 'is_multiprocess' attribute is deprecated and will be removed in"
785 " Werkzeug 4.0. Use 'environ[\"wsgi.multiprocess\"]' instead.",
786 DeprecationWarning,
787 stacklevel=2,
788 )
789 return self.environ["wsgi.multiprocess"] # type: ignore[no-any-return]
790
791 @property
792 def is_run_once(self) -> str | None:
793 """Indicates the WSGI server process will start, handle one request,
794 then stop. This may be the case for CGI.
795
796 .. deprecated:: 3.2
797 Will be removed in Werkzeug 4.0. Use
798 ``environ["wsgi.run_once"]`` instead.
799 """
800 import warnings
801
802 warnings.warn(
803 "The 'is_run_once' attribute is deprecated and will be removed in"
804 " Werkzeug 4.0. Use 'environ[\"wsgi.run_once\"]' instead.",
805 DeprecationWarning,
806 stacklevel=2,
807 )
808 return self.environ["wsgi.run_once"] # type: ignore[no-any-return]
809
810 # JSON
811
812 #: A module or other object that has ``dumps`` and ``loads``
813 #: functions that match the API of the built-in :mod:`json` module.
814 json_module = json
815
816 @property
817 def json(self) -> t.Any:
818 """The parsed JSON data if :attr:`mimetype` indicates JSON
819 (:mimetype:`application/json`, see :attr:`is_json`).
820
821 Calls :meth:`get_json` with default arguments.
822
823 If the request content type is not ``application/json``, this
824 will raise a 415 Unsupported Media Type error.
825
826 .. versionchanged:: 2.3
827 Raise a 415 error instead of 400.
828
829 .. versionchanged:: 2.1
830 Raise a 400 error if the content type is incorrect.
831 """
832 return self.get_json()
833
834 # Cached values for ``(silent=False, silent=True)``. Initialized
835 # with sentinel values.
836 _cached_json: tuple[t.Any, t.Any] = (Ellipsis, Ellipsis)
837
838 @t.overload
839 def get_json(
840 self, force: bool = ..., silent: t.Literal[False] = ..., cache: bool = ...
841 ) -> t.Any: ...
842
843 @t.overload
844 def get_json(
845 self, force: bool = ..., silent: bool = ..., cache: bool = ...
846 ) -> t.Any | None: ...
847
848 def get_json(
849 self, force: bool = False, silent: bool = False, cache: bool = True
850 ) -> t.Any | None:
851 """Parse :attr:`data` as JSON.
852
853 If the mimetype does not indicate JSON
854 (:mimetype:`application/json`, see :attr:`is_json`), or parsing
855 fails, :meth:`on_json_loading_failed` is called and
856 its return value is used as the return value. By default this
857 raises a 415 Unsupported Media Type resp.
858
859 :param force: Ignore the mimetype and always try to parse JSON.
860 :param silent: Silence mimetype and parsing errors, and
861 return ``None`` instead.
862 :param cache: Store the parsed JSON to return for subsequent
863 calls.
864
865 .. versionchanged:: 2.3
866 Raise a 415 error instead of 400.
867
868 .. versionchanged:: 2.1
869 Raise a 400 error if the content type is incorrect.
870 """
871 if cache and self._cached_json[silent] is not Ellipsis:
872 return self._cached_json[silent]
873
874 if not (force or self.is_json):
875 if not silent:
876 return self.on_json_loading_failed(None)
877 else:
878 return None
879
880 data = self.get_data(cache=cache)
881
882 try:
883 rv = self.json_module.loads(data)
884 except ValueError as e:
885 if silent:
886 rv = None
887
888 if cache:
889 normal_rv, _ = self._cached_json
890 self._cached_json = (normal_rv, rv)
891 else:
892 rv = self.on_json_loading_failed(e)
893
894 if cache:
895 _, silent_rv = self._cached_json
896 self._cached_json = (rv, silent_rv)
897 else:
898 if cache:
899 self._cached_json = (rv, rv)
900
901 return rv
902
903 def on_json_loading_failed(self, e: ValueError | None) -> t.Any:
904 """Called if :meth:`get_json` fails and isn't silenced.
905
906 If this method returns a value, it is used as the return value
907 for :meth:`get_json`. The default implementation raises
908 :exc:`~werkzeug.exceptions.BadRequest`.
909
910 :param e: If parsing failed, this is the exception. It will be
911 ``None`` if the content type wasn't ``application/json``.
912
913 .. versionchanged:: 2.3
914 Raise a 415 error instead of 400.
915 """
916 if e is not None:
917 raise BadRequest(f"Failed to decode JSON object: {e}")
918
919 raise UnsupportedMediaType(
920 "Did not attempt to load JSON data because the request"
921 " Content-Type was not 'application/json'."
922 )
923
924 def wrap_file(
925 self, file: t.IO[bytes], buffer_size: int = 128 * 1024
926 ) -> cabc.Iterable[bytes]:
927 """Wrap a file with ``environ["wsgi.file_wrapper"]``, to be sent in a
928 :class:`.Response`. The WSGI server provides this if it has a way to
929 send file data more efficiently. If it's not provided, uses a basic
930 wrapper for consistent iteration.
931
932 You'll also want to set :attr:`.Response.direct_passthrough` to ``True``
933 to tell the response not to do its own iteration.
934
935 Use :attr:`send_file` instead of generating a file response manually. It
936 will handle caching, range requests, wrapping, and more.
937
938 :param file: A file-like object in ``rb`` mode.
939 :param buffer_size: Number of bytes to read for each iteration. Defaults
940 to 128 KiB.
941
942 .. versionadded:: 3.2
943 """
944 cls: wt.FileWrapper = self.environ.get("wsgi.file_wrapper", _FileWrapper)
945 return cls(file, buffer_size)