651 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			Python
		
	
	
	
			
		
		
	
	
			651 lines
		
	
	
		
			24 KiB
		
	
	
	
		
			Python
		
	
	
	
from __future__ import annotations
 | 
						|
 | 
						|
import collections.abc as cabc
 | 
						|
import functools
 | 
						|
import json
 | 
						|
import typing as t
 | 
						|
from io import BytesIO
 | 
						|
 | 
						|
from .._internal import _wsgi_decoding_dance
 | 
						|
from ..datastructures import CombinedMultiDict
 | 
						|
from ..datastructures import EnvironHeaders
 | 
						|
from ..datastructures import FileStorage
 | 
						|
from ..datastructures import ImmutableMultiDict
 | 
						|
from ..datastructures import iter_multi_items
 | 
						|
from ..datastructures import MultiDict
 | 
						|
from ..exceptions import BadRequest
 | 
						|
from ..exceptions import UnsupportedMediaType
 | 
						|
from ..formparser import default_stream_factory
 | 
						|
from ..formparser import FormDataParser
 | 
						|
from ..sansio.request import Request as _SansIORequest
 | 
						|
from ..utils import cached_property
 | 
						|
from ..utils import environ_property
 | 
						|
from ..wsgi import _get_server
 | 
						|
from ..wsgi import get_input_stream
 | 
						|
 | 
						|
if t.TYPE_CHECKING:
 | 
						|
    from _typeshed.wsgi import WSGIApplication
 | 
						|
    from _typeshed.wsgi import WSGIEnvironment
 | 
						|
 | 
						|
 | 
						|
class Request(_SansIORequest):
 | 
						|
    """Represents an incoming WSGI HTTP request, with headers and body
 | 
						|
    taken from the WSGI environment. Has properties and methods for
 | 
						|
    using the functionality defined by various HTTP specs. The data in
 | 
						|
    requests object is read-only.
 | 
						|
 | 
						|
    Text data is assumed to use UTF-8 encoding, which should be true for
 | 
						|
    the vast majority of modern clients. Using an encoding set by the
 | 
						|
    client is unsafe in Python due to extra encodings it provides, such
 | 
						|
    as ``zip``. To change the assumed encoding, subclass and replace
 | 
						|
    :attr:`charset`.
 | 
						|
 | 
						|
    :param environ: The WSGI environ is generated by the WSGI server and
 | 
						|
        contains information about the server configuration and client
 | 
						|
        request.
 | 
						|
    :param populate_request: Add this request object to the WSGI environ
 | 
						|
        as ``environ['werkzeug.request']``. Can be useful when
 | 
						|
        debugging.
 | 
						|
    :param shallow: Makes reading from :attr:`stream` (and any method
 | 
						|
        that would read from it) raise a :exc:`RuntimeError`. Useful to
 | 
						|
        prevent consuming the form data in middleware, which would make
 | 
						|
        it unavailable to the final application.
 | 
						|
 | 
						|
    .. versionchanged:: 3.0
 | 
						|
        The ``charset``, ``url_charset``, and ``encoding_errors`` parameters
 | 
						|
        were removed.
 | 
						|
 | 
						|
    .. versionchanged:: 2.1
 | 
						|
        Old ``BaseRequest`` and mixin classes were removed.
 | 
						|
 | 
						|
    .. versionchanged:: 2.1
 | 
						|
        Remove the ``disable_data_descriptor`` attribute.
 | 
						|
 | 
						|
    .. versionchanged:: 2.0
 | 
						|
        Combine ``BaseRequest`` and mixins into a single ``Request``
 | 
						|
        class.
 | 
						|
 | 
						|
    .. versionchanged:: 0.5
 | 
						|
        Read-only mode is enforced with immutable classes for all data.
 | 
						|
    """
 | 
						|
 | 
						|
    #: the maximum content length.  This is forwarded to the form data
 | 
						|
    #: parsing function (:func:`parse_form_data`).  When set and the
 | 
						|
    #: :attr:`form` or :attr:`files` attribute is accessed and the
 | 
						|
    #: parsing fails because more than the specified value is transmitted
 | 
						|
    #: a :exc:`~werkzeug.exceptions.RequestEntityTooLarge` exception is raised.
 | 
						|
    #:
 | 
						|
    #: .. versionadded:: 0.5
 | 
						|
    max_content_length: int | None = None
 | 
						|
 | 
						|
    #: the maximum form field size.  This is forwarded to the form data
 | 
						|
    #: parsing function (:func:`parse_form_data`).  When set and the
 | 
						|
    #: :attr:`form` or :attr:`files` attribute is accessed and the
 | 
						|
    #: data in memory for post data is longer than the specified value a
 | 
						|
    #: :exc:`~werkzeug.exceptions.RequestEntityTooLarge` exception is raised.
 | 
						|
    #:
 | 
						|
    #: .. versionchanged:: 3.1
 | 
						|
    #:     Defaults to 500kB instead of unlimited.
 | 
						|
    #:
 | 
						|
    #: .. versionadded:: 0.5
 | 
						|
    max_form_memory_size: int | None = 500_000
 | 
						|
 | 
						|
    #: The maximum number of multipart parts to parse, passed to
 | 
						|
    #: :attr:`form_data_parser_class`. Parsing form data with more than this
 | 
						|
    #: many parts will raise :exc:`~.RequestEntityTooLarge`.
 | 
						|
    #:
 | 
						|
    #: .. versionadded:: 2.2.3
 | 
						|
    max_form_parts = 1000
 | 
						|
 | 
						|
    #: The form data parser that should be used.  Can be replaced to customize
 | 
						|
    #: the form date parsing.
 | 
						|
    form_data_parser_class: type[FormDataParser] = FormDataParser
 | 
						|
 | 
						|
    #: The WSGI environment containing HTTP headers and information from
 | 
						|
    #: the WSGI server.
 | 
						|
    environ: WSGIEnvironment
 | 
						|
 | 
						|
    #: Set when creating the request object. If ``True``, reading from
 | 
						|
    #: the request body will cause a ``RuntimeException``. Useful to
 | 
						|
    #: prevent modifying the stream from middleware.
 | 
						|
    shallow: bool
 | 
						|
 | 
						|
    def __init__(
 | 
						|
        self,
 | 
						|
        environ: WSGIEnvironment,
 | 
						|
        populate_request: bool = True,
 | 
						|
        shallow: bool = False,
 | 
						|
    ) -> None:
 | 
						|
        super().__init__(
 | 
						|
            method=environ.get("REQUEST_METHOD", "GET"),
 | 
						|
            scheme=environ.get("wsgi.url_scheme", "http"),
 | 
						|
            server=_get_server(environ),
 | 
						|
            root_path=_wsgi_decoding_dance(environ.get("SCRIPT_NAME") or ""),
 | 
						|
            path=_wsgi_decoding_dance(environ.get("PATH_INFO") or ""),
 | 
						|
            query_string=environ.get("QUERY_STRING", "").encode("latin1"),
 | 
						|
            headers=EnvironHeaders(environ),
 | 
						|
            remote_addr=environ.get("REMOTE_ADDR"),
 | 
						|
        )
 | 
						|
        self.environ = environ
 | 
						|
        self.shallow = shallow
 | 
						|
 | 
						|
        if populate_request and not shallow:
 | 
						|
            self.environ["werkzeug.request"] = self
 | 
						|
 | 
						|
    @classmethod
 | 
						|
    def from_values(cls, *args: t.Any, **kwargs: t.Any) -> Request:
 | 
						|
        """Create a new request object based on the values provided.  If
 | 
						|
        environ is given missing values are filled from there.  This method is
 | 
						|
        useful for small scripts when you need to simulate a request from an URL.
 | 
						|
        Do not use this method for unittesting, there is a full featured client
 | 
						|
        object (:class:`Client`) that allows to create multipart requests,
 | 
						|
        support for cookies etc.
 | 
						|
 | 
						|
        This accepts the same options as the
 | 
						|
        :class:`~werkzeug.test.EnvironBuilder`.
 | 
						|
 | 
						|
        .. versionchanged:: 0.5
 | 
						|
           This method now accepts the same arguments as
 | 
						|
           :class:`~werkzeug.test.EnvironBuilder`.  Because of this the
 | 
						|
           `environ` parameter is now called `environ_overrides`.
 | 
						|
 | 
						|
        :return: request object
 | 
						|
        """
 | 
						|
        from ..test import EnvironBuilder
 | 
						|
 | 
						|
        builder = EnvironBuilder(*args, **kwargs)
 | 
						|
        try:
 | 
						|
            return builder.get_request(cls)
 | 
						|
        finally:
 | 
						|
            builder.close()
 | 
						|
 | 
						|
    @classmethod
 | 
						|
    def application(cls, f: t.Callable[[Request], WSGIApplication]) -> WSGIApplication:
 | 
						|
        """Decorate a function as responder that accepts the request as
 | 
						|
        the last argument.  This works like the :func:`responder`
 | 
						|
        decorator but the function is passed the request object as the
 | 
						|
        last argument and the request object will be closed
 | 
						|
        automatically::
 | 
						|
 | 
						|
            @Request.application
 | 
						|
            def my_wsgi_app(request):
 | 
						|
                return Response('Hello World!')
 | 
						|
 | 
						|
        As of Werkzeug 0.14 HTTP exceptions are automatically caught and
 | 
						|
        converted to responses instead of failing.
 | 
						|
 | 
						|
        :param f: the WSGI callable to decorate
 | 
						|
        :return: a new WSGI callable
 | 
						|
        """
 | 
						|
        #: return a callable that wraps the -2nd argument with the request
 | 
						|
        #: and calls the function with all the arguments up to that one and
 | 
						|
        #: the request.  The return value is then called with the latest
 | 
						|
        #: two arguments.  This makes it possible to use this decorator for
 | 
						|
        #: both standalone WSGI functions as well as bound methods and
 | 
						|
        #: partially applied functions.
 | 
						|
        from ..exceptions import HTTPException
 | 
						|
 | 
						|
        @functools.wraps(f)
 | 
						|
        def application(*args: t.Any) -> cabc.Iterable[bytes]:
 | 
						|
            request = cls(args[-2])
 | 
						|
            with request:
 | 
						|
                try:
 | 
						|
                    resp = f(*args[:-2] + (request,))
 | 
						|
                except HTTPException as e:
 | 
						|
                    resp = t.cast("WSGIApplication", e.get_response(args[-2]))
 | 
						|
                return resp(*args[-2:])
 | 
						|
 | 
						|
        return t.cast("WSGIApplication", application)
 | 
						|
 | 
						|
    def _get_file_stream(
 | 
						|
        self,
 | 
						|
        total_content_length: int | None,
 | 
						|
        content_type: str | None,
 | 
						|
        filename: str | None = None,
 | 
						|
        content_length: int | None = None,
 | 
						|
    ) -> t.IO[bytes]:
 | 
						|
        """Called to get a stream for the file upload.
 | 
						|
 | 
						|
        This must provide a file-like class with `read()`, `readline()`
 | 
						|
        and `seek()` methods that is both writeable and readable.
 | 
						|
 | 
						|
        The default implementation returns a temporary file if the total
 | 
						|
        content length is higher than 500KB.  Because many browsers do not
 | 
						|
        provide a content length for the files only the total content
 | 
						|
        length matters.
 | 
						|
 | 
						|
        :param total_content_length: the total content length of all the
 | 
						|
                                     data in the request combined.  This value
 | 
						|
                                     is guaranteed to be there.
 | 
						|
        :param content_type: the mimetype of the uploaded file.
 | 
						|
        :param filename: the filename of the uploaded file.  May be `None`.
 | 
						|
        :param content_length: the length of this file.  This value is usually
 | 
						|
                               not provided because webbrowsers do not provide
 | 
						|
                               this value.
 | 
						|
        """
 | 
						|
        return default_stream_factory(
 | 
						|
            total_content_length=total_content_length,
 | 
						|
            filename=filename,
 | 
						|
            content_type=content_type,
 | 
						|
            content_length=content_length,
 | 
						|
        )
 | 
						|
 | 
						|
    @property
 | 
						|
    def want_form_data_parsed(self) -> bool:
 | 
						|
        """``True`` if the request method carries content. By default
 | 
						|
        this is true if a ``Content-Type`` is sent.
 | 
						|
 | 
						|
        .. versionadded:: 0.8
 | 
						|
        """
 | 
						|
        return bool(self.environ.get("CONTENT_TYPE"))
 | 
						|
 | 
						|
    def make_form_data_parser(self) -> FormDataParser:
 | 
						|
        """Creates the form data parser. Instantiates the
 | 
						|
        :attr:`form_data_parser_class` with some parameters.
 | 
						|
 | 
						|
        .. versionadded:: 0.8
 | 
						|
        """
 | 
						|
        return self.form_data_parser_class(
 | 
						|
            stream_factory=self._get_file_stream,
 | 
						|
            max_form_memory_size=self.max_form_memory_size,
 | 
						|
            max_content_length=self.max_content_length,
 | 
						|
            max_form_parts=self.max_form_parts,
 | 
						|
            cls=self.parameter_storage_class,
 | 
						|
        )
 | 
						|
 | 
						|
    def _load_form_data(self) -> None:
 | 
						|
        """Method used internally to retrieve submitted data.  After calling
 | 
						|
        this sets `form` and `files` on the request object to multi dicts
 | 
						|
        filled with the incoming form data.  As a matter of fact the input
 | 
						|
        stream will be empty afterwards.  You can also call this method to
 | 
						|
        force the parsing of the form data.
 | 
						|
 | 
						|
        .. versionadded:: 0.8
 | 
						|
        """
 | 
						|
        # abort early if we have already consumed the stream
 | 
						|
        if "form" in self.__dict__:
 | 
						|
            return
 | 
						|
 | 
						|
        if self.want_form_data_parsed:
 | 
						|
            parser = self.make_form_data_parser()
 | 
						|
            data = parser.parse(
 | 
						|
                self._get_stream_for_parsing(),
 | 
						|
                self.mimetype,
 | 
						|
                self.content_length,
 | 
						|
                self.mimetype_params,
 | 
						|
            )
 | 
						|
        else:
 | 
						|
            data = (
 | 
						|
                self.stream,
 | 
						|
                self.parameter_storage_class(),
 | 
						|
                self.parameter_storage_class(),
 | 
						|
            )
 | 
						|
 | 
						|
        # inject the values into the instance dict so that we bypass
 | 
						|
        # our cached_property non-data descriptor.
 | 
						|
        d = self.__dict__
 | 
						|
        d["stream"], d["form"], d["files"] = data
 | 
						|
 | 
						|
    def _get_stream_for_parsing(self) -> t.IO[bytes]:
 | 
						|
        """This is the same as accessing :attr:`stream` with the difference
 | 
						|
        that if it finds cached data from calling :meth:`get_data` first it
 | 
						|
        will create a new stream out of the cached data.
 | 
						|
 | 
						|
        .. versionadded:: 0.9.3
 | 
						|
        """
 | 
						|
        cached_data = getattr(self, "_cached_data", None)
 | 
						|
        if cached_data is not None:
 | 
						|
            return BytesIO(cached_data)
 | 
						|
        return self.stream
 | 
						|
 | 
						|
    def close(self) -> None:
 | 
						|
        """Closes associated resources of this request object.  This
 | 
						|
        closes all file handles explicitly.  You can also use the request
 | 
						|
        object in a with statement which will automatically close it.
 | 
						|
 | 
						|
        .. versionadded:: 0.9
 | 
						|
        """
 | 
						|
        files = self.__dict__.get("files")
 | 
						|
        for _key, value in iter_multi_items(files or ()):
 | 
						|
            value.close()
 | 
						|
 | 
						|
    def __enter__(self) -> Request:
 | 
						|
        return self
 | 
						|
 | 
						|
    def __exit__(self, exc_type, exc_value, tb) -> None:  # type: ignore
 | 
						|
        self.close()
 | 
						|
 | 
						|
    @cached_property
 | 
						|
    def stream(self) -> t.IO[bytes]:
 | 
						|
        """The WSGI input stream, with safety checks. This stream can only be consumed
 | 
						|
        once.
 | 
						|
 | 
						|
        Use :meth:`get_data` to get the full data as bytes or text. The :attr:`data`
 | 
						|
        attribute will contain the full bytes only if they do not represent form data.
 | 
						|
        The :attr:`form` attribute will contain the parsed form data in that case.
 | 
						|
 | 
						|
        Unlike :attr:`input_stream`, this stream guards against infinite streams or
 | 
						|
        reading past :attr:`content_length` or :attr:`max_content_length`.
 | 
						|
 | 
						|
        If ``max_content_length`` is set, it can be enforced on streams if
 | 
						|
        ``wsgi.input_terminated`` is set. Otherwise, an empty stream is returned.
 | 
						|
 | 
						|
        If the limit is reached before the underlying stream is exhausted (such as a
 | 
						|
        file that is too large, or an infinite stream), the remaining contents of the
 | 
						|
        stream cannot be read safely. Depending on how the server handles this, clients
 | 
						|
        may show a "connection reset" failure instead of seeing the 413 response.
 | 
						|
 | 
						|
        .. versionchanged:: 2.3
 | 
						|
            Check ``max_content_length`` preemptively and while reading.
 | 
						|
 | 
						|
        .. versionchanged:: 0.9
 | 
						|
            The stream is always set (but may be consumed) even if form parsing was
 | 
						|
            accessed first.
 | 
						|
        """
 | 
						|
        if self.shallow:
 | 
						|
            raise RuntimeError(
 | 
						|
                "This request was created with 'shallow=True', reading"
 | 
						|
                " from the input stream is disabled."
 | 
						|
            )
 | 
						|
 | 
						|
        return get_input_stream(
 | 
						|
            self.environ, max_content_length=self.max_content_length
 | 
						|
        )
 | 
						|
 | 
						|
    input_stream = environ_property[t.IO[bytes]](
 | 
						|
        "wsgi.input",
 | 
						|
        doc="""The raw WSGI input stream, without any safety checks.
 | 
						|
 | 
						|
        This is dangerous to use. It does not guard against infinite streams or reading
 | 
						|
        past :attr:`content_length` or :attr:`max_content_length`.
 | 
						|
 | 
						|
        Use :attr:`stream` instead.
 | 
						|
        """,
 | 
						|
    )
 | 
						|
 | 
						|
    @cached_property
 | 
						|
    def data(self) -> bytes:
 | 
						|
        """The raw data read from :attr:`stream`. Will be empty if the request
 | 
						|
        represents form data.
 | 
						|
 | 
						|
        To get the raw data even if it represents form data, use :meth:`get_data`.
 | 
						|
        """
 | 
						|
        return self.get_data(parse_form_data=True)
 | 
						|
 | 
						|
    @t.overload
 | 
						|
    def get_data(
 | 
						|
        self,
 | 
						|
        cache: bool = True,
 | 
						|
        as_text: t.Literal[False] = False,
 | 
						|
        parse_form_data: bool = False,
 | 
						|
    ) -> bytes: ...
 | 
						|
 | 
						|
    @t.overload
 | 
						|
    def get_data(
 | 
						|
        self,
 | 
						|
        cache: bool = True,
 | 
						|
        as_text: t.Literal[True] = ...,
 | 
						|
        parse_form_data: bool = False,
 | 
						|
    ) -> str: ...
 | 
						|
 | 
						|
    def get_data(
 | 
						|
        self, cache: bool = True, as_text: bool = False, parse_form_data: bool = False
 | 
						|
    ) -> bytes | str:
 | 
						|
        """This reads the buffered incoming data from the client into one
 | 
						|
        bytes object.  By default this is cached but that behavior can be
 | 
						|
        changed by setting `cache` to `False`.
 | 
						|
 | 
						|
        Usually it's a bad idea to call this method without checking the
 | 
						|
        content length first as a client could send dozens of megabytes or more
 | 
						|
        to cause memory problems on the server.
 | 
						|
 | 
						|
        Note that if the form data was already parsed this method will not
 | 
						|
        return anything as form data parsing does not cache the data like
 | 
						|
        this method does.  To implicitly invoke form data parsing function
 | 
						|
        set `parse_form_data` to `True`.  When this is done the return value
 | 
						|
        of this method will be an empty string if the form parser handles
 | 
						|
        the data.  This generally is not necessary as if the whole data is
 | 
						|
        cached (which is the default) the form parser will used the cached
 | 
						|
        data to parse the form data.  Please be generally aware of checking
 | 
						|
        the content length first in any case before calling this method
 | 
						|
        to avoid exhausting server memory.
 | 
						|
 | 
						|
        If `as_text` is set to `True` the return value will be a decoded
 | 
						|
        string.
 | 
						|
 | 
						|
        .. versionadded:: 0.9
 | 
						|
        """
 | 
						|
        rv = getattr(self, "_cached_data", None)
 | 
						|
        if rv is None:
 | 
						|
            if parse_form_data:
 | 
						|
                self._load_form_data()
 | 
						|
            rv = self.stream.read()
 | 
						|
            if cache:
 | 
						|
                self._cached_data = rv
 | 
						|
        if as_text:
 | 
						|
            rv = rv.decode(errors="replace")
 | 
						|
        return rv
 | 
						|
 | 
						|
    @cached_property
 | 
						|
    def form(self) -> ImmutableMultiDict[str, str]:
 | 
						|
        """The form parameters.  By default an
 | 
						|
        :class:`~werkzeug.datastructures.ImmutableMultiDict`
 | 
						|
        is returned from this function.  This can be changed by setting
 | 
						|
        :attr:`parameter_storage_class` to a different type.  This might
 | 
						|
        be necessary if the order of the form data is important.
 | 
						|
 | 
						|
        Please keep in mind that file uploads will not end up here, but instead
 | 
						|
        in the :attr:`files` attribute.
 | 
						|
 | 
						|
        .. versionchanged:: 0.9
 | 
						|
 | 
						|
            Previous to Werkzeug 0.9 this would only contain form data for POST
 | 
						|
            and PUT requests.
 | 
						|
        """
 | 
						|
        self._load_form_data()
 | 
						|
        return self.form
 | 
						|
 | 
						|
    @cached_property
 | 
						|
    def values(self) -> CombinedMultiDict[str, str]:
 | 
						|
        """A :class:`werkzeug.datastructures.CombinedMultiDict` that
 | 
						|
        combines :attr:`args` and :attr:`form`.
 | 
						|
 | 
						|
        For GET requests, only ``args`` are present, not ``form``.
 | 
						|
 | 
						|
        .. versionchanged:: 2.0
 | 
						|
            For GET requests, only ``args`` are present, not ``form``.
 | 
						|
        """
 | 
						|
        sources = [self.args]
 | 
						|
 | 
						|
        if self.method != "GET":
 | 
						|
            # GET requests can have a body, and some caching proxies
 | 
						|
            # might not treat that differently than a normal GET
 | 
						|
            # request, allowing form data to "invisibly" affect the
 | 
						|
            # cache without indication in the query string / URL.
 | 
						|
            sources.append(self.form)
 | 
						|
 | 
						|
        args = []
 | 
						|
 | 
						|
        for d in sources:
 | 
						|
            if not isinstance(d, MultiDict):
 | 
						|
                d = MultiDict(d)
 | 
						|
 | 
						|
            args.append(d)
 | 
						|
 | 
						|
        return CombinedMultiDict(args)
 | 
						|
 | 
						|
    @cached_property
 | 
						|
    def files(self) -> ImmutableMultiDict[str, FileStorage]:
 | 
						|
        """:class:`~werkzeug.datastructures.MultiDict` object containing
 | 
						|
        all uploaded files.  Each key in :attr:`files` is the name from the
 | 
						|
        ``<input type="file" name="">``.  Each value in :attr:`files` is a
 | 
						|
        Werkzeug :class:`~werkzeug.datastructures.FileStorage` object.
 | 
						|
 | 
						|
        It basically behaves like a standard file object you know from Python,
 | 
						|
        with the difference that it also has a
 | 
						|
        :meth:`~werkzeug.datastructures.FileStorage.save` function that can
 | 
						|
        store the file on the filesystem.
 | 
						|
 | 
						|
        Note that :attr:`files` will only contain data if the request method was
 | 
						|
        POST, PUT or PATCH and the ``<form>`` that posted to the request had
 | 
						|
        ``enctype="multipart/form-data"``.  It will be empty otherwise.
 | 
						|
 | 
						|
        See the :class:`~werkzeug.datastructures.MultiDict` /
 | 
						|
        :class:`~werkzeug.datastructures.FileStorage` documentation for
 | 
						|
        more details about the used data structure.
 | 
						|
        """
 | 
						|
        self._load_form_data()
 | 
						|
        return self.files
 | 
						|
 | 
						|
    @property
 | 
						|
    def script_root(self) -> str:
 | 
						|
        """Alias for :attr:`self.root_path`. ``environ["SCRIPT_ROOT"]``
 | 
						|
        without a trailing slash.
 | 
						|
        """
 | 
						|
        return self.root_path
 | 
						|
 | 
						|
    @cached_property
 | 
						|
    def url_root(self) -> str:
 | 
						|
        """Alias for :attr:`root_url`. The URL with scheme, host, and
 | 
						|
        root path. For example, ``https://example.com/app/``.
 | 
						|
        """
 | 
						|
        return self.root_url
 | 
						|
 | 
						|
    remote_user = environ_property[str](
 | 
						|
        "REMOTE_USER",
 | 
						|
        doc="""If the server supports user authentication, and the
 | 
						|
        script is protected, this attribute contains the username the
 | 
						|
        user has authenticated as.""",
 | 
						|
    )
 | 
						|
    is_multithread = environ_property[bool](
 | 
						|
        "wsgi.multithread",
 | 
						|
        doc="""boolean that is `True` if the application is served by a
 | 
						|
        multithreaded WSGI server.""",
 | 
						|
    )
 | 
						|
    is_multiprocess = environ_property[bool](
 | 
						|
        "wsgi.multiprocess",
 | 
						|
        doc="""boolean that is `True` if the application is served by a
 | 
						|
        WSGI server that spawns multiple processes.""",
 | 
						|
    )
 | 
						|
    is_run_once = environ_property[bool](
 | 
						|
        "wsgi.run_once",
 | 
						|
        doc="""boolean that is `True` if the application will be
 | 
						|
        executed only once in a process lifetime.  This is the case for
 | 
						|
        CGI for example, but it's not guaranteed that the execution only
 | 
						|
        happens one time.""",
 | 
						|
    )
 | 
						|
 | 
						|
    # JSON
 | 
						|
 | 
						|
    #: A module or other object that has ``dumps`` and ``loads``
 | 
						|
    #: functions that match the API of the built-in :mod:`json` module.
 | 
						|
    json_module = json
 | 
						|
 | 
						|
    @property
 | 
						|
    def json(self) -> t.Any | None:
 | 
						|
        """The parsed JSON data if :attr:`mimetype` indicates JSON
 | 
						|
        (:mimetype:`application/json`, see :attr:`is_json`).
 | 
						|
 | 
						|
        Calls :meth:`get_json` with default arguments.
 | 
						|
 | 
						|
        If the request content type is not ``application/json``, this
 | 
						|
        will raise a 415 Unsupported Media Type error.
 | 
						|
 | 
						|
        .. versionchanged:: 2.3
 | 
						|
            Raise a 415 error instead of 400.
 | 
						|
 | 
						|
        .. versionchanged:: 2.1
 | 
						|
            Raise a 400 error if the content type is incorrect.
 | 
						|
        """
 | 
						|
        return self.get_json()
 | 
						|
 | 
						|
    # Cached values for ``(silent=False, silent=True)``. Initialized
 | 
						|
    # with sentinel values.
 | 
						|
    _cached_json: tuple[t.Any, t.Any] = (Ellipsis, Ellipsis)
 | 
						|
 | 
						|
    @t.overload
 | 
						|
    def get_json(
 | 
						|
        self, force: bool = ..., silent: t.Literal[False] = ..., cache: bool = ...
 | 
						|
    ) -> t.Any: ...
 | 
						|
 | 
						|
    @t.overload
 | 
						|
    def get_json(
 | 
						|
        self, force: bool = ..., silent: bool = ..., cache: bool = ...
 | 
						|
    ) -> t.Any | None: ...
 | 
						|
 | 
						|
    def get_json(
 | 
						|
        self, force: bool = False, silent: bool = False, cache: bool = True
 | 
						|
    ) -> t.Any | None:
 | 
						|
        """Parse :attr:`data` as JSON.
 | 
						|
 | 
						|
        If the mimetype does not indicate JSON
 | 
						|
        (:mimetype:`application/json`, see :attr:`is_json`), or parsing
 | 
						|
        fails, :meth:`on_json_loading_failed` is called and
 | 
						|
        its return value is used as the return value. By default this
 | 
						|
        raises a 415 Unsupported Media Type resp.
 | 
						|
 | 
						|
        :param force: Ignore the mimetype and always try to parse JSON.
 | 
						|
        :param silent: Silence mimetype and parsing errors, and
 | 
						|
            return ``None`` instead.
 | 
						|
        :param cache: Store the parsed JSON to return for subsequent
 | 
						|
            calls.
 | 
						|
 | 
						|
        .. versionchanged:: 2.3
 | 
						|
            Raise a 415 error instead of 400.
 | 
						|
 | 
						|
        .. versionchanged:: 2.1
 | 
						|
            Raise a 400 error if the content type is incorrect.
 | 
						|
        """
 | 
						|
        if cache and self._cached_json[silent] is not Ellipsis:
 | 
						|
            return self._cached_json[silent]
 | 
						|
 | 
						|
        if not (force or self.is_json):
 | 
						|
            if not silent:
 | 
						|
                return self.on_json_loading_failed(None)
 | 
						|
            else:
 | 
						|
                return None
 | 
						|
 | 
						|
        data = self.get_data(cache=cache)
 | 
						|
 | 
						|
        try:
 | 
						|
            rv = self.json_module.loads(data)
 | 
						|
        except ValueError as e:
 | 
						|
            if silent:
 | 
						|
                rv = None
 | 
						|
 | 
						|
                if cache:
 | 
						|
                    normal_rv, _ = self._cached_json
 | 
						|
                    self._cached_json = (normal_rv, rv)
 | 
						|
            else:
 | 
						|
                rv = self.on_json_loading_failed(e)
 | 
						|
 | 
						|
                if cache:
 | 
						|
                    _, silent_rv = self._cached_json
 | 
						|
                    self._cached_json = (rv, silent_rv)
 | 
						|
        else:
 | 
						|
            if cache:
 | 
						|
                self._cached_json = (rv, rv)
 | 
						|
 | 
						|
        return rv
 | 
						|
 | 
						|
    def on_json_loading_failed(self, e: ValueError | None) -> t.Any:
 | 
						|
        """Called if :meth:`get_json` fails and isn't silenced.
 | 
						|
 | 
						|
        If this method returns a value, it is used as the return value
 | 
						|
        for :meth:`get_json`. The default implementation raises
 | 
						|
        :exc:`~werkzeug.exceptions.BadRequest`.
 | 
						|
 | 
						|
        :param e: If parsing failed, this is the exception. It will be
 | 
						|
            ``None`` if the content type wasn't ``application/json``.
 | 
						|
 | 
						|
        .. versionchanged:: 2.3
 | 
						|
            Raise a 415 error instead of 400.
 | 
						|
        """
 | 
						|
        if e is not None:
 | 
						|
            raise BadRequest(f"Failed to decode JSON object: {e}")
 | 
						|
 | 
						|
        raise UnsupportedMediaType(
 | 
						|
            "Did not attempt to load JSON data because the request"
 | 
						|
            " Content-Type was not 'application/json'."
 | 
						|
        )
 |